diff --git a/.flox/env.json b/.flox/env.json index 4a42555..2e3356b 100644 --- a/.flox/env.json +++ b/.flox/env.json @@ -1,5 +1,5 @@ { - "name": "catalog-check", + "name": "declaration-check", "version": 1, "env_id": "47ab46d7-8fac-4adf-8615-34b14a0cc0c6" } diff --git a/.github/actions/check/action.yml b/.github/actions/check/action.yml index f06f4f8..2262af2 100644 --- a/.github/actions/check/action.yml +++ b/.github/actions/check/action.yml @@ -12,7 +12,7 @@ # A composite action rather than a reusable workflow for the checks themselves: # GitHub fetches an action's source while resolving `uses:`, so a caller needs # nothing checked out but its own repository. -name: catalog-check +name: declaration-check description: Run one of the checks every flox repository must pass. inputs: @@ -23,7 +23,7 @@ inputs: path: description: Declaration to read, relative to the repository root. required: false - default: catalog-info.yaml + default: flox-info.yaml python-version: required: false default: '3.12' diff --git a/.github/workflows/catalog-check.yml b/.github/workflows/declaration-check.yml similarity index 82% rename from .github/workflows/catalog-check.yml rename to .github/workflows/declaration-check.yml index 232de76..f81a002 100644 --- a/.github/workflows/catalog-check.yml +++ b/.github/workflows/declaration-check.yml @@ -10,7 +10,7 @@ # would reach private repositories only, and 83 of the live ones are public. # # Nothing here reads a credential, and nothing here needs to. See the action. -name: catalog-check +name: declaration-check on: # Kept callable directly so a repository can adopt the check ahead of the @@ -19,7 +19,7 @@ on: inputs: path: type: string - default: catalog-info.yaml + default: flox-info.yaml pull_request: push: branches: [main] @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - - uses: flox/catalog-check/.github/actions/check@2f04631c4c19ac18270d6589c8b6bf8ddbbfb504 # keep in step with main + - uses: flox/declaration-check/.github/actions/check@2f04631c4c19ac18270d6589c8b6bf8ddbbfb504 # keep in step with main with: check: declaration - path: ${{ inputs.path || 'catalog-info.yaml' }} + path: ${{ inputs.path || 'flox-info.yaml' }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9277b79..df084f4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,6 @@ # This repository's own unit tests. Nothing else runs them, and no other # repository cares about them — the check other repositories must pass is in -# catalog-check.yml. +# declaration-check.yml. name: tests # No paths filter, deliberately. A required check that is skipped never reports, diff --git a/README.md b/README.md index 7d1546f..5ffeee0 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,25 @@ -# catalog-check +# declaration-check Checks that a flox repository declares what it is and who owns it. -Every repository carries a `catalog-info.yaml` — a [Backstage entity -descriptor](https://backstage.io/docs/features/software-catalog/descriptor-format) -— saying how exposed it is, how much human review a dependency bump needs, its -maturity, and which area of responsibility owns it. This repository holds the -check that the declaration is present and complete, and nothing else. +Every repository carries a `flox-info.yaml` saying how exposed it is, how much +human review a dependency bump needs, its maturity, and which area of +responsibility owns it. This repository holds the check that the declaration is +present and complete, and nothing else. + +The contents are a [Backstage entity +descriptor](https://backstage.io/docs/features/software-catalog/descriptor-format), +unchanged — the schema is theirs and worth keeping, so a Backstage instance could +read these as-is. Only the filename is ours. Backstage's own convention is +`catalog-info.yaml`, and "catalog" at flox means the Flox Catalog, which several +floxhub components serve; a file in every repository borrowing that word would +cost more in confusion than the default filename saves in configuration. ```yaml apiVersion: backstage.io/v1alpha1 kind: Component metadata: - name: catalog-check + name: declaration-check labels: flox.dev/classification: internal-tooling # customer-facing | distribution | internal-tooling | non-shipping | non-production flox.dev/max-tier: manual # auto | assisted | manual @@ -31,11 +38,11 @@ else notices. ## Running it -An organisation ruleset names `.github/workflows/catalog-check.yml` as a required +An organisation ruleset names `.github/workflows/declaration-check.yml` as a required workflow, so repositories do not call it themselves. To run it against a checkout: ``` -python3 declaration.py --path catalog-info.yaml +python3 declaration.py --path flox-info.yaml ``` It exits 0 when the declaration is complete, 1 with the fields that are missing or diff --git a/declaration.py b/declaration.py index 780a440..faa8f15 100644 --- a/declaration.py +++ b/declaration.py @@ -5,7 +5,9 @@ place that knows the format: everything downstream takes the dict this returns, so changing the encoding later means changing this file and nothing else. -Today the encoding is a Backstage entity descriptor at `catalog-info.yaml`. That +Today the encoding is a Backstage entity descriptor at `flox-info.yaml` — their +schema, our filename, because `catalog-info.yaml` would put the Flox Catalog's +word in every repository. That is an implementation detail, not a commitment — see ADR-001 and ADR-008's withdrawal. Backstage's own schema validates the envelope; it does not validate our facts, because `metadata.labels` is an open string map and will accept a @@ -383,7 +385,7 @@ def is_expected_in_production(decl, today=None): # explains why it is being asked. # --------------------------------------------------------------------------- -DEFAULT_PATH = "catalog-info.yaml" +DEFAULT_PATH = "flox-info.yaml" TEMPLATE = """apiVersion: backstage.io/v1alpha1 kind: Component @@ -487,7 +489,7 @@ def _report_uncovered(args, gaps, declared): "declared, because its %d other part%s %s." % (declared, "" if declared == 1 else "s", "is" if declared == 1 else "are"), file=out) - print("\nAdd a catalog-info.yaml in each, and list it in %s. Or, if one of the " + print("\nAdd a flox-info.yaml in each, and list it in %s. Or, if one of the " "parts already declared should own it, move that declaration up to the " "directory above both." % args.path, file=out) _write_summary(args, "### Undeclared parts\n\n%s\n" diff --git a/catalog-info.yaml b/flox-info.yaml similarity index 92% rename from catalog-info.yaml rename to flox-info.yaml index d3b0c29..e09226b 100644 --- a/catalog-info.yaml +++ b/flox-info.yaml @@ -1,7 +1,7 @@ apiVersion: backstage.io/v1alpha1 kind: Component metadata: - name: catalog-check + name: declaration-check description: The check that every flox repository declares what it is and who owns it. labels: flox.dev/classification: internal-tooling diff --git a/test_declaration.py b/test_declaration.py index 74dea27..f4cc4f6 100644 --- a/test_declaration.py +++ b/test_declaration.py @@ -173,14 +173,14 @@ class TestMonorepoLocations(unittest.TestCase): " name: example\n" "spec:\n" " targets:\n" - " - ./src/web-ui/catalog-info.yaml\n" - " - ./src/web-bff/catalog-info.yaml\n" + " - ./src/web-ui/flox-info.yaml\n" + " - ./src/web-bff/flox-info.yaml\n" ) def test_targets_are_read_and_normalised(self): self.assertEqual( declaration.targets(self.LOCATION), - ["src/web-ui/catalog-info.yaml", "src/web-bff/catalog-info.yaml"]) + ["src/web-ui/flox-info.yaml", "src/web-bff/flox-info.yaml"]) def test_a_component_is_not_a_location(self): self.assertIsNone(declaration.targets(decl())) @@ -200,7 +200,7 @@ def test_a_location_pointing_outside_the_repository_is_refused(self): the property ADR-001 exists to get. """ external = (self.LOCATION.split("targets:")[0] - + "targets:\n - https://example.com/catalog-info.yaml\n") + + "targets:\n - https://example.com/flox-info.yaml\n") with self.assertRaises(declaration.Invalid) as caught: declaration.targets(external) self.assertIn("not URLs", " ".join(caught.exception.problems)) @@ -376,20 +376,20 @@ def location(self, *targets): def test_a_dotted_directory_keeps_its_dot(self): self.assertEqual( - declaration.targets(self.location("./.github/catalog-info.yaml")), - [".github/catalog-info.yaml"]) + declaration.targets(self.location("./.github/flox-info.yaml")), + [".github/flox-info.yaml"]) def test_a_dotted_directory_without_a_prefix_is_unchanged(self): self.assertEqual( - declaration.targets(self.location(".github/catalog-info.yaml")), - [".github/catalog-info.yaml"]) + declaration.targets(self.location(".github/flox-info.yaml")), + [".github/flox-info.yaml"]) def test_an_ordinary_relative_prefix_is_still_removed(self): self.assertEqual( - declaration.targets(self.location("./src/web-ui/catalog-info.yaml")), - ["src/web-ui/catalog-info.yaml"]) + declaration.targets(self.location("./src/web-ui/flox-info.yaml")), + ["src/web-ui/flox-info.yaml"]) def test_repeated_prefixes_are_removed_a_segment_at_a_time(self): self.assertEqual( - declaration.targets(self.location("././.github/x/catalog-info.yaml")), - [".github/x/catalog-info.yaml"]) + declaration.targets(self.location("././.github/x/flox-info.yaml")), + [".github/x/flox-info.yaml"])