mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-10-19 02:51:42 -07:00
forgetest: the lint's docstrings and its row reason say what it reads, not what a workflow runs on
host_row_problems' docstring gave the reason a row is listed as "a
dispatch, a call or a schedule runs on no change". A workflow on
workflow_call alone runs on every run of the workflow that calls it
(forgeext's package.yml is one); the lint lists it because it does not
follow a call to its caller. The reason it printed, "<ci> runs on no
push or pull request", was false the same way for such a workflow, and
for a flow mapping (`on: {push: ...}`) that names push. The docstrings
of _on_every_run and workflow_runs said that a step under an `if:`
other than true does not run on every run, where the lint evaluates no
condition: a step under `always()` or `success()` runs on every run and
still counts as no step. The Test page of the site says each of these
as the lint applies it.
The docstrings now say what the lint reads: a row is listed when the
workflow's own `on:` names neither push nor pull_request as the lint
reads it (a dispatch, a call or a schedule alone, a call not followed
to its caller, a flow mapping), and a step with a condition counts as
no step because the lint evaluates none. The row's reason reads "<ci>:
the lint reads no push or pull_request in its own on:". The comments
of the two cases that hold these rules say the same. No rule changes:
the same rows are listed, for the same workflows.
Proof: forgetest-ci "Unit tests" (`python -B -m unittest discover -s
tests -v` in forgetest): test_manifest.py runs 39 tests, OK, on Windows
with python 3.14 and on Ubuntu 24.04 with python 3.12, with
test_the_workflow_has_to_run_the_host_test asserting the new reason. A
probe of host_row_problems: a workflow on workflow_call alone and one
whose flow-mapping `on:` names push are each listed with the new
reason, and a plain `on: [push]` one is not. The coverage lint on the
tree manifest from the recipe pins reports 0 uncovered paths, 0
host-tested row problems, 43 tests. pyflakes reports no undefined name.
Acceptance: none. forgetest is dev-only and in no fingerprint (the
source_sha of 43 of 43 tests is unchanged); the lint runs in CI, not in
a campaign, and tests/ are in no fingerprint.
This commit is contained in:
@@ -577,12 +577,13 @@ def workflow_steps(text):
|
|||||||
|
|
||||||
|
|
||||||
def _on_every_run(step):
|
def _on_every_run(step):
|
||||||
"""Whether a step runs on every run of its workflow and its failure
|
"""Whether the lint counts a step as one that runs on every run of
|
||||||
fails the run: neither it nor its job carries an `if:` other than
|
its workflow and fails the run when it fails: neither the step nor
|
||||||
`true`, or a `continue-on-error:` other than `false`. A step that
|
its job carries an `if:` other than the literal `true` or a
|
||||||
runs only under a condition, or whose failure the run tolerates,
|
`continue-on-error:` other than the literal `false`, and the
|
||||||
proves nothing about what it runs, and neither does a step of a
|
workflow has no key the lint cannot read ("unread"). The lint
|
||||||
workflow with a key the lint cannot read ("unread")."""
|
evaluates no condition, so a step under `always()` or `success()`
|
||||||
|
counts as no step too."""
|
||||||
if step.get("unread"):
|
if step.get("unread"):
|
||||||
return False
|
return False
|
||||||
for d in (step, step.get("job") or {}):
|
for d in (step, step.get("job") or {}):
|
||||||
@@ -708,10 +709,11 @@ def workflow_runs(steps, test_path):
|
|||||||
(tests.test_x, tests.test_x.Case.test_one); unittest discover from the
|
(tests.test_x, tests.test_x.Case.test_one); unittest discover from the
|
||||||
test's own directory with a pattern its name matches; pytest on the
|
test's own directory with a pattern its name matches; pytest on the
|
||||||
test or its own directory. An argument to anything else (echo, a build,
|
test or its own directory. An argument to anything else (echo, a build,
|
||||||
an install) does not run the test. Only a step that runs on every run of
|
an install) does not run the test. Only a step that _on_every_run
|
||||||
the workflow, and that fails the run when it fails, counts: a step under
|
accepts counts: the lint evaluates no condition, so a step under an
|
||||||
an `if:` other than true, or with a `continue-on-error:` other than
|
`if:` other than the literal true, or with a `continue-on-error:`
|
||||||
false, on the step or on its job, runs nothing."""
|
other than the literal false, on the step or on its job, counts as
|
||||||
|
no step."""
|
||||||
full = posixpath.normpath(test_path)
|
full = posixpath.normpath(test_path)
|
||||||
stem, ext = posixpath.splitext(posixpath.basename(full))
|
stem, ext = posixpath.splitext(posixpath.basename(full))
|
||||||
compiled = ext in (".c", ".cc", ".cpp")
|
compiled = ext in (".c", ".cc", ".cpp")
|
||||||
@@ -757,10 +759,12 @@ def host_row_problems(manifest, host=HOST_TESTED, root=REPO_ROOT, sources=SOURCE
|
|||||||
"""HOST_TESTED rows that prove nothing: a glob that selects no
|
"""HOST_TESTED rows that prove nothing: a glob that selects no
|
||||||
behavioral file of its component (the same defect as an empty covers
|
behavioral file of its component (the same defect as an empty covers
|
||||||
entry), a host test or a workflow that does not exist, a workflow that
|
entry), a host test or a workflow that does not exist, a workflow that
|
||||||
cannot be read where it should be, one that runs on no push or pull
|
cannot be read where it should be, one whose own `on:` names neither
|
||||||
request (a dispatch, a call or a schedule runs on no change), one that
|
push nor pull_request as the lint reads it (workflow_triggers: a
|
||||||
does not check out the test's repository, or one with no step that
|
dispatch, a call or a schedule alone, a call not followed to the
|
||||||
runs the test on every run (workflow_runs). Whether a
|
workflow that calls it, and a flow mapping, which names no event),
|
||||||
|
one that does not check out the test's repository, or one with no
|
||||||
|
step that runs the test on every run (workflow_runs). Whether a
|
||||||
workflow runs its test is not checked where it cannot be read (see
|
workflow runs its test is not checked where it cannot be read (see
|
||||||
read_source). Returns [(component, glob, host test, why)]."""
|
read_source). Returns [(component, glob, host test, why)]."""
|
||||||
out = []
|
out = []
|
||||||
@@ -779,7 +783,7 @@ def host_row_problems(manifest, host=HOST_TESTED, root=REPO_ROOT, sources=SOURCE
|
|||||||
if text is None:
|
if text is None:
|
||||||
continue
|
continue
|
||||||
if not workflow_triggers(text) & {"push", "pull_request"}:
|
if not workflow_triggers(text) & {"push", "pull_request"}:
|
||||||
out.append((comp, pat, ref, "%s runs on no push or pull request" % ci))
|
out.append((comp, pat, ref, "%s: the lint reads no push or pull_request in its own on:" % ci))
|
||||||
continue
|
continue
|
||||||
steps = workflow_steps(text)
|
steps = workflow_steps(text)
|
||||||
test_repo, _sep, test_path = ref.partition(":")
|
test_repo, _sep, test_path = ref.partition(":")
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ class CoverageReportTests(unittest.TestCase):
|
|||||||
self.assertEqual(m.host_row_problems(man, [runs], root=root, sources=None), [])
|
self.assertEqual(m.host_row_problems(man, [runs], root=root, sources=None), [])
|
||||||
self.assertEqual(m.host_row_problems(man, [idle], root=root, sources=None),
|
self.assertEqual(m.host_row_problems(man, [idle], root=root, sources=None),
|
||||||
[(idle[0], idle[1], idle[2], ci + " does not run it")])
|
[(idle[0], idle[1], idle[2], ci + " does not run it")])
|
||||||
# a workflow that runs on no push or pull request runs it on no change, and a step whose
|
# a workflow whose own on: names neither push nor pull_request is listed, and a step whose
|
||||||
# failure the run tolerates does not run it
|
# failure the run tolerates does not run it
|
||||||
job = "jobs:\n test:\n steps:\n - uses: actions/checkout@v4\n - run: python3 scripts/bench/stream_test.py\n"
|
job = "jobs:\n test:\n steps:\n - uses: actions/checkout@v4\n - run: python3 scripts/bench/stream_test.py\n"
|
||||||
root = self._root({"scripts/bench/stream_test.py": "",
|
root = self._root({"scripts/bench/stream_test.py": "",
|
||||||
@@ -252,7 +252,7 @@ class CoverageReportTests(unittest.TestCase):
|
|||||||
manual = runs[:3] + ("forgefirm:.github/workflows/manual.yml",)
|
manual = runs[:3] + ("forgefirm:.github/workflows/manual.yml",)
|
||||||
soft = runs[:3] + ("forgefirm:.github/workflows/soft.yml",)
|
soft = runs[:3] + ("forgefirm:.github/workflows/soft.yml",)
|
||||||
self.assertEqual(m.host_row_problems(man, [manual, soft], root=root, sources=None),
|
self.assertEqual(m.host_row_problems(man, [manual, soft], root=root, sources=None),
|
||||||
[manual[:3] + (manual[3] + " runs on no push or pull request",),
|
[manual[:3] + (manual[3] + ": the lint reads no push or pull_request in its own on:",),
|
||||||
soft[:3] + (soft[3] + " does not run it",)])
|
soft[:3] + (soft[3] + " does not run it",)])
|
||||||
|
|
||||||
def _runs(self, yml, path):
|
def _runs(self, yml, path):
|
||||||
@@ -320,7 +320,8 @@ class CoverageReportTests(unittest.TestCase):
|
|||||||
def test_a_step_counts_only_when_every_run_of_the_workflow_runs_it_and_its_failure_fails_the_run(self):
|
def test_a_step_counts_only_when_every_run_of_the_workflow_runs_it_and_its_failure_fails_the_run(self):
|
||||||
step = "steps:\n - name: x\n%s run: ./build/tray_test\n"
|
step = "steps:\n - name: x\n%s run: ./build/tray_test\n"
|
||||||
test = "tests/tray_test.c"
|
test = "tests/tray_test.c"
|
||||||
# a step under an if: runs it on some runs, not every run; literally true is no condition
|
# the lint evaluates no condition: an if: other than the literal true counts as no step,
|
||||||
|
# always() included; literally true is no condition
|
||||||
self.assertFalse(self._runs(step % " if: false\n", test))
|
self.assertFalse(self._runs(step % " if: false\n", test))
|
||||||
self.assertFalse(self._runs(step % " if: github.event_name == 'push'\n", test))
|
self.assertFalse(self._runs(step % " if: github.event_name == 'push'\n", test))
|
||||||
self.assertFalse(self._runs(step % " if: ${{ always() }}\n", test))
|
self.assertFalse(self._runs(step % " if: ${{ always() }}\n", test))
|
||||||
|
|||||||
Reference in New Issue
Block a user