@@ -15,23 +15,19 @@ permissions:
1515jobs :
1616 changes :
1717 name : Detect changed paths
18- if : github.event_name == 'pull_request'
1918 runs-on : ubuntu-latest
2019 permissions :
2120 contents : read
2221 pull-requests : read
2322 outputs :
24- java : ${{ steps.filter.outputs.java }}
25- js : ${{ steps.filter.outputs.js }}
26- python : ${{ steps.filter.outputs.python }}
27- go : ${{ steps.filter.outputs.go }}
28- rust : ${{ steps.filter.outputs.rust }}
29- csharp : ${{ steps.filter.outputs.csharp }}
30- actions : ${{ steps.filter.outputs.actions }}
23+ matrix : ${{ steps.build-matrix.outputs.matrix }}
24+ skipped-matrix : ${{ steps.build-matrix.outputs.skipped-matrix }}
3125 steps :
3226 - uses : actions/checkout@v4
27+
3328 - uses : dorny/paths-filter@v3
3429 id : filter
30+ if : github.event_name == 'pull_request'
3531 with :
3632 filters : |
3733 java:
@@ -52,51 +48,108 @@ jobs:
5248 - '.github/workflows/**'
5349 - '.github/actions/**'
5450
51+ - name : Build language matrix
52+ id : build-matrix
53+ run : |
54+ ALL_LANGUAGES=("java-kotlin" "javascript-typescript" "python" "go" "rust" "csharp" "actions")
55+ ALL_GATES=("java" "js" "python" "go" "rust" "csharp" "actions")
56+
57+ # On push/schedule, analyse ALL languages; skip none.
58+ if [[ "${{ github.event_name }}" != "pull_request" ]]; then
59+ entries=()
60+ for lang in "${ALL_LANGUAGES[@]}"; do
61+ entries+=("{\"language\":\"${lang}\"}")
62+ done
63+ joined=$(IFS=,; echo "${entries[*]}")
64+ echo "matrix={\"include\":[${joined}]}" >> "$GITHUB_OUTPUT"
65+ echo 'skipped-matrix={"include":[]}' >> "$GITHUB_OUTPUT"
66+ else
67+ entries=()
68+ skipped=()
69+ filter_outputs=("${{ steps.filter.outputs.java }}" "${{ steps.filter.outputs.js }}" "${{ steps.filter.outputs.python }}" "${{ steps.filter.outputs.go }}" "${{ steps.filter.outputs.rust }}" "${{ steps.filter.outputs.csharp }}" "${{ steps.filter.outputs.actions }}")
70+
71+ for i in "${!ALL_LANGUAGES[@]}"; do
72+ lang="${ALL_LANGUAGES[$i]}"
73+ changed="${filter_outputs[$i]}"
74+ if [[ "$changed" == "true" ]]; then
75+ entries+=("{\"language\":\"${lang}\"}")
76+ else
77+ skipped+=("{\"language\":\"${lang}\"}")
78+ fi
79+ done
80+
81+ if [[ ${#entries[@]} -eq 0 ]]; then
82+ echo 'matrix={"include":[]}' >> "$GITHUB_OUTPUT"
83+ else
84+ joined=$(IFS=,; echo "${entries[*]}")
85+ echo "matrix={\"include\":[${joined}]}" >> "$GITHUB_OUTPUT"
86+ fi
87+
88+ if [[ ${#skipped[@]} -eq 0 ]]; then
89+ echo 'skipped-matrix={"include":[]}' >> "$GITHUB_OUTPUT"
90+ else
91+ joined=$(IFS=,; echo "${skipped[*]}")
92+ echo "skipped-matrix={\"include\":[${joined}]}" >> "$GITHUB_OUTPUT"
93+ fi
94+ fi
95+
5596 analyze :
5697 name : Analyze (${{ matrix.language }})
5798 needs : changes
58- # Run even if 'changes' is skipped (e.g. on push/schedule where paths-filter
59- # may not flag changes). Each step has its own gate condition.
60- if : always()
99+ if : ${{ fromJson(needs.changes.outputs.matrix).include[0] != null }}
61100 runs-on : ubuntu-latest
62101 permissions :
63102 security-events : write
64103 contents : read
65104 strategy :
66105 fail-fast : false
67- matrix :
68- include :
69- - language : java-kotlin
70- gate : java
71- - language : javascript-typescript
72- gate : js
73- - language : python
74- gate : python
75- - language : go
76- gate : go
77- - language : rust
78- gate : rust
79- - language : csharp
80- gate : csharp
81- - language : actions
82- gate : actions
106+ matrix : ${{ fromJson(needs.changes.outputs.matrix) }}
83107 steps :
84108 - name : Checkout repository
85- if : ${{ needs.changes.outputs[matrix.gate] == 'true' || github.event_name == 'schedule' || github.event_name == 'push' }}
86109 uses : actions/checkout@v4
87110
88111 - name : Initialize CodeQL
89- if : ${{ needs.changes.outputs[matrix.gate] == 'true' || github.event_name == 'schedule' || github.event_name == 'push' }}
90112 uses : github/codeql-action/init@v3
91113 with :
92114 languages : ${{ matrix.language }}
93115
94116 - name : Autobuild
95- if : ${{ needs.changes.outputs[matrix.gate] == 'true' || github.event_name == 'schedule' || github.event_name == 'push' }}
96117 uses : github/codeql-action/autobuild@v3
97118
98119 - name : Perform CodeQL Analysis
99- if : ${{ needs.changes.outputs[matrix.gate] == 'true' || github.event_name == 'schedule' || github.event_name == 'push' }}
100120 uses : github/codeql-action/analyze@v3
101121 with :
102122 category : " /language:${{ matrix.language }}"
123+
124+ # Upload empty SARIF for languages that were NOT analysed in this PR.
125+ # Code scanning branch protection expects results for every category that
126+ # has ever been uploaded on the default branch; missing categories block merge.
127+ skip-analysis :
128+ name : Skip (${{ matrix.language }})
129+ needs : changes
130+ if : ${{ github.event_name == 'pull_request' && fromJson(needs.changes.outputs.skipped-matrix).include[0] != null }}
131+ runs-on : ubuntu-latest
132+ permissions :
133+ security-events : write
134+ strategy :
135+ fail-fast : false
136+ matrix : ${{ fromJson(needs.changes.outputs.skipped-matrix) }}
137+ steps :
138+ - name : Create empty SARIF
139+ run : |
140+ cat > "$RUNNER_TEMP/empty.sarif" <<'EOF'
141+ {
142+ "version": "2.1.0",
143+ "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
144+ "runs": [{
145+ "tool": { "driver": { "name": "CodeQL", "version": "0.0.0" } },
146+ "results": []
147+ }]
148+ }
149+ EOF
150+
151+ - name : Upload empty SARIF
152+ uses : github/codeql-action/upload-sarif@v3
153+ with :
154+ sarif_file : ${{ runner.temp }}/empty.sarif
155+ category : " /language:${{ matrix.language }}"
0 commit comments