From e474cbaea1fd35f860a9c5bc1468ef910c2553a8 Mon Sep 17 00:00:00 2001 From: Pavel Zwerschke Date: Tue, 4 Aug 2026 16:41:59 +0200 Subject: [PATCH] fix: Always skip `autoupdate-schedule = "never"` Both pixi scanners only compared `autoupdate-schedule` against the run's schedule when `--schedule` was passed, so an unfiltered run ignored the setting entirely and opened pull requests for repositories that had opted out. Treat `never` as an unconditional opt-out instead: it is honored with or without `--schedule`, while the remaining values keep selecting a cadence. --- docs/contents/built-in-updaters/pixi.md | 3 +- docs/contents/reference/cli.md | 4 +- quant_ranger/_impl/cli_options.py | 3 +- .../_impl/updaters/_pixi_update/_update.py | 14 ++++--- quant_ranger/_impl/updaters/_pixi_version.py | 6 +++ tests/test_pixi_update.py | 41 +++++++++++++++++++ tests/test_pixi_version.py | 32 +++++++++++++++ 7 files changed, 94 insertions(+), 9 deletions(-) diff --git a/docs/contents/built-in-updaters/pixi.md b/docs/contents/built-in-updaters/pixi.md index a9ad114..46aa490 100644 --- a/docs/contents/built-in-updaters/pixi.md +++ b/docs/contents/built-in-updaters/pixi.md @@ -174,7 +174,8 @@ quant-ranger update \ ``` `--schedule weekly` runs only configurations set to `weekly`. -Omitting the option is a manual, unfiltered run and includes configurations set to `never`. +Omitting the option is a manual, unfiltered run over every other cadence. +Configurations set to `never` are always skipped, with or without the option. Other updaters do not accept this option. Control their cadence by choosing when the workflow calls them. diff --git a/docs/contents/reference/cli.md b/docs/contents/reference/cli.md index 5a9d88c..eca5e51 100644 --- a/docs/contents/reference/cli.md +++ b/docs/contents/reference/cli.md @@ -130,7 +130,7 @@ $ quant-ranger update pixi-version [OPTIONS] **Options**: -* `--schedule [weekly|monthly|quarterly]`: Filter to update configurations whose schedule matches this value. Omit to include all configurations, including `never`. +* `--schedule [weekly|monthly|quarterly]`: Filter to update configurations whose schedule matches this value. Omit to include every cadence. Configurations set to `never` are always excluded. * `--pixi-version TEXT`: Update to this pixi version (e.g. v0.70.0) instead of resolving the latest release from GitHub. * `--setup-pixi-marker TEXT`: Only update workflow files containing this marker, e.g. when using a fork of setup-pixi. [default: (prefix-dev/setup-pixi)] * `--help`: Show this message and exit. @@ -147,7 +147,7 @@ $ quant-ranger update pixi-update [OPTIONS] **Options**: -* `--schedule [weekly|monthly|quarterly]`: Filter to update configurations whose schedule matches this value. Omit to include all configurations, including `never`. +* `--schedule [weekly|monthly|quarterly]`: Filter to update configurations whose schedule matches this value. Omit to include every cadence. Configurations set to `never` are always excluded. * `--help`: Show this message and exit. ### `quant-ranger update node-dependency-cooldown` diff --git a/quant_ranger/_impl/cli_options.py b/quant_ranger/_impl/cli_options.py index d81c4ef..9d75ad9 100644 --- a/quant_ranger/_impl/cli_options.py +++ b/quant_ranger/_impl/cli_options.py @@ -38,7 +38,8 @@ def resolve(self, site_config: SiteConfig) -> OptionInfo | ArgumentInfo: "--schedule", help=( "Filter to update configurations whose schedule matches this value. " - "Omit to include all configurations, including `never`." + "Omit to include every cadence. Configurations set to `never` are " + "always excluded." ), ), ] diff --git a/quant_ranger/_impl/updaters/_pixi_update/_update.py b/quant_ranger/_impl/updaters/_pixi_update/_update.py index 27d6574..9797a3b 100644 --- a/quant_ranger/_impl/updaters/_pixi_update/_update.py +++ b/quant_ranger/_impl/updaters/_pixi_update/_update.py @@ -179,13 +179,17 @@ def scan_repository( if manifest is None: continue - if ( - self.schedule is not None - and self.schedule != manifest.tool.update.autoupdate_schedule - ): + configured_schedule = manifest.tool.update.autoupdate_schedule + # `never` opts out of autoupdates entirely, so it is honored even in + # an unfiltered run; the other values only select a cadence. + if configured_schedule == "never": + context.logger.debug(f"Skipping {path}: configured schedule is never.") + continue + + if self.schedule is not None and self.schedule != configured_schedule: context.logger.debug( f"Skipping {path}: configured schedule is " - f"{manifest.tool.update.autoupdate_schedule}; current scheduled run is {self.schedule}." + f"{configured_schedule}; current scheduled run is {self.schedule}." ) continue diff --git a/quant_ranger/_impl/updaters/_pixi_version.py b/quant_ranger/_impl/updaters/_pixi_version.py index c11f791..11a1354 100644 --- a/quant_ranger/_impl/updaters/_pixi_version.py +++ b/quant_ranger/_impl/updaters/_pixi_version.py @@ -108,6 +108,12 @@ def scan_repository( return [] config = self._read_config(repository_ref, context) + # `never` opts out of autoupdates entirely, so it is honored even in an + # unfiltered run; the other values only select a cadence. + if config.autoupdate_schedule == "never": + context.logger.debug("Skipping repository: configured schedule is never.") + return [] + if self.schedule is not None and config.autoupdate_schedule != self.schedule: context.logger.debug( f"Skipping repository: configured schedule is " diff --git a/tests/test_pixi_update.py b/tests/test_pixi_update.py index 01bc818..d2a58d9 100644 --- a/tests/test_pixi_update.py +++ b/tests/test_pixi_update.py @@ -1305,6 +1305,47 @@ def test_pixi_lockfile_scanner_filters_schedule_mismatches() -> None: ) +def test_pixi_lockfile_scanner_skips_never_without_schedule_filter() -> None: + repository = RepositoryRef(owner="quantco", name="with-lockfiles", branch="main") + logger = RecordingLogger() + github_client = FakeGitHubClient( + files={ + "quantco/with-lockfiles": [ + "pixi.lock", + "subproject/pixi.lock", + ], + }, + file_contents={ + "pixi.toml": """ + [tool.update] + autoupdate-schedule = "never" + """, + "subproject/pixi.toml": """ + [tool.update] + autoupdate-schedule = "weekly" + """, + }, + ) + + items = PixiUpdateUpdater(PixiUpdateOptions()).scanner.scan_all( + [repository], + RunContext( + site_config=SiteConfig(), + github_client=cast(GitHubClient, github_client), + logger=logger, + ), + ) + + assert [ + (item.repository_ref, item.path.as_posix()) for item in items.update_items + ] == [(repository, "subproject/pixi.lock")] + assert logger.logged( + LogLevel.DEBUG, + "[quantco/with-lockfiles@main] Skipping pixi.lock: configured schedule " + "is never.", + ) + + def test_pixi_lockfile_scanner_skips_missing_manifest() -> None: repository = RepositoryRef(owner="quantco", name="with-lockfile", branch="main") logger = RecordingLogger() diff --git a/tests/test_pixi_version.py b/tests/test_pixi_version.py index eb00339..2d0b618 100644 --- a/tests/test_pixi_version.py +++ b/tests/test_pixi_version.py @@ -368,6 +368,38 @@ def test_pixi_repository_scanner_filters_schedule_mismatches() -> None: ) +def test_pixi_repository_scanner_skips_never_without_schedule_filter() -> None: + repository = RepositoryRef(owner="quantco", name="with-lockfile", branch="main") + logger = RecordingLogger() + github_client = FakeGitHubClient( + files={"quantco/with-lockfile": ["pixi.lock"]}, + file_contents={ + "pixi.toml": """ + [tool.pixi-version-updater] + autoupdate-schedule = "never" + """, + }, + ) + + items = PixiVersionUpdater( + PixiVersionOptions(setup_pixi_marker="prefix-dev/setup-pixi") + ).scanner.scan_all( + [repository], + RunContext( + site_config=SiteConfig(), + github_client=cast(GitHubClient, github_client), + logger=logger, + ), + ) + + assert items.update_items == () + assert logger.logged( + LogLevel.DEBUG, + "[quantco/with-lockfile@main] Skipping repository: configured schedule " + "is never.", + ) + + def test_pixi_repository_scanner_reads_scheduled_config_once_per_repository() -> None: repository = RepositoryRef(owner="quantco", name="with-lockfiles", branch="main") github_client = FakeGitHubClient(