|
12 | 12 | push: |
13 | 13 | branches: [main, master] |
14 | 14 |
|
| 15 | +# Cause-B mitigation (#77): cancel superseded runs so stacked pushes |
| 16 | +# to the same ref don't pile up identical jobs in the queue. |
| 17 | +concurrency: |
| 18 | + group: ${{ github.workflow }}-${{ github.ref }} |
| 19 | + cancel-in-progress: true |
| 20 | + |
15 | 21 | permissions: |
16 | 22 | contents: read |
17 | 23 |
|
@@ -256,31 +262,37 @@ jobs: |
256 | 262 |
|
257 | 263 | echo "has_manifest=true" >> "$GITHUB_OUTPUT" |
258 | 264 |
|
259 | | - # Validate TOML structure using Python 3.11+ tomllib |
260 | | - python3 -c " |
261 | | -import tomllib, sys |
262 | | -with open('eclexiaiser.toml', 'rb') as f: |
263 | | - data = tomllib.load(f) |
264 | | -project = data.get('project', {}) |
265 | | -if not project.get('name', '').strip(): |
266 | | - print('ERROR: project.name is required', file=sys.stderr) |
267 | | - sys.exit(1) |
268 | | -functions = data.get('functions', []) |
269 | | -if not functions: |
270 | | - print('ERROR: at least one [[functions]] entry is required', file=sys.stderr) |
271 | | - sys.exit(1) |
272 | | -for fn in functions: |
273 | | - if not fn.get('name', '').strip(): |
274 | | - print('ERROR: function name cannot be empty', file=sys.stderr) |
275 | | - sys.exit(1) |
276 | | - if not fn.get('source', '').strip(): |
277 | | - print(f'ERROR: function {fn[\"name\"]} has no source path', file=sys.stderr) |
278 | | - sys.exit(1) |
279 | | -print(f'Valid: {project[\"name\"]} ({len(functions)} function(s))') |
280 | | -" || { |
| 265 | + # Validate TOML structure using Python 3.11+ tomllib. |
| 266 | + # The Python heredoc body sits at the YAML block-scalar base |
| 267 | + # indentation, so after GitHub strips the block's common indent |
| 268 | + # the interpreter receives it column-aligned (no sed dedent — |
| 269 | + # a sed-based dedent breaks because YAML removes the block's |
| 270 | + # leading indent before the script ever reaches the shell). |
| 271 | + if ! python3 - <<'PY' |
| 272 | + import tomllib, sys |
| 273 | + with open('eclexiaiser.toml', 'rb') as f: |
| 274 | + data = tomllib.load(f) |
| 275 | + project = data.get('project', {}) |
| 276 | + if not project.get('name', '').strip(): |
| 277 | + print('ERROR: project.name is required', file=sys.stderr) |
| 278 | + sys.exit(1) |
| 279 | + functions = data.get('functions', []) |
| 280 | + if not functions: |
| 281 | + print('ERROR: at least one [[functions]] entry is required', file=sys.stderr) |
| 282 | + sys.exit(1) |
| 283 | + for fn in functions: |
| 284 | + if not fn.get('name', '').strip(): |
| 285 | + print('ERROR: function name cannot be empty', file=sys.stderr) |
| 286 | + sys.exit(1) |
| 287 | + if not fn.get('source', '').strip(): |
| 288 | + print(f'ERROR: function {fn["name"]} has no source path', file=sys.stderr) |
| 289 | + sys.exit(1) |
| 290 | + print(f'Valid: {project["name"]} ({len(functions)} function(s))') |
| 291 | + PY |
| 292 | + then |
281 | 293 | echo "::error file=eclexiaiser.toml::Invalid eclexiaiser.toml — see step output for details" |
282 | 294 | exit 1 |
283 | | - } |
| 295 | + fi |
284 | 296 |
|
285 | 297 | - name: Write summary |
286 | 298 | run: | |
|
0 commit comments