From f655c07c5edd5f8e97e372c705a1115a950877c6 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 22:45:20 +0200 Subject: [PATCH 01/25] refactor to read the policy from a file --- minimum_versions.py | 125 ++++++++++++++++++++++++++++++++------------ 1 file changed, 92 insertions(+), 33 deletions(-) diff --git a/minimum_versions.py b/minimum_versions.py index 2488295..cb98f6f 100644 --- a/minimum_versions.py +++ b/minimum_versions.py @@ -5,6 +5,7 @@ import sys from dataclasses import dataclass, field +import jsonschema import rich_click as click import yaml from dateutil.relativedelta import relativedelta @@ -18,27 +19,56 @@ click.rich_click.SHOW_ARGUMENTS = True -channels = ["conda-forge"] -platforms = ["noarch", "linux-64"] -ignored_packages = [ - "coveralls", - "hypothesis", - "pip", - "pytest", - "pytest-cov", - "pytest-env", - "pytest-mypy-plugins", - "pytest-timeout", - "pytest-xdist", -] + +schema = { + "type": "object", + "properties": { + "exclude": {"type": "array", "items": {"type": "string"}}, + "channels": {"type": "array", "items": {"type": "string"}}, + "platforms": {"type": "array", "items": {"type": "string"}}, + "overrides": { + "type": "object", + "patternProperties": { + "^[a-z][-a-z_]*": {"type": "string", "format": "date"} + }, + "additionalProperties": False, + }, + "policy": { + "type": "object", + "properties": { + "packages": { + "type": "object", + "patternProperties": { + "^[a-z][-a-z_]*$": {"type": "integer", "minimum": 1} + }, + "additionalProperties": False, + }, + "default": {"type": "integer", "minimum": 1}, + "ignored_violations": { + "type": "array", + "items": {"type": "string", "pattern": "^[a-z][-a-z_]*$"}, + }, + }, + "required": ["packages", "default", "ignored_violations"], + }, + }, + "required": ["exclude", "channels", "platforms", "overrides"], +} @dataclass class Policy: package_months: dict default_months: int + + channels: list[str] = field(default_factory=list) + platforms: list[str] = field(default_factory=list) + overrides: dict[str, Version] = field(default_factory=dict) + ignored_violations: list[str] = field(default_factory=list) + exclude: list[str] = field(default_factory=list) + def minimum_version(self, today, package_name, releases): if (override := self.overrides.get(package_name)) is not None: return find_release(releases, version=override) @@ -117,6 +147,28 @@ def parse_environment(text): return specs, warnings +def parse_policy(file): + policy = yaml.safe_load(file) + try: + jsonschema.validate(instance=policy, schema=schema) + except jsonschema.ValidationError as e: + raise jsonschema.ValidationError( + f"Invalid policy definition: {str(e)}" + ) from None + + package_policy = policy["policy"] + + return Policy( + channels=policy["channels"], + platforms=policy["platforms"], + exclude=policy["exclude"], + package_months=package_policy["packages"], + default_months=package_policy["default"], + ignored_violations=package_policy["ignored_violations"], + overrides=policy["overrides"], + ) + + def is_preview(version): candidates = {"rc", "b", "a"} @@ -175,11 +227,15 @@ def lookup_spec_release(spec, releases): return releases[spec.name][version] -def compare_versions(environments, policy_versions): +def compare_versions(environments, policy_versions, ignored_violations): status = {} for env, specs in environments.items(): env_status = any( - spec.version > policy_versions[spec.name].version for spec in specs + ( + spec.name not in ignored_violations + and spec.version > policy_versions[spec.name].version + ) + for spec in specs ) status[env] = env_status return status @@ -194,7 +250,7 @@ def version_comparison_symbol(required, policy): return "=" -def format_bump_table(specs, policy_versions, releases, warnings): +def format_bump_table(specs, policy_versions, releases, warnings, ignored_violations): table = Table( Column("Package", width=20), Column("Required", width=8), @@ -221,7 +277,10 @@ def format_bump_table(specs, policy_versions, releases, warnings): required_date = lookup_spec_release(spec, releases).timestamp status = version_comparison_symbol(required_version, policy_version) - style = styles[status] + if status == ">" and spec.name in ignored_violations: + style = warning_style + else: + style = styles[status] table.add_row( spec.name, @@ -261,9 +320,12 @@ def format_bump_table(specs, policy_versions, releases, warnings): type=click.Path(exists=True, readable=True, path_type=pathlib.Path), nargs=-1, ) -def main(environment_paths): +@click.option("--policy", "policy_file", type=click.File(mode="r")) +def main(policy_file, environment_paths): console = Console() + policy = parse_policy(policy_file) + parsed_environments = { path.stem: parse_environment(path.read_text()) for path in environment_paths } @@ -272,7 +334,7 @@ def main(environment_paths): env: dict(warnings_) for env, (_, warnings_) in parsed_environments.items() } environments = { - env: [spec for spec in specs if spec.name not in ignored_packages] + env: [spec for spec in specs if spec.name not in policy.exclude] for env, (specs, _) in parsed_environments.items() } @@ -280,19 +342,10 @@ def main(environment_paths): dict.fromkeys(spec.name for spec in concat(environments.values())) ) - policy_months = { - "python": 30, - "numpy": 18, - } - policy_months_default = 12 - overrides = {} - - policy = Policy( - policy_months, default_months=policy_months_default, overrides=overrides - ) - gateway = Gateway() - query = gateway.query(channels, platforms, all_packages, recursive=False) + query = gateway.query( + policy.channels, policy.platforms, all_packages, recursive=False + ) records = asyncio.run(query) today = datetime.date.today() @@ -307,13 +360,19 @@ def main(environment_paths): package_releases, curry(find_policy_versions, policy, today), ) - status = compare_versions(environments, policy_versions) + status = compare_versions(environments, policy_versions, policy.ignored_violations) release_lookup = { n: {r.version: r for r in releases} for n, releases in package_releases.items() } grids = { - env: format_bump_table(specs, policy_versions, release_lookup, warnings[env]) + env: format_bump_table( + specs, + policy_versions, + release_lookup, + warnings[env], + policy.ignored_violations, + ) for env, specs in environments.items() } root_grid = Table.grid() From 61d9c34e524a6cf00d535db01834c51c6cb1445a Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 22:45:49 +0200 Subject: [PATCH 02/25] add example policy with a ignored violation --- envs/env2.yaml | 1 + policy.yaml | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 policy.yaml diff --git a/envs/env2.yaml b/envs/env2.yaml index 8ac6e2d..b3d620f 100644 --- a/envs/env2.yaml +++ b/envs/env2.yaml @@ -6,3 +6,4 @@ dependencies: - xarray=2023.10.0 - dask=2023.10.0 - distributed=2023.10.0 + - pydap=3.5.1 diff --git a/policy.yaml b/policy.yaml new file mode 100644 index 0000000..4981f13 --- /dev/null +++ b/policy.yaml @@ -0,0 +1,26 @@ +exclude: + - coveralls + - pip + - pytest + - pytest-asyncio + - pytest-cov + - pytest-env + - pytest-mypy-plugins + - pytest-timeout + - pytest-xdist + - pytest-hypothesis +channels: + - conda-forge +platforms: + - noarch + - linux-64 +# in case conda-forge release dates are not accurate enough +overrides: {} +policy: + # all packages in months + packages: + python: 30 + numpy: 18 + default: 12 + ignored_violations: + - pydap From 12c8bc364dad8783d5420588e8d9f67752fd5b6b Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 22:49:37 +0200 Subject: [PATCH 03/25] expose the policy in the action --- action.yaml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/action.yaml b/action.yaml index 96916b8..0433056 100644 --- a/action.yaml +++ b/action.yaml @@ -2,6 +2,11 @@ name: "minimum-dependency-versions" description: >- Check that the minimum dependency versions follow `xarray`'s policy. inputs: + policy: + description: >- + The policy to follow + required: True + type: string environment-paths: description: >- The paths to the environment files @@ -22,6 +27,6 @@ runs: env: COLUMNS: 120 FORCE_COLOR: 3 - INPUT: ${{ inputs.environment-paths }} + POLICY_PATH: ${{ inputs.policy-path }} run: | - python ${{ github.action_path }}/minimum_versions.py $(echo $INPUT) + python minimum_versions.py --policy="$POLICY_PATH" ${{ join(fromJSON(inputs.environment-paths), ' ') }} From e49e72ce209f78eb2333a288aaa001a38cb9d7f8 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 22:50:01 +0200 Subject: [PATCH 04/25] use environment variables to make the action a bit safer --- action.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 0433056..c3dbc34 100644 --- a/action.yaml +++ b/action.yaml @@ -28,5 +28,6 @@ runs: COLUMNS: 120 FORCE_COLOR: 3 POLICY_PATH: ${{ inputs.policy-path }} + ENVIRONMENT_PATHS: ${{ join(fromJSON(inputs.environment-paths), ' ') }} run: | - python minimum_versions.py --policy="$POLICY_PATH" ${{ join(fromJSON(inputs.environment-paths), ' ') }} + python minimum_versions.py --policy="$POLICY_PATH" $ENVIRONMENT_PATHS From d2c4b9e80d4f5dc7e58df5be057af70ace9769f3 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 22:56:27 +0200 Subject: [PATCH 05/25] add comments to the example policy --- policy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/policy.yaml b/policy.yaml index 4981f13..1cff7df 100644 --- a/policy.yaml +++ b/policy.yaml @@ -1,3 +1,4 @@ +# these packages are completely ignored exclude: - coveralls - pip @@ -22,5 +23,6 @@ policy: python: 30 numpy: 18 default: 12 + # these packages don't fail the CI, but will be printed in the report ignored_violations: - pydap From be141b1d1eaf13b72da1fc11f8159e2a846c446d Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 22:58:12 +0200 Subject: [PATCH 06/25] depend on jsonschema --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 3a72cd4..21cbe21 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,5 @@ rich-click cytoolz pyyaml python-dateutil +jsonschema +rfc3339-validator From f7644662c2844f2fc7dfe47c7160f3e6b62c980b Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:07:57 +0200 Subject: [PATCH 07/25] pass the policy file in ci --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f31f242..344f9c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,6 +67,7 @@ jobs: id: action-run continue-on-error: true with: + policy: policy.yaml environment-paths: ${{ matrix.env-paths }} - name: detect outcome if: always() From 44dfa5a93174cbef4cacbc2a18e23de2ee3f0c5b Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:12:36 +0200 Subject: [PATCH 08/25] pass overrides as a keyword argument --- test_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_script.py b/test_script.py index 32d4db3..22a62f9 100644 --- a/test_script.py +++ b/test_script.py @@ -44,7 +44,7 @@ def test_spec_parse(text, expected_spec, expected_name, expected_warnings): ), ( "scipy", - Policy({"numpy": 6}, 8, {"scipy": Version("1.1.1")}), + Policy({"numpy": 6}, 8, overrides={"scipy": Version("1.1.1")}), dt.date(2024, 9, 5), Release(Version("1.1.1"), 0, dt.datetime(2023, 12, 1)), ), From 63734e8a52085bfc27571153a5940f29a2f79923 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:15:35 +0200 Subject: [PATCH 09/25] directly use the input --- action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index c3dbc34..0abbabf 100644 --- a/action.yaml +++ b/action.yaml @@ -28,6 +28,6 @@ runs: COLUMNS: 120 FORCE_COLOR: 3 POLICY_PATH: ${{ inputs.policy-path }} - ENVIRONMENT_PATHS: ${{ join(fromJSON(inputs.environment-paths), ' ') }} + ENVIRONMENT_PATHS: ${{ inputs.environment-paths }} run: | python minimum_versions.py --policy="$POLICY_PATH" $ENVIRONMENT_PATHS From 4ed7d599328d4e08fbcdde2fc0e707b01b644dc1 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:15:46 +0200 Subject: [PATCH 10/25] print the env (to debug) --- action.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/action.yaml b/action.yaml index 0abbabf..45c5aeb 100644 --- a/action.yaml +++ b/action.yaml @@ -30,4 +30,5 @@ runs: POLICY_PATH: ${{ inputs.policy-path }} ENVIRONMENT_PATHS: ${{ inputs.environment-paths }} run: | + env python minimum_versions.py --policy="$POLICY_PATH" $ENVIRONMENT_PATHS From 7650463d6a7e8aecdbf3719daee3697459006854 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:17:07 +0200 Subject: [PATCH 11/25] more extensive debugging --- action.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 45c5aeb..87481ee 100644 --- a/action.yaml +++ b/action.yaml @@ -30,5 +30,6 @@ runs: POLICY_PATH: ${{ inputs.policy-path }} ENVIRONMENT_PATHS: ${{ inputs.environment-paths }} run: | - env + env | grep -i -e "environment" + env | grep -i -e "policy" python minimum_versions.py --policy="$POLICY_PATH" $ENVIRONMENT_PATHS From 37e48828f3be77e8e5bddb325bccc1f946f34b31 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:18:07 +0200 Subject: [PATCH 12/25] typo in the policy input --- action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index 87481ee..c8aa179 100644 --- a/action.yaml +++ b/action.yaml @@ -27,7 +27,7 @@ runs: env: COLUMNS: 120 FORCE_COLOR: 3 - POLICY_PATH: ${{ inputs.policy-path }} + POLICY_PATH: ${{ inputs.policy }} ENVIRONMENT_PATHS: ${{ inputs.environment-paths }} run: | env | grep -i -e "environment" From 7f2aedc006224a2cba42595d8b719921b6d25bda Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:18:30 +0200 Subject: [PATCH 13/25] rewrite the description to be more accurate --- action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yaml b/action.yaml index c8aa179..8f7e468 100644 --- a/action.yaml +++ b/action.yaml @@ -4,7 +4,7 @@ description: >- inputs: policy: description: >- - The policy to follow + The path to the policy to follow required: True type: string environment-paths: From a524a38318fd1ead9adef75d05392ca09d34c1a2 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:24:38 +0200 Subject: [PATCH 14/25] allow using a time machine (this is important to keep the tests passing) --- minimum_versions.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/minimum_versions.py b/minimum_versions.py index cb98f6f..5b65348 100644 --- a/minimum_versions.py +++ b/minimum_versions.py @@ -314,14 +314,19 @@ def format_bump_table(specs, policy_versions, releases, warnings, ignored_violat return grid +def parse_date(string): + return datetime.datetime.strptime(string, "%Y-%m-%d").date() + + @click.command() @click.argument( "environment_paths", type=click.Path(exists=True, readable=True, path_type=pathlib.Path), nargs=-1, ) -@click.option("--policy", "policy_file", type=click.File(mode="r")) -def main(policy_file, environment_paths): +@click.option("--today", type=parse_date, default=None) +@click.option("--policy", "policy_file", type=click.File(mode="r"), required=True) +def main(today, policy_file, environment_paths): console = Console() policy = parse_policy(policy_file) @@ -348,7 +353,8 @@ def main(policy_file, environment_paths): ) records = asyncio.run(query) - today = datetime.date.today() + if today is None: + today = datetime.date.today() package_releases = pipe( records, concat, From 34f85153d4a7014802e4747fdd91d080a606cc37 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:28:59 +0200 Subject: [PATCH 15/25] allow passing `today` to the action --- .github/workflows/ci.yml | 1 + action.yaml | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 344f9c1..0a2ea65 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,7 @@ jobs: with: policy: policy.yaml environment-paths: ${{ matrix.env-paths }} + today: 2024-02-04 - name: detect outcome if: always() shell: bash -l {0} diff --git a/action.yaml b/action.yaml index 8f7e468..466a64e 100644 --- a/action.yaml +++ b/action.yaml @@ -5,13 +5,18 @@ inputs: policy: description: >- The path to the policy to follow - required: True + required: true type: string environment-paths: description: >- The paths to the environment files - required: True + required: true type: list + today: + description: >- + Time machine for testing + required: false + type: string outputs: {} runs: From 9dcc2c2b36ca1c7a6fa9d1fad3280d51a372d107 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:32:41 +0200 Subject: [PATCH 16/25] use a bash array to pass options --- action.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/action.yaml b/action.yaml index 466a64e..feee2c5 100644 --- a/action.yaml +++ b/action.yaml @@ -34,7 +34,11 @@ runs: FORCE_COLOR: 3 POLICY_PATH: ${{ inputs.policy }} ENVIRONMENT_PATHS: ${{ inputs.environment-paths }} + TODAY: ${{ inputs.today }} run: | - env | grep -i -e "environment" - env | grep -i -e "policy" - python minimum_versions.py --policy="$POLICY_PATH" $ENVIRONMENT_PATHS + if [[ "$TODAY" != "" ]]; then + opts=(--today="$TODAY") + else + opts=() + fi + python minimum_versions.py "$opts" --policy="$POLICY_PATH" $ENVIRONMENT_PATHS From 639f377f9d77cbabf0ba6990586102b3419bc198 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:34:25 +0200 Subject: [PATCH 17/25] mock today as Sep 2024 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a2ea65..51d3492 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: with: policy: policy.yaml environment-paths: ${{ matrix.env-paths }} - today: 2024-02-04 + today: 2024-09-05 - name: detect outcome if: always() shell: bash -l {0} From dd4a0d123402d98d6a1c4a7d36bb74b35ac09f5e Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:39:46 +0200 Subject: [PATCH 18/25] interpret empty string as `None` --- action.yaml | 7 +------ minimum_versions.py | 3 +++ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/action.yaml b/action.yaml index feee2c5..94446fc 100644 --- a/action.yaml +++ b/action.yaml @@ -36,9 +36,4 @@ runs: ENVIRONMENT_PATHS: ${{ inputs.environment-paths }} TODAY: ${{ inputs.today }} run: | - if [[ "$TODAY" != "" ]]; then - opts=(--today="$TODAY") - else - opts=() - fi - python minimum_versions.py "$opts" --policy="$POLICY_PATH" $ENVIRONMENT_PATHS + python minimum_versions.py --today="$TODAY" --policy="$POLICY_PATH" $ENVIRONMENT_PATHS diff --git a/minimum_versions.py b/minimum_versions.py index 5b65348..460b302 100644 --- a/minimum_versions.py +++ b/minimum_versions.py @@ -315,6 +315,9 @@ def format_bump_table(specs, policy_versions, releases, warnings, ignored_violat def parse_date(string): + if not string: + return None + return datetime.datetime.strptime(string, "%Y-%m-%d").date() From 1007c1038392be5a0a5fc96b8ad104bbe3cfb942 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:41:37 +0200 Subject: [PATCH 19/25] bump the mock date --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51d3492..0d1e9e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: with: policy: policy.yaml environment-paths: ${{ matrix.env-paths }} - today: 2024-09-05 + today: 2024-12-20 - name: detect outcome if: always() shell: bash -l {0} From f01106186fb6424369f7176a6610e8b9f0031d90 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:47:40 +0200 Subject: [PATCH 20/25] include the policy file in the readme --- README.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0939659..e75dd7e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,35 @@ Check that the minimum dependency versions follow `xarray`'s policy. ## Usage -To use the `minimum-dependency-versions` action in workflows, simply add a new step: +To use the `minimum-dependency-versions` action in workflows, create a policy file (`policy.yaml`): + +```yaml +# these packages are completely ignored +exclude: + - package1 + - package2 + - ... +channels: + - conda-forge +platforms: + - noarch + - linux-64 +policy: + # policy in months + # Example is xarray's values + packages: + python: 30 + numpy: 18 + default: 12 + overrides: + # override the policy for specific packages + package3: 0.3.1 + # these packages don't fail the CI, but will be printed in the report as a warning + ignored_violations: + - package4 +``` + +then add a new step to CI: ```yaml jobs: @@ -14,6 +42,7 @@ jobs: ... - uses: xarray-contrib/minimum-dependency-versions@version with: + policy: policy.yaml environment-paths: path/to/env.yaml ``` From 061479d43df0a4870f45873ac1a35842ebafc950 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:49:18 +0200 Subject: [PATCH 21/25] move the overrides into the package policy --- minimum_versions.py | 20 ++++++++++---------- policy.yaml | 3 +-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/minimum_versions.py b/minimum_versions.py index 460b302..20df0ab 100644 --- a/minimum_versions.py +++ b/minimum_versions.py @@ -26,13 +26,6 @@ "exclude": {"type": "array", "items": {"type": "string"}}, "channels": {"type": "array", "items": {"type": "string"}}, "platforms": {"type": "array", "items": {"type": "string"}}, - "overrides": { - "type": "object", - "patternProperties": { - "^[a-z][-a-z_]*": {"type": "string", "format": "date"} - }, - "additionalProperties": False, - }, "policy": { "type": "object", "properties": { @@ -44,15 +37,22 @@ "additionalProperties": False, }, "default": {"type": "integer", "minimum": 1}, + "overrides": { + "type": "object", + "patternProperties": { + "^[a-z][-a-z_]*": {"type": "string", "format": "date"} + }, + "additionalProperties": False, + }, "ignored_violations": { "type": "array", "items": {"type": "string", "pattern": "^[a-z][-a-z_]*$"}, }, }, - "required": ["packages", "default", "ignored_violations"], + "required": ["packages", "default", "overrides", "ignored_violations"], }, }, - "required": ["exclude", "channels", "platforms", "overrides"], + "required": ["exclude", "channels", "platforms", "policy"], } @@ -165,7 +165,7 @@ def parse_policy(file): package_months=package_policy["packages"], default_months=package_policy["default"], ignored_violations=package_policy["ignored_violations"], - overrides=policy["overrides"], + overrides=package_policy["overrides"], ) diff --git a/policy.yaml b/policy.yaml index 1cff7df..5b55bff 100644 --- a/policy.yaml +++ b/policy.yaml @@ -15,14 +15,13 @@ channels: platforms: - noarch - linux-64 -# in case conda-forge release dates are not accurate enough -overrides: {} policy: # all packages in months packages: python: 30 numpy: 18 default: 12 + overrides: {} # these packages don't fail the CI, but will be printed in the report ignored_violations: - pydap From bda385d5884e9492158baab61900950cb4362aa1 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:51:54 +0200 Subject: [PATCH 22/25] also move `exclude` into the policy section --- README.md | 10 +++++----- minimum_versions.py | 14 ++++++++++---- policy.yaml | 25 +++++++++++++------------ 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index e75dd7e..69ac401 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,6 @@ Check that the minimum dependency versions follow `xarray`'s policy. To use the `minimum-dependency-versions` action in workflows, create a policy file (`policy.yaml`): ```yaml -# these packages are completely ignored -exclude: - - package1 - - package2 - - ... channels: - conda-forge platforms: @@ -27,6 +22,11 @@ policy: overrides: # override the policy for specific packages package3: 0.3.1 + # these packages are completely ignored + exclude: + - package1 + - package2 + - ... # these packages don't fail the CI, but will be printed in the report as a warning ignored_violations: - package4 diff --git a/minimum_versions.py b/minimum_versions.py index 20df0ab..e29074a 100644 --- a/minimum_versions.py +++ b/minimum_versions.py @@ -23,7 +23,6 @@ schema = { "type": "object", "properties": { - "exclude": {"type": "array", "items": {"type": "string"}}, "channels": {"type": "array", "items": {"type": "string"}}, "platforms": {"type": "array", "items": {"type": "string"}}, "policy": { @@ -44,15 +43,22 @@ }, "additionalProperties": False, }, + "exclude": {"type": "array", "items": {"type": "string"}}, "ignored_violations": { "type": "array", "items": {"type": "string", "pattern": "^[a-z][-a-z_]*$"}, }, }, - "required": ["packages", "default", "overrides", "ignored_violations"], + "required": [ + "packages", + "default", + "overrides", + "exclude", + "ignored_violations", + ], }, }, - "required": ["exclude", "channels", "platforms", "policy"], + "required": ["channels", "platforms", "policy"], } @@ -161,7 +167,7 @@ def parse_policy(file): return Policy( channels=policy["channels"], platforms=policy["platforms"], - exclude=policy["exclude"], + exclude=package_policy["exclude"], package_months=package_policy["packages"], default_months=package_policy["default"], ignored_violations=package_policy["ignored_violations"], diff --git a/policy.yaml b/policy.yaml index 5b55bff..59a629b 100644 --- a/policy.yaml +++ b/policy.yaml @@ -1,15 +1,3 @@ -# these packages are completely ignored -exclude: - - coveralls - - pip - - pytest - - pytest-asyncio - - pytest-cov - - pytest-env - - pytest-mypy-plugins - - pytest-timeout - - pytest-xdist - - pytest-hypothesis channels: - conda-forge platforms: @@ -21,7 +9,20 @@ policy: python: 30 numpy: 18 default: 12 + # overrides for the policy overrides: {} + # these packages are completely ignored + exclude: + - coveralls + - pip + - pytest + - pytest-asyncio + - pytest-cov + - pytest-env + - pytest-mypy-plugins + - pytest-timeout + - pytest-xdist + - pytest-hypothesis # these packages don't fail the CI, but will be printed in the report ignored_violations: - pydap From db20865bcbe8626885af8616c245bff7deac8cc0 Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:53:16 +0200 Subject: [PATCH 23/25] ignore coverage cache files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5b48d8a..644c670 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .prettier_cache __pycache__/ +.coverage From 49bcbc71b3634c78be897093781cbf13b8eb97fb Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:53:57 +0200 Subject: [PATCH 24/25] autoupdate hooks --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5a63125..354db93 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -9,7 +9,7 @@ repos: hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.7 + rev: v0.12.11 hooks: - id: ruff args: ["--fix"] From 8098eb473741f98e8f1e67f7d0143394819bb76b Mon Sep 17 00:00:00 2001 From: Justus Magin Date: Fri, 29 Aug 2025 23:56:18 +0200 Subject: [PATCH 25/25] put the dependency installation into a capture group --- action.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/action.yaml b/action.yaml index 94446fc..36af420 100644 --- a/action.yaml +++ b/action.yaml @@ -26,7 +26,9 @@ runs: - name: install dependencies shell: bash -l {0} run: | + echo "::group::Install dependencies" python -m pip install -r ${{ github.action_path }}/requirements.txt + echo "::endgroup::" - name: analyze environments shell: bash -l {0} env: