diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65cde63..4887953 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -167,7 +167,6 @@ jobs: env: GH_TOKEN: ${{ github.token }} TAG: ${{ needs.prepare.outputs.release_tag }} - env: KERNEL_REF: ${{ needs.prepare.outputs.kernel_ref }} KERNEL_SHA: ${{ needs.prepare.outputs.kernel_sha }} run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20676fa..beea281 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,14 +26,8 @@ jobs: shellcheck --version shellcheck scripts/*.sh packaging/*.sh - - name: workflows parse - run: | - python3 - <<'EOF' - import glob, yaml - for f in sorted(glob.glob(".github/workflows/*.yml")): - yaml.safe_load(open(f)) - print("ok", f) - EOF + - name: workflows + run: ./scripts/lint-workflows.py # Catches the failure mode this repo cares about most: Kconfig silently # dropping a requested option. Takes a few minutes, no compilation. diff --git a/scripts/lint-workflows.py b/scripts/lint-workflows.py new file mode 100755 index 0000000..de0fc62 --- /dev/null +++ b/scripts/lint-workflows.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +"""Check the workflow files the way GitHub does, not the way PyYAML does. + +yaml.safe_load() accepts duplicate mapping keys and silently keeps the last +one, so a second `env:` in a step parses cleanly here and is then rejected by +GitHub with "'env' is already defined" - after a push, with zero jobs run and +no log to read. This loader refuses duplicates instead. +""" + +import glob +import sys + +import yaml + + +class StrictLoader(yaml.SafeLoader): + pass + + +def no_duplicates(loader, node, deep=False): + mapping = {} + for key_node, value_node in node.value: + key = loader.construct_object(key_node, deep=deep) + if key in mapping: + raise yaml.YAMLError( + "duplicate key %r at line %d, column %d" + % (key, key_node.start_mark.line + 1, key_node.start_mark.column + 1) + ) + mapping[key] = loader.construct_object(value_node, deep=deep) + return mapping + + +StrictLoader.add_constructor( + yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, no_duplicates +) + + +def main(paths): + paths = paths or sorted(glob.glob(".github/workflows/*.yml")) + failed = False + for path in paths: + try: + doc = yaml.load(open(path), Loader=StrictLoader) + except yaml.YAMLError as exc: + print("FAIL %s: %s" % (path, exc)) + failed = True + continue + jobs = doc.get("jobs") or {} + if not jobs: + print("FAIL %s: no jobs defined" % path) + failed = True + continue + print("ok %s (%s)" % (path, ", ".join(jobs))) + return 1 if failed else 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:]))