fix(ci): run existing script contracts in quick checks (#7203)

* fix(ci): share quick checks and lint workflows

* fix(ci): install actionlint from its verified release

* fix(ci): reject dependencies on required quick checks

* fix(ci): run existing script contracts in quick checks
This commit is contained in:
Zhengchao An
2026-09-06 00:50:06 +08:00
committed by GitHub
parent a6b5da64f2
commit 8f763fb1a2
3 changed files with 21 additions and 19 deletions
+4
View File
@@ -94,6 +94,10 @@ runs:
shell: bash
run: ./scripts/check_embedded_secrets.sh
- name: Run script contract tests
shell: bash
run: make script-tests
- name: Check test wiring
shell: bash
run: |
+9 -5
View File
@@ -567,7 +567,7 @@ def check_quick_checks(root: Path) -> list[str]:
errors.append(f"{relative}: missing composite action")
return errors
steps = yaml_block(runs, "steps", 2) or []
for command in ("shellcheck --version && actionlint", "./scripts/check_error_other_format_ratchet.sh"):
for command in ("shellcheck --version && actionlint", "./scripts/check_error_other_format_ratchet.sh", "make script-tests"):
step = workflow_step_block(steps, command, key="run", indent=4)
if step is None:
errors.append(f"{relative}: missing direct execution of {command}")
@@ -906,6 +906,7 @@ class SelfTests(unittest.TestCase):
" - name: Lint workflows\n shell: bash\n run: shellcheck --version && actionlint\n"
" - name: Error format ratchet\n shell: bash\n"
" run: ./scripts/check_error_other_format_ratchet.sh\n"
" - name: Script tests\n shell: bash\n run: make script-tests\n"
)
sources = {
".github/workflows/ci.yml": caller.replace(
@@ -964,6 +965,8 @@ class SelfTests(unittest.TestCase):
"only installed actionlint": action.replace("run: shellcheck --version && actionlint", "run: echo actionlint"),
"missing shellcheck preflight": action.replace("shellcheck --version && ", ""),
"missing ratchet": action.replace("run: ./scripts/check_error_other_format_ratchet.sh", "run: echo skipped"),
"missing script tests": action.replace("run: make script-tests", "run: echo skipped"),
"swallowed script failure": action.replace("run: make script-tests", "run: make script-tests || true"),
"swallowed lint failure": action.replace("&& actionlint", "&& actionlint || true"),
"swallowed ratchet failure": action.replace("ratchet.sh", "ratchet.sh || true"),
"conditional lint": action.replace("run: shellcheck", "if: false\n run: shellcheck"),
@@ -973,7 +976,7 @@ class SelfTests(unittest.TestCase):
"name: Lint workflows", "name: |\n run: shellcheck --version && actionlint"
).replace("\n run: shellcheck --version && actionlint\n", "\n run: shellcheck --version && actionlint\n || true\n"),
}
for command in ("shellcheck --version && actionlint", "./scripts/check_error_other_format_ratchet.sh"):
for command in ("shellcheck --version && actionlint", "./scripts/check_error_other_format_ratchet.sh", "make script-tests"):
for key in ("'if' : false", '"if": false', "'continue-on-error': true", '"continue-on-error" : true'):
mutations[f"quoted {command} {key}"] = action.replace(f"run: {command}", f"{key}\n run: {command}")
for separator in ("", "\n", " # continued command\n"):
@@ -994,9 +997,10 @@ class SelfTests(unittest.TestCase):
root = Path(tmp)
(root / "scripts").mkdir()
commands = ("shellcheck", "actionlint", "./scripts/check_error_other_format_ratchet.sh")
for failing in commands:
(root / "Makefile").write_text(".PHONY: script-tests\nscript-tests:\n\texit 17\n")
for failing in (*commands, "make script-tests"):
with self.subTest(command=failing):
run = "shellcheck --version && actionlint" if failing != commands[-1] else failing
run = "shellcheck --version && actionlint" if failing in ("shellcheck", "actionlint") else failing
step = workflow_step_block(steps, run, key="run", indent=4)
self.assertIsNotNone(step)
run_index = next(index for index, line in enumerate(step[1]) if line.startswith(" run:"))
@@ -1011,7 +1015,7 @@ class SelfTests(unittest.TestCase):
cwd=root, env=dict(os.environ, PATH=f"{root}{os.pathsep}{os.environ['PATH']}"),
capture_output=True, text=True,
)
self.assertEqual(result.returncode, 17, result.stderr)
self.assertEqual(result.returncode, 2 if failing == "make script-tests" else 17, result.stderr)
def test_validate_includes_quick_checks(self) -> None:
error = "Quick Checks wiring regression"
+8 -14
View File
@@ -62,20 +62,14 @@ exit 1
STUB
chmod +x "$TMP_ROOT/bin/python3"
SANDBOX_PATH="$TMP_ROOT/bin:/usr/bin:/bin"
if PATH="$SANDBOX_PATH" command -v uv >/dev/null 2>&1; then
# uv is reachable even from the sandbox PATH, so the resolver would
# legitimately fall back to it instead of failing. Skip this case.
echo "️ uv is on the sandbox PATH; skipping the no-interpreter case"
else
if PATH="$SANDBOX_PATH" "$RESOLVER" -c 'pass' \
>"$TMP_ROOT/none.out" 2>"$TMP_ROOT/none.err"; then
fail "resolver succeeded with no usable interpreter on PATH"
fi
grep -q 'No Python 3.11+ interpreter found' "$TMP_ROOT/none.err" \
|| fail "missing-interpreter failure did not name the requirement"
grep -q 'RUSTFS_PYTHON=' "$TMP_ROOT/none.err" \
|| fail "missing-interpreter failure did not point at the override"
ln -s "$(command -v bash)" "$TMP_ROOT/bin/bash"
if PATH="$TMP_ROOT/bin" RUSTFS_PYTHON="" "$RESOLVER" -c 'pass' \
>"$TMP_ROOT/none.out" 2>"$TMP_ROOT/none.err"; then
fail "resolver succeeded with no usable interpreter on PATH"
fi
grep -q 'No Python 3.11+ interpreter found' "$TMP_ROOT/none.err" \
|| fail "missing-interpreter failure did not name the requirement"
grep -q 'RUSTFS_PYTHON=' "$TMP_ROOT/none.err" \
|| fail "missing-interpreter failure did not point at the override"
echo "✅ scripts/python_bin.sh resolver checks passed"