Skip to content

[codex] Fix cross nightly toolchain resolution#255

Merged
leynos merged 8 commits intomainfrom
fix/cross-nightly-arg
Apr 18, 2026
Merged

[codex] Fix cross nightly toolchain resolution#255
leynos merged 8 commits intomainfrom
fix/cross-nightly-arg

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Apr 17, 2026

Summary

  • remove the explicit +toolchain override from cross build in rust-build-release
  • drop the cross-only toolchain sanitization/install path that only existed to support that CLI override
  • update tests to assert that cross relies on the repo-declared toolchain instead of injecting a +... argument

Why

When a target repository already pins a dated nightly in rust-toolchain.toml, rustup exports RUSTUP_TOOLCHAIN=nightly-YYYY-MM-DD. Passing cross +nightly-YYYY-MM-DD build ... at the same time causes cross/rustup to combine both sources into an invalid toolchain name with the date repeated, which rustup rejects.

Impact

cross now resolves its toolchain solely from RUSTUP_TOOLCHAIN or the repository's rust-toolchain.toml, while cargo keeps its existing explicit toolchain override behavior.

Validation

  • make check-fmt
  • make typecheck
  • make lint
  • make test
  • focused rust-build-release pytest run covering the command shape regression

Summary by Sourcery

Rely on the repository’s or rustup’s toolchain resolution for cross builds instead of injecting an explicit toolchain override, and adjust tests accordingly.

Bug Fixes:

  • Prevent invalid toolchain names when invoking cross by no longer passing an explicit +toolchain override.

Enhancements:

  • Simplify cross decision logic by removing special toolchain sanitization and installation for cross invocations.

Tests:

  • Update and extend rust-build-release tests to assert that cross build commands omit +toolchain arguments and rely on the repo-declared toolchain.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 17, 2026

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Cross Nightly Toolchain Resolution Fix

This PR removes the action’s practice of injecting a "+toolchain" CLI override into cross invocations to avoid conflicts with rustup’s environment-based resolution (RUSTUP_TOOLCHAIN=nightly-YYYY-MM-DD) and simplifies toolchain handling for cross builds.

Root cause

  • The action previously sanitised and injected a "+..." toolchain spec into cross commands. When a repository pins a dated nightly in rust-toolchain.toml, rustup exports RUSTUP_TOOLCHAIN=nightly-YYYY-MM-DD; concurrently invoking cross +nightly-YYYY-MM-DD could produce an invalid duplicated-date toolchain name which rustup rejects.

Solution

  • Stop injecting explicit "+toolchain" arguments into cross commands; cross now resolves its toolchain from RUSTUP_TOOLCHAIN or the repository’s rust-toolchain.toml.
  • When an explicit action toolchain (RBR_TOOLCHAIN) is provided, main() sets RUSTUP_TOOLCHAIN by applying with_env(RUSTUP_TOOLCHAIN=<resolved_toolchain>) to the constructed command rather than passing + on the CLI.
  • Remove cross-only triple/channel sanitisation and the install/fallback path that existed solely to support CLI toolchain overrides.
  • Simplify toolchain resolution and cross decision plumbing:
    • _resolve_toolchain now returns only the resolved toolchain string.
    • _decide_cross_usage no longer computes or returns a cross_toolchain_spec.
    • _build_cross_command no longer prepends a "+toolchain" argument.
  • Add a typing-only _SupportsEnvFormulate protocol and adjust the command wrapper so with_env preserves display-name behaviour.

Key code changes

  • .github/actions/rust-build-release/src/main.py
    • Deleted triple/channel sanitisation helpers and removed cross_toolchain_spec from _CrossDecision.
    • Simplified _resolve_toolchain and _decide_cross_usage signatures/behaviour.
    • _build_cross_command stops injecting "+toolchain"; explicit RBR_TOOLCHAIN is exported via command environment using with_env.
    • Added _SupportsEnvFormulate protocol and refined _CommandWrapper.with_env.
  • Tests and test helpers
    • .github/actions/rust-build-release/tests/conftest.py: _DummyCommand gained env/with_env; CrossDecision test protocol adapted; fixtures updated to the new _resolve_toolchain contract.
    • .github/actions/rust-build-release/tests/rust_build_release_test_helpers.py: added assert_no_toolchain_override(parts).
    • .github/actions/rust-build-release/tests/test_manifest_path.py: merged duplicated tests into a single parametrised pytest (covering explicit-override and no-override cases), and added assertions that cross commands contain no "+..." override and that RUSTUP_TOOLCHAIN is exported only when an explicit toolchain is supplied.
    • .github/actions/rust-build-release/tests/test_features.py and test_target_install.py: updated to assert no "+toolchain" in cross invocations and appropriate use of RUSTUP_TOOLCHAIN.
    • .github/actions/rust-build-release/tests/test_toolchain_sanitize.py: removed obsolete sanitisation test that is no longer relevant.
  • Commit history: tests consolidated and updated in a test-focused commit ("test: cover repo nightly cross main flow"); main functional changes implemented as described.

Behavioural impact

  • cross: no longer receives CLI "+toolchain" overrides from the action; it uses RUSTUP_TOOLCHAIN or rust-toolchain.toml for toolchain selection.
  • cargo: retains explicit "+toolchain" override behaviour where still used.
  • Prevents the failure mode where dated-nightly environment vars combined with injected CLI overrides produced invalid toolchain names.

Validation

  • Formatting, typecheck, lint and full test suite executed on the branch.
  • Focused pytest regression coverage added to assert cross command composition omits "+toolchain" overrides and to cover repo-declared dated-nightly scenarios.

Documentation / Execplans

  • No new execplan, ADR, RFC or external design document is referenced or added by this PR.

Walkthrough

Remove target-triple sanitisation and channel-derivation logic; stop injecting +toolchain into cross invocations and apply explicit toolchains via the command environment (RUSTUP_TOOLCHAIN) when an explicit override is provided.

Changes

Cohort / File(s) Summary
Implementation refactor
\.github/actions/rust-build-release/src/main.py
Add a typing-only protocol for commands supporting with_env; remove triple-component matching and channel-stripping helpers; simplify _resolve_toolchain() and _decide_cross_usage(); drop cross_toolchain_spec and stop passing +toolchain args into cross, applying toolchains via command environment instead.
Test fixtures & doubles
\.github/actions/rust-build-release/tests/conftest.py, \.github/actions/rust-build-release/tests/rust_build_release_test_helpers.py
Extend _DummyCommand with env and with_env(...) to model environment composition; add assert_no_toolchain_override(parts) helper; update test harnesses to mock _resolve_toolchain() returning a single str.
Test assertions & scenarios
\.github/actions/rust-build-release/tests/test_features.py, \.github/actions/rust-build-release/tests/test_manifest_path.py, \.github/actions/rust-build-release/tests/test_target_install.py
Assert cross commands contain no +... toolchain override segments; verify RUSTUP_TOOLCHAIN is set in command env only when an explicit toolchain= override is provided; adjust mocks/fixtures to new resolver signature.
Test cleanup
\.github/actions/rust-build-release/tests/test_toolchain_sanitize.py
Remove test_toolchain_channel_strips_host_triple() and unused ModuleType import; update module docstring to reflect regression coverage for repo-declared toolchains and cross builds.

Sequence Diagram(s)

sequenceDiagram
    participant Main as Main (action)
    participant Env as Environment
    participant Cross as cross CLI
    participant Rustup as rustup

    Main->>Main: determine toolchain (repo / override)
    alt explicit RBR_TOOLCHAIN provided
        Main->>Env: set RUSTUP_TOOLCHAIN=<resolved_toolchain>
        Main->>Cross: invoke `cross build` (no +toolchain arg)
        Cross->>Rustup: consult RUSTUP_TOOLCHAIN from env
    else no explicit override
        Main->>Cross: invoke `cross build` (no +toolchain arg)
        Cross->>Rustup: use default rustup toolchain
    end
Loading

Poem

✨ Strip the triples, cut the frill,
Run cross clean, obey the will,
Drop the plus, let commands be light,
Export the toolchain when it's right,
Build swift, build true — release tonight. 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Testing ⚠️ Warning Integration tests verify end-to-end with_env() functionality, but critical unit tests for _CommandWrapper.with_env() and _DummyCommand.with_env() methods, including error handling and environment merging logic, are missing. Add unit tests for _CommandWrapper.with_env() success/TypeError cases, _DummyCommand.with_env() environment merging and validation, and sequential with_env() calls to complement existing integration tests.
User-Facing Documentation ⚠️ Warning Pull request introduces significant user-facing behavioural change to cross command toolchain handling without updating user-facing documentation. Update CHANGELOG.md with fix entry and README.md to clarify that cross uses environment variables or rust-toolchain.toml rather than CLI +toolchain overrides.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title '[codex] Fix cross nightly toolchain resolution' directly aligns with the main change: removing explicit +toolchain overrides from cross build commands to fix invalid toolchain name generation.
Description check ✅ Passed The description comprehensively covers the changeset: rationale for the fix, implementation changes, test adjustments, and validation steps all relate meaningfully to the toolchain resolution corrections across the codebase.
Developer Documentation ✅ Passed The pull request includes comprehensive documentation of all internal API and architectural changes in .github/actions/DEVELOPMENT.md, clearly explaining the new .with_env() protocol, modified _resolve_toolchain() signature, and RUSTUP_TOOLCHAIN environment variable approach for cross builds.
Module-Level Documentation ✅ Passed All modules in this pull request—both existing and newly added—carry clear module-level docstrings that explain their purpose and utility.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cross-nightly-arg

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Apr 17, 2026

Reviewer's Guide

Align cross build behavior with rustup toolchain resolution by removing cross-specific toolchain overrides and sanitization logic, so cross now relies on the repository or environment toolchain, with tests updated to enforce the new behavior.

Sequence diagram for updated cross and cargo toolchain resolution

sequenceDiagram
    actor Developer
    participant GithubAction as rust_build_release_action
    participant Decision as _decide_cross_usage
    participant Cargo as cargo
    participant Cross as cross

    Developer->>GithubAction: Trigger rust-build-release
    GithubAction->>Decision: _decide_cross_usage(toolchain_name, installed_names, rustup_exec, target, host_target)
    Decision-->>GithubAction: _CrossDecision(cargo_toolchain_spec=+toolchain_name,
    Decision-->>GithubAction:  use_cross, cross_path, use_cross_local_backend)

    alt use_cross is true
        GithubAction->>Cross: cross build --manifest-path ... --target target
        Note over Cross: No +toolchain spec passed
        Cross->>Cross: Resolve toolchain from RUSTUP_TOOLCHAIN or rust-toolchain.toml
    else use_cross is false
        GithubAction->>Cargo: cargo +toolchain_name build --manifest-path ... --target target
    end
Loading

Updated class diagram for _CrossDecision toolchain fields

classDiagram
    class _CrossDecision {
        str cross_path
        str cross_version
        bool use_cross
        str cargo_toolchain_spec
        bool use_cross_local_backend
        bool docker_present
    }

    class ToolchainDecisionLogic {
        +_decide_cross_usage(toolchain_name, installed_names, rustup_exec, target, host_target) _CrossDecision
        +_build_cross_command(decision, manifest_path, target, features, release) void
    }

    ToolchainDecisionLogic ..> _CrossDecision : returns

    class CargoInvocation {
        +build_command: cargo cargo_toolchain_spec build ...
    }

    class CrossInvocation {
        +build_command: cross build ...
    }

    ToolchainDecisionLogic ..> CargoInvocation : uses
    ToolchainDecisionLogic ..> CrossInvocation : uses

    class EnvironmentToolchainResolution {
        +RUSTUP_TOOLCHAIN
        +rust_toolchain_toml
    }

    CrossInvocation ..> EnvironmentToolchainResolution : resolves toolchain from
    CargoInvocation ..> _CrossDecision : uses cargo_toolchain_spec
Loading

File-Level Changes

Change Details Files
Stop passing an explicit +toolchain override to cross and remove related sanitization logic.
  • Remove OS triple constants and helper functions that detected and stripped target triples from toolchain names.
  • Simplify _decide_cross_usage to only compute a cargo_toolchain_spec while ignoring installed toolchains and rustup for cross-specific overrides.
  • Drop cross_toolchain_spec from the _CrossDecision tuple and its use in _build_cross_command, so cross is invoked without a +toolchain argument.
.github/actions/rust-build-release/src/main.py
Update tests to reflect that cross no longer receives a +toolchain argument and remove obsolete sanitize tests.
  • Extend manifest-path and feature-related tests to assert that generated cross commands start with cross build and contain no arguments starting with + after the subcommand.
  • Add a regression test that ensures cross relies on the repo-declared nightly toolchain instead of a CLI override when building a nightly project.
  • Remove tests that validated _toolchain_channel behavior and triple stripping for cross CLI overrides.
  • Update CrossDecision test protocol and fixtures to drop cross_toolchain_spec and adjust fake decisions accordingly.
.github/actions/rust-build-release/tests/test_manifest_path.py
.github/actions/rust-build-release/tests/test_toolchain_sanitize.py
.github/actions/rust-build-release/tests/test_features.py
.github/actions/rust-build-release/tests/conftest.py
.github/actions/rust-build-release/tests/test_target_install.py

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

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos leynos marked this pull request as ready for review April 18, 2026 12:14
sourcery-ai[bot]

This comment was marked as resolved.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 344ffe9e62

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/actions/rust-build-release/src/main.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/actions/rust-build-release/src/main.py:
- Around line 341-347: The function _decide_cross_usage currently includes
unused parameters _installed_names and _rustup_exec; remove those parameters
from _decide_cross_usage's signature and update the call site that invokes
_decide_cross_usage (the call around the noted call site) to stop passing those
two arguments, ensuring the function's type annotations and any callers are
adjusted accordingly; if this function is exported or used elsewhere search for
references to _decide_cross_usage and update them the same way to preserve
compatibility.

In @.github/actions/rust-build-release/tests/test_features.py:
- Around line 259-261: The duplicated assertion logic that checks cross commands
(parts[1] == "build" and all(not part.startswith("+") for part in parts[1:]))
should be extracted into a shared test helper (e.g., assert_cross_command(parts)
or validate_cross_command_parts) and used from both test_features.py and
test_manifest_path.py; implement the helper in a common test utilities module or
at the top of the test package, update the tests to call that helper instead of
repeating the two assertions, and ensure the helper name matches references so
test discovery and readability improve.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 92dd719f-abea-471d-adab-94ab80fceffc

📥 Commits

Reviewing files that changed from the base of the PR and between 6b13b51 and 344ffe9.

📒 Files selected for processing (6)
  • .github/actions/rust-build-release/src/main.py
  • .github/actions/rust-build-release/tests/conftest.py
  • .github/actions/rust-build-release/tests/test_features.py
  • .github/actions/rust-build-release/tests/test_manifest_path.py
  • .github/actions/rust-build-release/tests/test_target_install.py
  • .github/actions/rust-build-release/tests/test_toolchain_sanitize.py
💤 Files with no reviewable changes (2)
  • .github/actions/rust-build-release/tests/test_target_install.py
  • .github/actions/rust-build-release/tests/conftest.py

Comment thread .github/actions/rust-build-release/src/main.py
Comment thread .github/actions/rust-build-release/tests/test_features.py Outdated
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/actions/rust-build-release/src/main.py (1)

625-635: 🧹 Nitpick | 🔵 Trivial

Collapse _resolve_toolchain() to a scalar return.

Drop the dead list return. Line 625 now discards the second value immediately, and _decide_cross_usage() no longer consumes any installed-toolchain state. Shrink the private helper contract to str and remove the tuple plumbing from the test stubs as well.

♻️ Proposed change
-    toolchain_name, _installed_names = _resolve_toolchain(
+    toolchain_name = _resolve_toolchain(
         rustup_exec, requested_toolchain, target_to_build
     )
# Then update _resolve_toolchain() to return only `toolchain_name`
# and simplify the patched return values in the tests.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/actions/rust-build-release/src/main.py around lines 625 - 635, The
call to _resolve_toolchain currently unpacks a dead second value; change
_resolve_toolchain to return only the toolchain_name (str) and update its call
sites (e.g., replace "toolchain_name, _installed_names =
_resolve_toolchain(...)" with "toolchain_name = _resolve_toolchain(...)") and
any other unpacking uses, adjust _decide_cross_usage callers if they expected
the removed value, and update test stubs/mocks to return a simple string instead
of a tuple so the function signature and all call sites consistently use a
single str return.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In @.github/actions/rust-build-release/src/main.py:
- Around line 625-635: The call to _resolve_toolchain currently unpacks a dead
second value; change _resolve_toolchain to return only the toolchain_name (str)
and update its call sites (e.g., replace "toolchain_name, _installed_names =
_resolve_toolchain(...)" with "toolchain_name = _resolve_toolchain(...)") and
any other unpacking uses, adjust _decide_cross_usage callers if they expected
the removed value, and update test stubs/mocks to return a simple string instead
of a tuple so the function signature and all call sites consistently use a
single str return.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8bb69a98-b081-4bec-a3bd-c5df1904fd67

📥 Commits

Reviewing files that changed from the base of the PR and between 344ffe9 and b63a202.

📒 Files selected for processing (5)
  • .github/actions/rust-build-release/src/main.py
  • .github/actions/rust-build-release/tests/conftest.py
  • .github/actions/rust-build-release/tests/test_features.py
  • .github/actions/rust-build-release/tests/test_manifest_path.py
  • .github/actions/rust-build-release/tests/test_target_install.py
💤 Files with no reviewable changes (1)
  • .github/actions/rust-build-release/tests/test_target_install.py

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/actions/rust-build-release/tests/test_target_install.py (1)

74-79: ⚠️ Potential issue | 🟠 Major

Update this assertion to the new cross contract.

Stop asserting a +toolchain argv fragment here. The implementation no longer injects one for cross, so this test is still pinned to the pre-PR command shape and no longer validates the regression that this change is meant to fix. Assert build as the subcommand, assert that no later arg starts with +, and record RUSTUP_TOOLCHAIN from the command wrapper’s environment instead.

🧪 Proposed fix
-    app_env.patch_run_cmd(run_cmd_side_effect)
+    captured: dict[str, object] = {}
+
+    def fake_run(cmd: object) -> None:
+        parts = list(cmd.formulate())
+        run_cmd_side_effect(parts)
+        captured["parts"] = parts
+        captured["env"] = getattr(cmd, "env", {})
+
+    app_env.patch_attr("run_cmd", fake_run)
@@
-    build_cmd = app_env.calls[-1]
+    build_cmd = typ.cast("list[str]", captured["parts"])
     assert Path(build_cmd[0]).name == "cross"
-    assert build_cmd[1] == f"+{default_toolchain}"
+    assert build_cmd[1] == "build"
+    assert all(not part.startswith("+") for part in build_cmd[1:])
+    assert captured["env"] == {"RUSTUP_TOOLCHAIN": default_toolchain}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/actions/rust-build-release/tests/test_target_install.py around lines
74 - 79, The test currently asserts a "+toolchain" argv fragment; update it to
match the new cross contract by replacing the app_env.patch_run_cmd usage with a
fake_run that captures command parts and env (use names from the diff: fake_run,
captured, run_cmd_side_effect), call main_module.main("aarch64-pc-windows-gnu",
default_toolchain) as before, then set build_cmd = captured["parts"] and assert
Path(build_cmd[0]).name == "cross", assert build_cmd[1] == "build", assert
all(not part.startswith("+") for part in build_cmd[1:]), and assert
captured["env"] == {"RUSTUP_TOOLCHAIN": default_toolchain}; remove the old
assertion that build_cmd[1] == f"+{default_toolchain}".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/actions/rust-build-release/src/main.py:
- Around line 666-669: The cross environment variable uses the raw user input
`explicit_toolchain` instead of the canonicalised `toolchain_name` returned by
`_resolve_toolchain()` (which itself uses `_resolve_toolchain_name()` and
`_fallback_toolchain_name()`); update the branch where `explicit_toolchain` is
applied so that `build_cmd.with_env(RUSTUP_TOOLCHAIN=...)` uses `toolchain_name`
instead, ensuring `build_cmd` (the `_SupportsEnvFormulate` object) receives the
resolved toolchain that matches cargo and target installation paths and avoids
unrecognised identifiers when fallback resolution was used.

In @.github/actions/rust-build-release/tests/test_manifest_path.py:
- Around line 14-15: The test imports the helper directly as "from conftest
import assert_no_toolchain_override", which relies on pytest path injection and
is brittle; change the import to a package-relative import (e.g., "from
.conftest import assert_no_toolchain_override") or move the helper into a proper
test utility module and import it (e.g., from tests.utils import
assert_no_toolchain_override), and update the test_manifest_path.py import to
use that package-relative or utility-module import so it no longer depends on
top-level conftest resolution.

---

Outside diff comments:
In @.github/actions/rust-build-release/tests/test_target_install.py:
- Around line 74-79: The test currently asserts a "+toolchain" argv fragment;
update it to match the new cross contract by replacing the app_env.patch_run_cmd
usage with a fake_run that captures command parts and env (use names from the
diff: fake_run, captured, run_cmd_side_effect), call
main_module.main("aarch64-pc-windows-gnu", default_toolchain) as before, then
set build_cmd = captured["parts"] and assert Path(build_cmd[0]).name == "cross",
assert build_cmd[1] == "build", assert all(not part.startswith("+") for part in
build_cmd[1:]), and assert captured["env"] == {"RUSTUP_TOOLCHAIN":
default_toolchain}; remove the old assertion that build_cmd[1] ==
f"+{default_toolchain}".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 075ee775-0967-4348-a003-56ed598d2298

📥 Commits

Reviewing files that changed from the base of the PR and between b63a202 and 02bdad8.

📒 Files selected for processing (4)
  • .github/actions/rust-build-release/src/main.py
  • .github/actions/rust-build-release/tests/conftest.py
  • .github/actions/rust-build-release/tests/test_manifest_path.py
  • .github/actions/rust-build-release/tests/test_target_install.py

Comment thread .github/actions/rust-build-release/src/main.py
Comment thread .github/actions/rust-build-release/tests/test_manifest_path.py Outdated
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 18, 2026

@coderabbitai Have the following now been resolved?

Annul any requirements that violate the en-GB-oxendict spelling (-ize / -yse / -our) conventions (for example a request to replace "normalize" with "normalise" or "artefact" with "artifact"), or where the requirement unnecessarily increases cyclomatic complexity.

Please address the comments from this code review:

## Overall Comments
- In `_decide_cross_usage`, `installed_names` and `rustup_exec` are now unused (renamed to `_installed_names`/`_rustup_exec`), so consider removing them from the function signature and its call sites to simplify the API and make the intent clearer.

## Individual Comments

### Comment 1
<location path=".github/actions/rust-build-release/src/main.py" line_range="343-344" />
<code_context>
     toolchain_name: str,
-    installed_names: list[str],
-    rustup_exec: str,
+    _installed_names: list[str],
+    _rustup_exec: str,
     target: str,
     host_target: str,
</code_context>
<issue_to_address>
**suggestion:** Consider removing now-unused parameters from `_decide_cross_usage` to simplify the API.

With the sanitization/install logic removed, `_installed_names` and `_rustup_exec` are unused here. Unless you need to preserve the existing signature for external callers, it would be clearer to drop these parameters and adjust the call sites accordingly.

Suggested implementation:

```python
def _decide_cross_usage(
    toolchain_name: str,
    target: str,
    host_target: str,
) -> _CrossDecision:

```

Update all call sites of `_decide_cross_usage` in `.github/actions/rust-build-release/src/main.py` (and any other modules, if applicable) to:
1. Stop passing the `_installed_names` and `_rustup_exec` arguments.
2. Ensure calls now use the simplified signature: `_decide_cross_usage(toolchain_name, target, host_target)` with the correct positional or keyword argument order.
</issue_to_address>

### Comment 2
<location path=".github/actions/rust-build-release/tests/test_features.py" line_range="259-261" />
<code_context>
             )

         parts = list(cmd.formulate())
+        if builder_type == "cross":
+            assert parts[1] == "build"
+            assert all(not part.startswith("+") for part in parts[1:])

         _assert_features_in_command_parts(
</code_context>
<issue_to_address>
**suggestion:** Extract a small helper for the repeated cross command shape assertion.

This cross-specific assertion (`parts[1] == "build"` and no `"+"` prefixes in `parts[1:]`) is duplicated here and in `test_manifest_path.py`. Consider extracting a shared helper (e.g. `_assert_no_toolchain_override(parts: list[str])`) in a common test module and calling it from both places to centralize the invariant and reduce duplication.

Suggested implementation:

```python
            )

        def _assert_no_toolchain_override(parts: list[str]) -> None:
            assert parts[1] == "build"
            assert all(not part.startswith("+") for part in parts[1:])

        parts = list(cmd.formulate())
        if builder_type == "cross":
            _assert_no_toolchain_override(parts)

```

To fully implement your suggestion of a shared helper:
1. Move `_assert_no_toolchain_override` to a common test helper module (e.g. `.github/actions/rust-build-release/tests/_helpers.py` or `conftest.py`) as a top-level function.
2. Import and use `_assert_no_toolchain_override` in both `test_features.py` and `test_manifest_path.py`, replacing any duplicated inline assertions there.
3. Remove the local definition in `test_features.py` once the shared helper is in place and imported.
</issue_to_address>

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 18, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check current state of _decide_cross_usage in main.py
rg -n "_decide_cross_usage|_installed_names|_rustup_exec" .github/actions/rust-build-release/src/main.py

echo "---"
# Check assert_no_toolchain_override in conftest.py
rg -n "assert_no_toolchain_override|no_toolchain_override" .github/actions/rust-build-release/tests/conftest.py

echo "---"
# Check usage in test_features.py
rg -n "assert_no_toolchain_override|no_toolchain_override" .github/actions/rust-build-release/tests/test_features.py

echo "---"
# Check usage in test_manifest_path.py
rg -n "assert_no_toolchain_override|no_toolchain_override" .github/actions/rust-build-release/tests/test_manifest_path.py

Length of output: 609


@leynos Yes, both are resolved on the current branch:

Comment 1 — Remove unused parameters from _decide_cross_usage:
_installed_names and _rustup_exec are absent from main.py entirely. The call site at line 643 already uses the simplified three-parameter form:

decision = _decide_cross_usage(toolchain_name, target_to_build, host_target)

Comment 2 — Extract shared helper for cross command shape assertion:
assert_no_toolchain_override is defined in conftest.py (line 216) and imported and called in both test_features.py and test_manifest_path.py (the latter uses it at four call sites).

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 18, 2026

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Code Duplication

.github/actions/rust-build-release/tests/test_manifest_path.py:

What lead to degradation?

The module contains 2 functions with similar structure: test_main_does_not_export_cross_toolchain_without_explicit_override,test_main_exports_explicit_toolchain_to_cross_command

Why does this problem occur?

Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health.

How to fix it?

A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

@coderabbitai

This comment was marked as resolved.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
.github/actions/rust-build-release/tests/test_manifest_path.py (1)

329-393: 🧹 Nitpick | 🔵 Trivial

Collapse these two cross toolchain-env tests into one parametrized case.

Merge this pair into a single @pytest.mark.parametrize test. Both functions patch the same attributes, capture the same fields, and assert the same command invariant; only the explicit input and expected env differ, so keeping them separate invites drift.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/actions/rust-build-release/tests/test_manifest_path.py around lines
329 - 393, Collapse the two tests
test_main_exports_explicit_toolchain_to_cross_command and
test_main_does_not_export_cross_toolchain_without_explicit_override into one
pytest.mark.parametrize test that reuses the same setup (harness.patch_attr,
captured dict, decision = context.cross_decision_factory, fake_run patch of
run_cmd, and assert_no_toolchain_override on parts) and only varies the inputs
and expected env: parameterize the call to context.main_module.main (pass
toolchain="nightly-2026-03-26" for the explicit case and omit/None for the
ambient case) and the expected captured["env"] ({"RUSTUP_TOOLCHAIN":
"nightly-2026-03-26-x86_64-unknown-linux-gnu"} vs {}). Keep the same assertions
on parts and use descriptive param ids; remove the original two test functions
and ensure the new test still patches _resolve_target_argument,
_resolve_toolchain/resolve_requested_toolchain, and _decide_cross_usage as
before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/actions/rust-build-release/src/main.py:
- Around line 625-631: The code currently strips whitespace into
explicit_toolchain but then calls resolve_requested_toolchain(...) with the
original toolchain variable, allowing a whitespace-only override to bypass
fallback; change the resolve_requested_toolchain call to pass explicit_toolchain
instead of toolchain so the normalized (stripped) value is used when computing
requested_toolchain (update the call site that constructs requested_toolchain
which references resolve_requested_toolchain, keeping project_dir, manifest_path
and fallback DEFAULT_TOOLCHAIN the same).

In @.github/actions/rust-build-release/tests/conftest.py:
- Around line 209-213: The with_env method currently discards positional args
(args) and only merges kwargs into the wrapped _DummyCommand, which narrows the
API compared to the real command; update with_env to accept and parse
mapping-style positional environment arguments from *args (e.g., dict or Mapping
instances), merge them in order before applying **kwargs into wrapped.env, and
ensure wrapped.env = {**self.env, **merged_from_args, **kwargs}; also validate
or raise if any arg is not a mapping so _DummyCommand's with_env contract
mirrors the production wrapper.

In @.github/actions/rust-build-release/tests/test_target_install.py:
- Around line 83-85: Replace the two open-coded assertions about the build
command with the shared helper: call assert_no_toolchain_override(build_cmd)
instead of asserting build_cmd[1] == "build" and checking parts for '+'; keep
the existing env check (assert captured["env"] == {"RUSTUP_TOOLCHAIN":
default_toolchain}) as-is. This consolidates the command-shape invariant into
the helper (referencing build_cmd, default_toolchain, and the helper
assert_no_toolchain_override).

---

Duplicate comments:
In @.github/actions/rust-build-release/tests/test_manifest_path.py:
- Around line 329-393: Collapse the two tests
test_main_exports_explicit_toolchain_to_cross_command and
test_main_does_not_export_cross_toolchain_without_explicit_override into one
pytest.mark.parametrize test that reuses the same setup (harness.patch_attr,
captured dict, decision = context.cross_decision_factory, fake_run patch of
run_cmd, and assert_no_toolchain_override on parts) and only varies the inputs
and expected env: parameterize the call to context.main_module.main (pass
toolchain="nightly-2026-03-26" for the explicit case and omit/None for the
ambient case) and the expected captured["env"] ({"RUSTUP_TOOLCHAIN":
"nightly-2026-03-26-x86_64-unknown-linux-gnu"} vs {}). Keep the same assertions
on parts and use descriptive param ids; remove the original two test functions
and ensure the new test still patches _resolve_target_argument,
_resolve_toolchain/resolve_requested_toolchain, and _decide_cross_usage as
before.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b6576ab4-2a82-4d0d-a65e-6232ffd3384a

📥 Commits

Reviewing files that changed from the base of the PR and between 02bdad8 and 63a21a2.

📒 Files selected for processing (6)
  • .github/actions/rust-build-release/src/main.py
  • .github/actions/rust-build-release/tests/conftest.py
  • .github/actions/rust-build-release/tests/rust_build_release_test_helpers.py
  • .github/actions/rust-build-release/tests/test_features.py
  • .github/actions/rust-build-release/tests/test_manifest_path.py
  • .github/actions/rust-build-release/tests/test_target_install.py

Comment thread .github/actions/rust-build-release/src/main.py
Comment thread .github/actions/rust-build-release/tests/conftest.py
Comment thread .github/actions/rust-build-release/tests/test_target_install.py Outdated
codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/actions/rust-build-release/tests/test_manifest_path.py:
- Around line 346-385: Add a test case exercising main() with a repo-declared
nightly manifest by adding a NIGHTLY_CRANELIFT_PROJECT / dated-nightly scenario
to test_main_cross_toolchain_environment (or a small companion test) where
explicit_toolchain is None: arrange resolved_toolchain to represent the nightly
manifest, ensure setup_manifest provides the dated-nightly path, call
context.main_module.main("aarch64-unknown-linux-gnu") (no toolchain arg), and
assert that captured["env"] contains the expected NIGHTLY_CRANELIFT_PROJECT (and
still no toolchain override) — this ensures the dated-nightly branch exercised
by _build_cross_command() is covered end-to-end by main().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 10ee12a8-fe1e-4ade-a5db-667499f2e23d

📥 Commits

Reviewing files that changed from the base of the PR and between 63a21a2 and ca19d97.

📒 Files selected for processing (1)
  • .github/actions/rust-build-release/tests/test_manifest_path.py

Comment thread .github/actions/rust-build-release/tests/test_manifest_path.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
.github/actions/rust-build-release/tests/test_manifest_path.py (1)

13-13: ⚠️ Potential issue | 🟡 Minor

Switch this helper import to a package-relative path.

Replace the absolute import on Line 13 with from .rust_build_release_test_helpers import assert_no_toolchain_override to avoid accidental module shadowing from sys.path precedence.

#!/bin/bash
set -euo pipefail
# Verify whether helper module names can collide and where this import style is used.
fd -a 'rust_build_release_test_helpers.py$' .
rg -n 'from rust_build_release_test_helpers import|from \.rust_build_release_test_helpers import' .github/actions/rust-build-release/tests
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/actions/rust-build-release/tests/test_manifest_path.py at line 13,
Replace the top-level import of the test helper with a package-relative import
so the local helper module can't be shadowed; change the import of
rust_build_release_test_helpers to a relative import (referencing the module
rust_build_release_test_helpers and the symbol assert_no_toolchain_override) by
using from .rust_build_release_test_helpers import assert_no_toolchain_override
in the test file that imports assert_no_toolchain_override.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.github/actions/rust-build-release/tests/test_manifest_path.py:
- Line 13: Replace the top-level import of the test helper with a
package-relative import so the local helper module can't be shadowed; change the
import of rust_build_release_test_helpers to a relative import (referencing the
module rust_build_release_test_helpers and the symbol
assert_no_toolchain_override) by using from .rust_build_release_test_helpers
import assert_no_toolchain_override in the test file that imports
assert_no_toolchain_override.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 266f3c01-57f3-4009-8392-2064c7f8b71b

📥 Commits

Reviewing files that changed from the base of the PR and between 460f49e and d8d1fff.

📒 Files selected for processing (1)
  • .github/actions/rust-build-release/tests/test_manifest_path.py

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 18, 2026

@coderabbitai pause

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 18, 2026

✅ Actions performed

Reviews paused.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 18, 2026

@coderabbitai please create a new GitHub issue for the following:

Verified this finding against the current code and did not change it.

test_manifest_path.py still imports assert_no_toolchain_override as from rust_build_release_test_helpers import ..., but the tests directory is not a Python package because it has no __init__.py. In that state, changing it to from .rust_build_release_test_helpers import ... would fail under normal import semantics because there is no package context for a relative import.

I also confirmed the broader issue: importing this test module directly outside pytest already fails with ModuleNotFoundError No module named 'rust_build_release_test_helpers', which means the current import relies on pytest’s path handling. A package-relative import would not solve that in the current layout. If you want this hardened, the correct fix is to make the tests directory a package or move the helper to a package/module that is imported consistently by all test runners.

@leynos leynos merged commit 413dd72 into main Apr 18, 2026
23 checks passed
@leynos leynos deleted the fix/cross-nightly-arg branch April 18, 2026 18:15
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 18, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh issue create \
  --repo leynos/shared-actions \
  --title "test helper import relies on pytest path injection; fragile outside pytest" \
  --assignee leynos \
  --body "## Summary

The test helper \`assert_no_toolchain_override\` defined in \`.github/actions/rust-build-release/tests/rust_build_release_test_helpers.py\` is imported by test modules (e.g. \`test_manifest_path.py\`) using a bare module import:

\`\`\`python
from rust_build_release_test_helpers import assert_no_toolchain_override
\`\`\`

The \`tests\` directory currently has no \`__init__.py\`, so it is not a Python package. This bare import works only because pytest injects the directory into \`sys.path\`. Importing the test module directly outside pytest fails with:

\`\`\`
ModuleNotFoundError: No module named 'rust_build_release_test_helpers'
\`\`\`

Changing the import to a relative form (\`from .rust_build_release_test_helpers import ...\`) would also fail under the current layout because there is no package context.

## Recommended fix

Either:
- Add an \`__init__.py\` to \`.github/actions/rust-build-release/tests/\` to make it a proper Python package and switch to relative imports (\`from .rust_build_release_test_helpers import ...\`), **or**
- Move the helper into a module that is importable consistently by all test runners (e.g. via \`conftest.py\` or a properly installed package).

## Context

Identified during review of PR `#255` (https://github.com/leynos/shared-actions/pull/255) and verified against the current state of the branch; not addressed in that PR.

Reported by `@leynos`."

Length of output: 51


@leynos: Issue created — #256

It captures the fragile bare-import pattern, the root cause (no __init__.py), why a relative import would equally fail in the current layout, and the two recommended remediation paths.

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