mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-11 16:54:03 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
`.fvmrc` is a declaration nothing in this fleet reads. `subosito/flutter-action`
takes its own `flutter-version:`, and that pin is what the runner installs, so
the two drift in silence and the failure mode is the worst kind: green
locally, red in CI, with no diff to explain it.
kuhylog is the live case. Its runner is on Flutter **3.44.9**, which predates
the `@awaitNotRequired` annotation, so `unawaited(Navigator.push(...))` is
`unnecessary_unawaited` on 3.47.2 here and `discarded_futures` there -- the two
SDKs demand opposite code and CI went red on a commit that is clean locally.
The fleet is spread across 3.44.6, 3.44.8, 3.47.0 and 3.47.1 with no one
tracking it.
So a workflow's `flutter-version:` / `node-version:` is now a dependency like
any other, judged against the same latest stable. That needs no separate
"these must agree" rule: two values both required to equal latest already
agree. A channel name and a `${{ }}` expression are skipped -- one is not a
version, the other resolves at run time and guessing is worse than silence.
Found real drift on its first run: both TypeScript workflows here pinned
`node-version: 24`, a floating major that lets two runs of the same commit
install different Node. Now 24.20.0.
321 tests, 100% branch coverage on every production module.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRykabMwPgDzFHcARoqpaK
84 lines
2.7 KiB
Python
84 lines
2.7 KiB
Python
"""The toolchain versions a CI runner actually installs.
|
|
|
|
`.fvmrc` is a declaration nothing in this fleet reads; `subosito/flutter-action`
|
|
takes its own `flutter-version:`, and that is what the runner gets. When the
|
|
two disagree the failure is green-locally / red-in-CI with no diff to explain
|
|
it -- kuhylog's runner was on Flutter 3.44.9, which predates the
|
|
`@awaitNotRequired` annotation, so the same code was a violation there and
|
|
clean here.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dep_freshness import discover
|
|
from dep_freshness.parsers import workflow
|
|
from dep_freshness.tests.conftest import write
|
|
|
|
CI = """\
|
|
name: ci
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
jobs:
|
|
verify:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: subosito/flutter-action@v2
|
|
with:
|
|
flutter-version: 3.44.9
|
|
channel: stable
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '24.18.0'
|
|
"""
|
|
|
|
|
|
def _path(repo):
|
|
return repo / ".github/workflows/ci.yml"
|
|
|
|
|
|
def test_a_workflow_pin_is_a_toolchain_dependency(repo):
|
|
deps = {
|
|
d.name: d for d in workflow.parse(write(repo, ".github/workflows/ci.yml", CI))
|
|
}
|
|
assert deps["flutter"].pinned == "3.44.9"
|
|
assert deps["flutter"].line == 12
|
|
assert deps["node"].pinned == "24.18.0"
|
|
assert deps["node"].ecosystem == "toolchain"
|
|
|
|
|
|
def test_a_channel_name_is_not_a_version(repo):
|
|
body = CI.replace("flutter-version: 3.44.9", "flutter-version: stable")
|
|
names = [
|
|
d.name for d in workflow.parse(write(repo, ".github/workflows/ci.yml", body))
|
|
]
|
|
assert "flutter" not in names, "a channel tells the gate nothing to compare"
|
|
|
|
|
|
def test_a_runtime_expression_is_skipped_rather_than_guessed(repo):
|
|
body = CI.replace("flutter-version: 3.44.9", "flutter-version: ${{ env.FLUTTER }}")
|
|
names = [
|
|
d.name for d in workflow.parse(write(repo, ".github/workflows/ci.yml", body))
|
|
]
|
|
assert "flutter" not in names
|
|
|
|
|
|
def test_an_unreadable_workflow_yields_nothing(repo):
|
|
assert workflow.parse(repo / ".github/workflows/gone.yml") == []
|
|
|
|
|
|
def test_only_files_under_github_workflows_count(repo):
|
|
assert workflow.is_workflow(_path(repo))
|
|
assert workflow.is_workflow(repo / ".github/workflows/ci.yaml")
|
|
assert not workflow.is_workflow(repo / ".github/ci.yml")
|
|
assert not workflow.is_workflow(repo / "workflows/ci.yml")
|
|
assert not workflow.is_workflow(repo / ".github/workflows/notes.md")
|
|
|
|
|
|
def test_discovery_routes_a_workflow_to_the_workflow_parser(repo):
|
|
path = write(repo, ".github/workflows/ci.yml", CI)
|
|
assert discover.is_manifest(path)
|
|
assert {d.name for d in discover.parse_manifest(path)} == {"flutter", "node"}
|
|
assert path in discover.find_manifests(repo)
|