Skip to content

auto-detect format in ci#146

Open
Kilo59 wants to merge 13 commits intomainfrom
auto-detect-ci
Open

auto-detect format in ci#146
Kilo59 wants to merge 13 commits intomainfrom
auto-detect-ci

Conversation

@Kilo59
Copy link
Copy Markdown
Owner

@Kilo59 Kilo59 commented Apr 3, 2026

Summary by Sourcery

Auto-detect and propagate output format and other CLI defaults (branch, path, exclude, pre-commit) through the configuration, CLI, and core execution paths, simplifying argument handling and CI integration.

New Features:

  • Auto-detect the output format from the CI environment (GitHub, GitLab, etc.) when not explicitly provided via CLI or config.
  • Add support for configuring the output format in [tool.ruff-sync] config and wiring it through to formatters and validation.

Bug Fixes:

  • Ensure pre-commit sync configuration and execution use a simple boolean default instead of MISSING sentinels, preventing unintended serialization and behavior differences.
  • Normalize branch, path, and exclude defaults in the CLI layer so downstream core logic receives concrete values, avoiding divergent default resolution.

Enhancements:

  • Introduce a typed CLIArguments protocol to clarify and tighten arg resolution between argparse, config, and core logic.
  • Refine config serialization to omit default values for exclude, branch, path, and pre-commit, producing cleaner pyproject.toml output.
  • Improve CI output format validation and add tests to cover CLI/config/env precedence and end-to-end resolution.
  • Simplify upstream URL resolution by resolving branch/path earlier and passing fully resolved URLs to core.
  • Remove the core-level default resolver helper in favor of using resolved values directly.
  • Annotate logging formatter override and clean up typing workarounds in CLI and tasks utilities.
  • Extend resolve_defaults to include output_format as part of the shared default resolution contract.

Build:

  • Bump project version to 0.1.5.dev1.

CI:

  • Update pre-commit Ruff hook version to v0.15.9.

Documentation:

  • Document the extended --output-format options and CI auto-detection in the Ruff Sync usage skill docs.

Tests:

  • Add comprehensive tests for output format resolution across CLI, config, and CI environment, including end-to-end verification via main().
  • Update serialization, formatter, constants, and basic CLI tests to reflect new defaults and behavior for exclude, branch, path, pre-commit, and output_format.
  • Loosen test linting rules to allow necessary casts in tests and equality checks for RuffConfigFileName.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Apr 3, 2026

Reviewer's Guide

Centralizes default resolution of CLI arguments (especially output format, branch, path, exclude, pre-commit) and adds CI-aware auto-detection and propagation of output format across the CLI, core execution, serialization, and tests, while cleaning up MISSING sentinels and minor typing/logging improvements.

Sequence diagram for CLI main with CI-aware output format resolution

sequenceDiagram
    actor User
    participant CLI as cli_main
    participant Parser as argparse_ArgumentParser
    participant Cfg as get_config
    participant Resolver as _resolve_args
    participant PCResolver as _resolve_pre_commit
    participant CI as _detect_ci_provider
    participant Core as core_check_or_pull
    participant FmtFactory as get_formatter
    participant Formatter as ResultFormatter

    User->>CLI: invoke ruff_sync_cli
    CLI->>Parser: parse_args()
    Parser-->>CLI: args: CLIArguments

    CLI->>Cfg: get_config(initial_to)
    Cfg-->>CLI: config: Config

    CLI->>Resolver: _resolve_args(args, config, initial_to)
    Resolver->>Resolver: _resolve_upstream
    Resolver->>Resolver: _resolve_to
    Resolver->>Resolver: _resolve_exclude
    Resolver->>Resolver: _resolve_branch
    Resolver->>Resolver: _resolve_path
    Resolver->>Resolver: _resolve_output_format

    alt output_format from CLI
        Resolver-->>Resolver: return CLI args.output_format
    else output_format from config
        Resolver-->>Resolver: parse config.output_format to OutputFormat
    else auto detect in CI
        Resolver->>CI: _detect_ci_provider()
        CI-->>Resolver: provider or null
        alt provider detected
            Resolver-->>Resolver: map provider to OutputFormat
        else no provider
            Resolver-->>Resolver: use OutputFormat.TEXT
        end
    end

    Resolver-->>CLI: ResolvedArgs (includes output_format)

    CLI->>PCResolver: _resolve_pre_commit(args, config)
    PCResolver-->>CLI: pre_commit bool

    CLI->>CLI: build Arguments with resolved_upstream, branch, path, exclude, pre_commit, output_format

    CLI->>Core: check or pull(Arguments)
    Core->>FmtFactory: get_formatter(args.output_format)
    FmtFactory-->>Core: Formatter

    Core->>Formatter: note("Checking or syncing...")
    Core->>Formatter: success or error messages
    Core-->>CLI: exit_code
    CLI-->>User: process exit_code
Loading

Class diagram for updated CLI and core argument resolution

classDiagram
    class OutputFormat {
        <<enum>>
        TEXT
        JSON
        GITHUB
        GITLAB
        SARIF
    }

    class CIProvider {
        <<enum>>
        GITHUB
        GITLAB
        SARIF
    }

    class Arguments {
        <<NamedTuple>>
        +str command
        +tuple~URL~ upstream
        +Path to
        +Iterable~str~ exclude
        +int verbose
        +str branch
        +str path
        +bool semantic
        +bool diff
        +bool init
        +bool pre_commit
        +bool save
        +OutputFormat output_format
    }

    class ResolvedArgs {
        <<NamedTuple>>
        +tuple~URL~ upstream
        +Path to
        +Iterable~str~ exclude
        +str branch
        +str path
        +OutputFormat output_format
    }

    class CLIArguments {
        <<protocol>>
        +str command
        +list~URL~ upstream
        +str to
        +str source
        +list~str~ exclude
        +int verbose
        +str branch
        +str path
        +bool pre_commit
        +OutputFormat output_format
        +bool init
        +bool save
        +bool semantic
        +bool diff
    }

    class Config {
        <<TypedDict>>
        +list~str~ exclude
        +str branch
        +str path
        +bool pre_commit_version_sync
        +str output_format
        +str to
        +str source
    }

    class ResultFormatter {
        <<interface>>
        +note(message str) void
        +success(message str) void
        +error(message str) void
    }

    class cli_module {
        +get_config(source Path) Config
        +_resolve_upstream(args CLIArguments, config Config) tuple~URL~
        +_resolve_exclude(args CLIArguments, config Config) Iterable~str~
        +_resolve_branch(args CLIArguments, config Config) str
        +_resolve_path(args CLIArguments, config Config) str
        +_resolve_output_format(args CLIArguments, config Config) OutputFormat
        +_resolve_to(args CLIArguments, config Config, initial_to Path) Path
        +_resolve_args(args CLIArguments, config Config, initial_to Path) ResolvedArgs
        +_resolve_pre_commit(args CLIArguments, config Config) bool
        +_detect_ci_provider() CIProvider
        +main() int
    }

    class core_module {
        +check(args Arguments) int
        +pull(args Arguments) int
        +serialize_ruff_sync_config(doc TOMLDocument, args Arguments) void
    }

    class constants_module {
        +resolve_defaults(branch str, path str, exclude Iterable~str~, output_format OutputFormat) tuple
    }

    cli_module --> CLIArguments
    cli_module --> ResolvedArgs
    cli_module --> Arguments
    cli_module --> Config
    cli_module --> OutputFormat
    cli_module --> CIProvider

    core_module --> Arguments
    core_module --> ResultFormatter
    core_module --> OutputFormat

    constants_module --> OutputFormat
    constants_module --> Arguments

    Arguments o--> OutputFormat
    ResolvedArgs o--> OutputFormat
    Config o--> OutputFormat
    Arguments o--> Config
    Arguments o--> ResolvedArgs
    core_module ..> cli_module
    core_module ..> constants_module
Loading

File-Level Changes

Change Details Files
Refactor CLI argument resolution to use concrete defaults, a typed protocol, and shared helpers, including CI-aware output-format detection and pre-commit flag resolution.
  • Changed Arguments and ResolvedArgs to use concrete defaults for exclude, branch, path, and pre_commit instead of a MISSING sentinel, and added output_format to ResolvedArgs.
  • Introduced a CLIArguments Protocol to type parsed argparse results and updated resolver helpers (_resolve_upstream, _resolve_exclude, _resolve_branch, _resolve_path, _resolve_to) to use Config and CLIArguments instead of Any/Mapping.
  • Added _resolve_output_format to select the output format with precedence CLI > config > CI auto-detection > text default, and wired it into _resolve_args.
  • Added _resolve_pre_commit helper to resolve the pre-commit flag from CLI or config and removed the inline multi-key lookup logic from main.
  • Updated _get_cli_parser to make --output-format default to None and adjusted the help text to document CI auto-detection.
  • Simplified main() to use _resolve_args and _resolve_pre_commit, resolve upstream URLs once with the resolved branch/path, and pass the resolved output_format directly into Arguments.
  • Annotated ColorFormatter.format with @OverRide and removed outdated type ignore.
src/ruff_sync/cli.py
Propagate and consume the resolved output format and concrete defaults in core execution and config serialization instead of MISSING-based resolution.
  • Extended Config TypedDict to include an optional output_format string for config-driven format selection.
  • Removed the _resolve_defaults helper in core.py and switched _merge_multiple_upstreams to use args.branch/path/exclude directly, assuming they are already default-resolved by the CLI layer.
  • Updated check() and pull() to derive the formatter directly from args.output_format without additional normalization and stored the selected output_format in a local variable for clarity.
  • Changed serialize_ruff_sync_config to omit defaults by comparing against DEFAULT_EXCLUDE, DEFAULT_BRANCH, DEFAULT_PATH, and False for pre_commit, and to skip serializing pre-commit when it is at its default False value.
  • Simplified the pre-commit sync trigger in pull() to check args.pre_commit directly rather than comparing to MISSING.
src/ruff_sync/core.py
Extend shared default-resolution helper to handle output_format alongside branch, path, and exclude.
  • Updated resolve_defaults in constants.py to accept an optional output_format argument (with MISSING default) and return a 4-tuple (branch, path, exclude, output_format).
  • Ensured resolve_defaults normalizes MISSING output_format to OutputFormat.TEXT and kept existing normalization for branch, path, and exclude intact.
src/ruff_sync/constants.py
Update tests to reflect new defaults, output-format auto-detection, and simplified pre-commit/config behavior.
  • Adjusted serialization tests to use DEFAULT_EXCLUDE, DEFAULT_BRANCH, and path=None instead of MISSING, and to assert that default pre_commit=False does not serialize any pre-commit key.
  • Updated tests that previously relied on MISSING for exclude/branch/path (e.g., test_exclude_resolution_* and pull-related tests) to expect early default resolution at the CLI layer and boolean pre_commit flags.
  • Extended resolve_defaults tests to cover the added output_format return value and default behavior.
  • Added new tests for CI output-format resolution precedence and an end-to-end main() test that verifies output_format is auto-detected as GITHUB in a GitHub Actions-like environment.
  • Adjusted formatter-related tests to construct Arguments with DEFAULT_EXCLUDE instead of MISSING and updated equality tests to add type-ignore comments for comparison-overlap.
  • Updated ci-validation tests to use CLIArguments, Config, and to exercise _resolve_output_format directly.
tests/test_serialization.py
tests/test_basic.py
tests/test_constants.py
tests/test_ci_validation.py
tests/test_formatters.py
Refresh project metadata, docs, and tooling to reflect new output-format behavior and dependency versions.
  • Bumped project version in pyproject.toml from 0.1.4 to 0.1.5.dev1.
  • Expanded CLI usage skill documentation to describe new output formats (gitlab, sarif) and CI auto-detection semantics for --output-format.
  • Relaxed certain Ruff lint rules and added a banned typing.cast rule with a custom message in pyproject.toml, plus allowed casts in tests via TID251.
  • Updated pre-commit configuration to use a newer ruff-pre-commit hook version (v0.15.9).
  • Simplified tasks.release by removing unnecessary typing.cast usage for Invoke command results and replacing with direct stdout access plus type ignore annotations.
  • Updated uv.lock to capture dependency changes (details implicit in lockfile diff).
pyproject.toml
.agents/skills/ruff-sync-usage/SKILL.md
.pre-commit-config.yaml
tasks.py
uv.lock

Possibly linked issues

  • #feat: Auto-detect CI environment for output format: PR implements the requested CI-based output-format auto-detection (GitHub/GitLab), honoring explicit flags and updating argument resolution.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/ruff_sync/cli.py" line_range="417-419" />
<code_context>
+            LOGGER.warning(f"Unknown output format in config: {fmt_str}")
+
+    # Auto-detection
+    provider = _detect_ci_provider()
+    if provider:
+        LOGGER.info(f"🤖 Auto-detected CI environment: {provider}")
+        return provider
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Auto-detected CI provider is returned as an OutputFormat, which is likely a type/enum mismatch.

Here `provider` is typed as `CIProvider | None`, but the function returns `OutputFormat | MissingType`. Returning `provider` directly means callers like `resolve_defaults(..., output_format)` and `get_formatter(output_format)` may receive a `CIProvider` where an `OutputFormat` is expected, which can break comparisons/formatter selection unless `CIProvider` is explicitly compatible with `OutputFormat`. Please either map CI providers to an `OutputFormat` here, or adjust the types so that relationship is explicit and enforced.
</issue_to_address>

### Comment 2
<location path="tests/test_ci_validation.py" line_range="88-97" />
<code_context>
+@pytest.mark.parametrize(
</code_context>
<issue_to_address>
**suggestion (testing):** Add test cases for explicit `--output-format text` and config `output-format = "text"` to cover non-auto-detected TEXT resolution

The current parametrized test covers CLI/config overriding CI, CI auto-detection, and the default `MISSING → TEXT` fallback, but it misses two explicit TEXT paths:

1. Explicit CLI flag: when `--output-format text` is set (with or without CI env vars), `_resolve_output_format` should return `OutputFormat.TEXT` directly, not `MISSING`. Please add a parametrized case like:

```python
(
    {"GITHUB_ACTIONS": "true"},
    {"output_format": OutputFormat.TEXT},
    {},
    OutputFormat.TEXT,
),
```

2. Config-only TEXT: when `output-format = "text"` is set in config without CI env vars, it should also resolve to `OutputFormat.TEXT`. For example:

```python
(
    {},
    {},
    {"output-format": "text"},
    OutputFormat.TEXT,
),
```

These will verify TEXT is correctly handled when chosen explicitly, not only via the default fallback.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +417 to +419
provider = _detect_ci_provider()
if provider:
LOGGER.info(f"🤖 Auto-detected CI environment: {provider}")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Auto-detected CI provider is returned as an OutputFormat, which is likely a type/enum mismatch.

Here provider is typed as CIProvider | None, but the function returns OutputFormat | MissingType. Returning provider directly means callers like resolve_defaults(..., output_format) and get_formatter(output_format) may receive a CIProvider where an OutputFormat is expected, which can break comparisons/formatter selection unless CIProvider is explicitly compatible with OutputFormat. Please either map CI providers to an OutputFormat here, or adjust the types so that relationship is explicit and enforced.

Comment on lines +88 to +97
@pytest.mark.parametrize(
("env_vars", "cli_args", "config", "expected"),
[
# CLI takes precedence
(
{"GITHUB_ACTIONS": "true"},
{"output_format": OutputFormat.JSON},
{},
OutputFormat.JSON,
),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add test cases for explicit --output-format text and config output-format = "text" to cover non-auto-detected TEXT resolution

The current parametrized test covers CLI/config overriding CI, CI auto-detection, and the default MISSING → TEXT fallback, but it misses two explicit TEXT paths:

  1. Explicit CLI flag: when --output-format text is set (with or without CI env vars), _resolve_output_format should return OutputFormat.TEXT directly, not MISSING. Please add a parametrized case like:
(
    {"GITHUB_ACTIONS": "true"},
    {"output_format": OutputFormat.TEXT},
    {},
    OutputFormat.TEXT,
),
  1. Config-only TEXT: when output-format = "text" is set in config without CI env vars, it should also resolve to OutputFormat.TEXT. For example:
(
    {},
    {},
    {"output-format": "text"},
    OutputFormat.TEXT,
),

These will verify TEXT is correctly handled when chosen explicitly, not only via the default fallback.

@Kilo59 Kilo59 self-assigned this Apr 3, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 3, 2026

Codecov Report

❌ Patch coverage is 92.22222% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.94%. Comparing base (9b16e11) to head (12b46d6).

Files with missing lines Patch % Lines
src/ruff_sync/cli.py 90.90% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #146      +/-   ##
==========================================
+ Coverage   93.75%   93.94%   +0.18%     
==========================================
  Files           6        6              
  Lines        1121     1156      +35     
==========================================
+ Hits         1051     1086      +35     
  Misses         70       70              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 4, 2026

╒═══════════════╤═════════════════╤═════════════════╤══════════════╤════════════╕
│ File          │ Maintainabili   │ Lines of Code   │ Cyclomatic   │ Unique     │
│               │ ty Index        │                 │ Complexity   │ Operands   │
╞═══════════════╪═════════════════╪═════════════════╪══════════════╪════════════╡
│ tasks.py      │ 48.5369 ->      │ 234 -> 234      │ 41 -> 41     │ 11 -> 11   │
│               │ 49.2963         │                 │              │            │
├───────────────┼─────────────────┼─────────────────┼──────────────┼────────────┤
│ tests/test_ba │ 20.8005 ->      │ 997 -> 989      │ 59 -> 58     │ 14 -> 13   │
│ sic.py        │ 21.0018         │                 │              │            │
├───────────────┼─────────────────┼─────────────────┼──────────────┼────────────┤
│ tests/test_ci │ 75.6652 ->      │ 85 -> 209       │ 3 -> 6       │ 2 -> 4     │
│ _validation.p │ 66.6466         │                 │              │            │
│ y             │                 │                 │              │            │
├───────────────┼─────────────────┼─────────────────┼──────────────┼────────────┤
│ tests/test_co │ 70.57 ->        │ 62 -> 63        │ 4 -> 4       │ 2 -> 2     │
│ nstants.py    │ 70.6767         │                 │              │            │
├───────────────┼─────────────────┼─────────────────┼──────────────┼────────────┤
│ tests/test_se │ 41.4272 ->      │ 398 -> 381      │ 18 -> 17     │ 6 -> 6     │
│ rialization.p │ 42.3771         │                 │              │            │
│ y             │                 │                 │              │            │
╘═══════════════╧═════════════════╧═════════════════╧══════════════╧════════════╛

@Kilo59
Copy link
Copy Markdown
Owner Author

Kilo59 commented Apr 4, 2026

@sourcery-ai review

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • Now that cli.main resolves branch, path, and exclude defaults up front and _merge_multiple_upstreams uses args.branch/path/exclude directly, consider simplifying constants.resolve_defaults (or removing its new output_format parameter) if it is no longer used as a central source of truth.
  • In the test_resolve_defaults_* tests you assert output_format == "text"; if OutputFormat is an enum, it would be more robust to assert against OutputFormat.TEXT (or output_format.value) to avoid relying on implicit enum-to-string equality.
  • When logging an unknown output_format in _resolve_output_format, consider including the valid OutputFormat values in the warning message to make misconfigurations easier to diagnose.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Now that `cli.main` resolves `branch`, `path`, and `exclude` defaults up front and `_merge_multiple_upstreams` uses `args.branch/path/exclude` directly, consider simplifying `constants.resolve_defaults` (or removing its new `output_format` parameter) if it is no longer used as a central source of truth.
- In the `test_resolve_defaults_*` tests you assert `output_format == "text"`; if `OutputFormat` is an enum, it would be more robust to assert against `OutputFormat.TEXT` (or `output_format.value`) to avoid relying on implicit enum-to-string equality.
- When logging an unknown `output_format` in `_resolve_output_format`, consider including the valid `OutputFormat` values in the warning message to make misconfigurations easier to diagnose.

## Individual Comments

### Comment 1
<location path="tests/test_ci_validation.py" line_range="127-111" />
<code_context>
+            {},
+            OutputFormat.TEXT,
+        ),
+        # Unknown config format falls back to auto-detect/default (GitHub in this env)
+        (
+            {"GITHUB_ACTIONS": "true"},
+            {},
+            {"output_format": "invalid"},
+            OutputFormat.GITHUB,
+        ),
+        # Explicit CLI TEXT (with CI env)
</code_context>
<issue_to_address>
**suggestion (testing):** Add an assertion that an invalid config output_format emits a warning log

This parametrized case verifies the fallback to GitHub for an invalid `output_format`, but it doesn't assert the new logging behaviour in `_resolve_output_format`. Please use `caplog` here to assert that the expected warning (e.g. containing `Unknown output format in config`) is emitted, so changes to logging are caught by the test.

Suggested implementation:

```python
        # Unknown config format falls back to auto-detect/default (GitHub in this env)
        # and should emit a warning log about the unknown output_format

```

To fully implement the requested assertion using `caplog`, you will also need to update the parametrized test function that uses these cases:

1. **Inject `caplog` into the test function signature**  
   If the test currently looks roughly like:
   ```python
   @pytest.mark.parametrize(
       "env, cli_config, file_config, expected_output_format",
       [...],
   )
   def test_resolve_output_format(env, cli_config, file_config, expected_output_format, monkeypatch):
       ...
   ```
   change the signature to accept `caplog`:
   ```python
   def test_resolve_output_format(env, cli_config, file_config, expected_output_format, monkeypatch, caplog):
   ```

2. **Add a conditional assertion for the invalid `output_format` case**  
   After calling `_resolve_output_format` (or whatever helper the test currently calls) and asserting `expected_output_format`, add a conditional block that checks for the invalid config case and asserts on the log:
   ```python
   with caplog.at_level(logging.WARNING):
       result = _resolve_output_format(env, cli_config, file_config)
       assert result is expected_output_format

   # Only the invalid config case should produce the warning
   if file_config.get("output_format") == "invalid":
       assert "Unknown output format in config" in caplog.text
   else:
       # Optionally assert that no warning was emitted in other cases
       assert "Unknown output format in config" not in caplog.text
   ```

3. **Ensure logging is imported / configured**  
   At the top of `tests/test_ci_validation.py`, ensure:
   ```python
   import logging
   ```
   is present so `logging.WARNING` is available.

These changes will make the parametrized case that uses `{"output_format": "invalid"}` verify not only the fallback to `OutputFormat.GITHUB` but also that `_resolve_output_format` emits the expected warning log.
</issue_to_address>

### Comment 2
<location path="tests/test_constants.py" line_range="22-23" />
<code_context>

 def test_resolve_defaults_passthrough():
     """Verify that non-MISSING values are passed through unchanged."""
-    branch, path, exclude = resolve_defaults("develop", "src", ["rule1"])
+    branch, path, exclude, _ = resolve_defaults("develop", "src", ["rule1"])

     assert branch == "develop"
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test that explicitly verifies resolve_defaults preserves a non-MISSING output_format

Currently the tests only cover the default `TEXT` case and don’t assert the behaviour when a non-MISSING `output_format` is provided. Please add a test that calls something like `resolve_defaults(MISSING, MISSING, MISSING, OutputFormat.GITLAB)` and asserts that the returned `output_format` remains `OutputFormat.GITLAB`, so this contract is explicitly covered by tests.

Suggested implementation:

```python
def test_resolve_defaults_passthrough():
    """Verify that non-MISSING values are passed through unchanged."""
    branch, path, exclude, _ = resolve_defaults("develop", "src", ["rule1"])

    assert branch == "develop"
    assert path == "src"


def test_resolve_defaults_output_format_passthrough():
    """Verify that a non-MISSING output_format is passed through unchanged."""
    branch, path, exclude, output_format = resolve_defaults(
        MISSING,
        MISSING,
        MISSING,
        OutputFormat.GITLAB,
    )

    assert branch == DEFAULT_BRANCH
    assert path is None  # DEFAULT_PATH ("") is normalized to None
    assert exclude == DEFAULT_EXCLUDE
    assert output_format == OutputFormat.GITLAB


def test_resolve_defaults_mixed():

```

If `OutputFormat` is not yet imported in `tests/test_constants.py`, you will also need to add an import at the top of the file, for example:
- `from <your_module>.constants import OutputFormat` (or the appropriate module path where `OutputFormat` is defined).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

{"GITHUB_ACTIONS": "true"},
{},
{},
OutputFormat.GITHUB,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add an assertion that an invalid config output_format emits a warning log

This parametrized case verifies the fallback to GitHub for an invalid output_format, but it doesn't assert the new logging behaviour in _resolve_output_format. Please use caplog here to assert that the expected warning (e.g. containing Unknown output format in config) is emitted, so changes to logging are caught by the test.

Suggested implementation:

        # Unknown config format falls back to auto-detect/default (GitHub in this env)
        # and should emit a warning log about the unknown output_format

To fully implement the requested assertion using caplog, you will also need to update the parametrized test function that uses these cases:

  1. Inject caplog into the test function signature
    If the test currently looks roughly like:

    @pytest.mark.parametrize(
        "env, cli_config, file_config, expected_output_format",
        [...],
    )
    def test_resolve_output_format(env, cli_config, file_config, expected_output_format, monkeypatch):
        ...

    change the signature to accept caplog:

    def test_resolve_output_format(env, cli_config, file_config, expected_output_format, monkeypatch, caplog):
  2. Add a conditional assertion for the invalid output_format case
    After calling _resolve_output_format (or whatever helper the test currently calls) and asserting expected_output_format, add a conditional block that checks for the invalid config case and asserts on the log:

    with caplog.at_level(logging.WARNING):
        result = _resolve_output_format(env, cli_config, file_config)
        assert result is expected_output_format
    
    # Only the invalid config case should produce the warning
    if file_config.get("output_format") == "invalid":
        assert "Unknown output format in config" in caplog.text
    else:
        # Optionally assert that no warning was emitted in other cases
        assert "Unknown output format in config" not in caplog.text
  3. Ensure logging is imported / configured
    At the top of tests/test_ci_validation.py, ensure:

    import logging

    is present so logging.WARNING is available.

These changes will make the parametrized case that uses {"output_format": "invalid"} verify not only the fallback to OutputFormat.GITHUB but also that _resolve_output_format emits the expected warning log.

Comment on lines -22 to 23
branch, path, exclude = resolve_defaults("develop", "src", ["rule1"])
branch, path, exclude, _ = resolve_defaults("develop", "src", ["rule1"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add a test that explicitly verifies resolve_defaults preserves a non-MISSING output_format

Currently the tests only cover the default TEXT case and don’t assert the behaviour when a non-MISSING output_format is provided. Please add a test that calls something like resolve_defaults(MISSING, MISSING, MISSING, OutputFormat.GITLAB) and asserts that the returned output_format remains OutputFormat.GITLAB, so this contract is explicitly covered by tests.

Suggested implementation:

def test_resolve_defaults_passthrough():
    """Verify that non-MISSING values are passed through unchanged."""
    branch, path, exclude, _ = resolve_defaults("develop", "src", ["rule1"])

    assert branch == "develop"
    assert path == "src"


def test_resolve_defaults_output_format_passthrough():
    """Verify that a non-MISSING output_format is passed through unchanged."""
    branch, path, exclude, output_format = resolve_defaults(
        MISSING,
        MISSING,
        MISSING,
        OutputFormat.GITLAB,
    )

    assert branch == DEFAULT_BRANCH
    assert path is None  # DEFAULT_PATH ("") is normalized to None
    assert exclude == DEFAULT_EXCLUDE
    assert output_format == OutputFormat.GITLAB


def test_resolve_defaults_mixed():

If OutputFormat is not yet imported in tests/test_constants.py, you will also need to add an import at the top of the file, for example:

  • from <your_module>.constants import OutputFormat (or the appropriate module path where OutputFormat is defined).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant