-
Notifications
You must be signed in to change notification settings - Fork 482
333 lines (303 loc) · 14 KB
/
Copy pathcicd_comp_initialize-phase.yml
File metadata and controls
333 lines (303 loc) · 14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# Initialize Phase Workflow
#
# This reusable workflow is responsible for initializing the build process,
# checking for previous builds, and determining which components need to be
# built or tested based on changes in the codebase.
#
# Key features:
# - Supports incremental builds via change detection
# - Can reuse artifacts from previous builds
# - Determines which components (backend, frontend, CLI) need attention
# - Configurable test skipping via CICD_SKIP_TESTS repository variable
#
# Outputs:
# - filters: JSON object with all filter results
# Usage: fromJSON(needs.initialize.outputs.filters).backend == 'true'
# - changes: JSON array of filter names that matched (for PR labeling)
# - artifact-run-id: Run ID to download artifacts from
# - found_artifacts: Whether previous build artifacts were found
name: Initialize Phase
on:
workflow_call:
inputs:
change-detection:
type: string
required: true
description: |
Controls whether to detect file changes for selective test execution:
- 'enabled': Run paths-filter to detect changes, run only affected components
- 'disabled': Skip detection, default all build/test components to run
reuse-previous-build:
description: 'Indicates if the workflow should reuse the previous build'
type: boolean
default: false
build-on-missing-artifacts:
description: 'If artifacts from previous build cannot be found should we build now or error. Only applicable if reuse-previous-build is set'
type: boolean
default: false
outputs:
# Artifact reuse outputs
artifact-run-id:
value: ${{ jobs.check-previous-build.outputs.artifact-run-id }}
found_artifacts:
value: ${{ jobs.check-previous-build.outputs.found_artifacts }}
# JSON object containing all filter results - use fromJSON() to access
# Example: fromJSON(needs.initialize.outputs.filters).backend == 'true'
filters:
value: ${{ jobs.changes.outputs.filters }}
# JSON array of filter names that matched (from dorny/paths-filter) - use for labeling
changes:
value: ${{ jobs.changes.outputs.changes }}
jobs:
# This job is used as a required check to indicate that the workflow has started and is running
initialize:
name: Initialize
runs-on: ubuntu-${{ vars.UBUNTU_RUNNER_VERSION || '24.04' }}
if: always()
steps:
- run: echo 'GitHub context'
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
- name: Initialize
id: initialize
shell: bash
run: |
echo "Initializing..."
# Check can be removed if we have resolved root cause
# We cannot use a local github action for this as it is run before we checkout the repo
# secrets.GITHUB_TOKEN is not available in composite workflows so it needs to be passed in.
- name: Check API Rate Limit
shell: bash
run: |
curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/rate_limit || true
# This job checks for artifacts from previous builds and determines if they can be reused
check-previous-build:
name: Check Previous Build
runs-on: ubuntu-${{ vars.UBUNTU_RUNNER_VERSION || '24.04' }}
outputs:
artifact-run-id: ${{ steps.check.outputs.run_id }}
found_artifacts: ${{ steps.check.outputs.found_artifacts }}
steps:
- name: Download Build Artifact
id: data-download
uses: dawidd6/action-download-artifact@v6
if: ${{ inputs.reuse-previous-build == true }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
workflow_search: true
commit: ${{ github.sha }}
workflow_conclusion: success
search_artifacts: true
dry_run: true
name: maven-repo
path: .
if_no_artifact_found: warn
- name: Set Outputs
id: check
run: |
build_artifact_exists=${{ steps.data-download.outputs.found_artifact }}
if [[ ${build_artifact_exists} == "true" ]]; then
run_id=`echo '${{ steps.data-download.outputs.artifacts }}' | jq -r '.[0].workflow_run.id'`
found_artifacts=true
echo "Merge Group Artifact Run id: $run_id"
else
echo "No Merge Group artifact found"
run_id="${{ github.run_id }}"
found_artifacts=false
fi
echo "run_id=$run_id" >> $GITHUB_OUTPUT
echo "found_artifacts=$found_artifacts" >> $GITHUB_OUTPUT
if [[ "${{ inputs.reuse-previous-build || 'false' }}" == "true" && "${found_artifacts}" != "true" && "${{ inputs.build-on-missing-artifacts }}" != "true" ]]; then
echo "build-on-missing-artifacts set to false. Failing build"
exit 1
fi
# This job determines which components of the project need to be built or tested
changes:
name: Check Changed Files
needs: [ check-previous-build ]
if: always() && !failure() && !cancelled()
runs-on: ubuntu-${{ vars.UBUNTU_RUNNER_VERSION || '24.04' }}
outputs:
# JSON object with all filter results
filters: ${{ steps.filter-rewrite.outputs.filters }}
# JSON array of filter names that matched (from dorny/paths-filter)
changes: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v5
if: ${{ inputs.change-detection == 'enabled' }}
# Execute the paths-filter step to determine changes
# For PRs, paths-filter automatically uses GitHub API to get changed files
- uses: dorny/paths-filter@v3.0.1
if: ${{ inputs.change-detection == 'enabled' }}
id: filter
with:
filters: .github/filters.yaml
- name: Rewrite Filter
id: filter-rewrite
env:
CICD_SKIP_TESTS: ${{ vars.CICD_SKIP_TESTS }}
CHANGE_DETECTION: ${{ inputs.change-detection }}
# All filter outputs as JSON - no need to list individually
FILTER_OUTPUTS: ${{ toJSON(steps.filter.outputs) }}
run: |
echo "::group::Rewrite Filter"
# ============================================================
# FILTER CONFIGURATION
# ============================================================
# build_test_filters: Components that can be built/tested
# - Default to 'true' when change-detection='disabled' (run all)
# - Use detected values when change-detection='enabled'
# - Can be disabled via CICD_SKIP_TESTS for test_filters subset
#
# info_filters: Informational filters (labeling, publishing decisions)
# - Always use detected values or 'false' if not detected
# - Not affected by CICD_SKIP_TESTS
#
# test_filters: Subset of build_test_filters affected by CICD_SKIP_TESTS
# ============================================================
build_test_filters="frontend cli backend build jvm_unit_test"
info_filters="sdk_libs documentation cicd"
test_filters="frontend cli backend jvm_unit_test"
declare -A results
if [ "$CHANGE_DETECTION" == "enabled" ]; then
echo "Change detection enabled - using paths-filter results"
# Parse filter outputs from dorny/paths-filter
filter_keys=$(echo "$FILTER_OUTPUTS" | jq -r 'to_entries | map(select(.key != "changes" and .key != "changes_count")) | .[].key')
echo "Detected filters: $filter_keys"
# Use detected values for all filters
for key in $filter_keys; do
value=$(echo "$FILTER_OUTPUTS" | jq -r --arg k "$key" '.[$k] // "false"')
results[$key]=$value
done
else
echo "Change detection disabled - defaulting build/test filters to true"
# Default build/test filters to true (run everything)
for key in $build_test_filters; do
results[$key]="true"
done
# Default info filters to false (no changes detected)
for key in $info_filters; do
results[$key]="false"
done
fi
# Apply CICD_SKIP_TESTS override - disable test-related filters
if [ "${CICD_SKIP_TESTS:-false}" == "true" ]; then
echo "CICD_SKIP_TESTS is set - disabling test filters"
for key in $test_filters; do
if [[ -v "results[$key]" ]]; then
results[$key]="false"
fi
done
fi
# Build JSON object from results
echo "Filter results:"
json_parts=""
for key in "${!results[@]}"; do
echo " ${key}=${results[$key]}"
if [ -n "$json_parts" ]; then
json_parts="${json_parts},"
fi
json_parts="${json_parts}\"${key}\":\"${results[$key]}\""
done
filters_json="{${json_parts}}"
echo "filters=${filters_json}" >> $GITHUB_OUTPUT
echo "Output JSON: ${filters_json}"
echo "::endgroup::"
# Generate step summary for workflow run visibility
- name: Generate Summary
if: ${{ inputs.change-detection == 'enabled' }}
env:
FILTERS_JSON: ${{ steps.filter-rewrite.outputs.filters }}
CHANGES_JSON: ${{ steps.filter.outputs.changes }}
CHANGE_DETECTION: ${{ inputs.change-detection }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
MERGE_GROUP_HEAD: ${{ github.event.merge_group.head_sha }}
run: |
cat >> $GITHUB_STEP_SUMMARY << 'HEADER'
## 🔍 Change Detection Summary
HEADER
# Configuration section
echo "### Configuration" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Setting | Value |" >> $GITHUB_STEP_SUMMARY
echo "|---------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Change Detection | \`$CHANGE_DETECTION\` |" >> $GITHUB_STEP_SUMMARY
if [ -n "$PR_NUMBER" ]; then
echo "| Context | Pull Request #$PR_NUMBER |" >> $GITHUB_STEP_SUMMARY
echo "| PR Head | \`${PR_HEAD_SHA:0:12}\` |" >> $GITHUB_STEP_SUMMARY
echo "| PR Base | \`${PR_BASE_SHA:0:12}\` |" >> $GITHUB_STEP_SUMMARY
elif [ -n "$MERGE_GROUP_HEAD" ]; then
echo "| Context | Merge Queue |" >> $GITHUB_STEP_SUMMARY
else
echo "| Context | Push/Other |" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
# PR Labels section (only for PRs)
if [ -n "$PR_NUMBER" ]; then
echo "### PR Labels" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Label mapping (must match .github/area-labels.yml)
declare -A label_map
label_map[area_backend]="Area : Backend"
label_map[area_frontend]="Area : Frontend"
label_map[area_cli]="Area : CLI"
label_map[area_sdk]="Area : SDK"
label_map[area_documentation]="Area : Documentation"
label_map[area_cicd]="Area : CI/CD"
labels_to_apply=""
if [ -n "$CHANGES_JSON" ] && [ "$CHANGES_JSON" != "null" ] && [ "$CHANGES_JSON" != "[]" ]; then
for area in "${!label_map[@]}"; do
if echo "$CHANGES_JSON" | jq -e --arg a "$area" 'index($a) != null' > /dev/null 2>&1; then
if [ -n "$labels_to_apply" ]; then
labels_to_apply="$labels_to_apply, "
fi
labels_to_apply="$labels_to_apply\`${label_map[$area]}\`"
fi
done
fi
if [ -n "$labels_to_apply" ]; then
echo "Labels to apply: $labels_to_apply" >> $GITHUB_STEP_SUMMARY
else
echo "_No area labels to apply_" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
fi
# Detected changes section
echo "### Detected Changes" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -n "$CHANGES_JSON" ] && [ "$CHANGES_JSON" != "null" ] && [ "$CHANGES_JSON" != "[]" ]; then
echo "Filters that matched:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Parse JSON array and display as list
echo "$CHANGES_JSON" | jq -r '.[]' | while read -r change; do
case "$change" in
area_*) echo "- 🏷️ \`$change\`" >> $GITHUB_STEP_SUMMARY ;;
backend) echo "- ⚙️ \`$change\`" >> $GITHUB_STEP_SUMMARY ;;
frontend) echo "- 🎨 \`$change\`" >> $GITHUB_STEP_SUMMARY ;;
cli) echo "- 💻 \`$change\`" >> $GITHUB_STEP_SUMMARY ;;
build) echo "- 🔨 \`$change\`" >> $GITHUB_STEP_SUMMARY ;;
jvm_unit_test) echo "- 🧪 \`$change\`" >> $GITHUB_STEP_SUMMARY ;;
*) echo "- 📁 \`$change\`" >> $GITHUB_STEP_SUMMARY ;;
esac
done
else
echo "_No file changes detected by paths-filter_" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
# Build/Test matrix section
echo "### Build & Test Matrix" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Component | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-----------|--------|" >> $GITHUB_STEP_SUMMARY
# Parse filters JSON and display status
for component in build backend frontend cli jvm_unit_test; do
value=$(echo "$FILTERS_JSON" | jq -r --arg k "$component" '.[$k] // "false"')
if [ "$value" == "true" ]; then
echo "| $component | ✅ Will run |" >> $GITHUB_STEP_SUMMARY
else
echo "| $component | ⏭️ Skipped |" >> $GITHUB_STEP_SUMMARY
fi
done
echo "" >> $GITHUB_STEP_SUMMARY