Skip to content

Refactor release workflow to use shared reusable actions#253

Merged
leynos merged 10 commits intomainfrom
terragon/refactor-release-workflow-shared-actions-x1sf00
Jan 4, 2026
Merged

Refactor release workflow to use shared reusable actions#253
leynos merged 10 commits intomainfrom
terragon/refactor-release-workflow-shared-actions-x1sf00

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Dec 29, 2025

Summary

  • Refactor release workflows to consume reusable actions from the leynos/shared-actions project, enabling consistent, pinned SHAs and shared logic for staging, packaging, and release mode decisions.
  • Align outputs/inputs across workflows to rely on shared-composites (stage-release-artefacts, determine-release-modes, export-cargo-metadata, etc.).

Changes

  • build-and-package.yml
    • Replace local staging composite with shared action:
    • Remove Windows path normalization step; expose paths via stage outputs and map to new keys:
      • application-path: ${{ steps.stage.outputs['binary-path'] }}
      • license-rtf-path: ${{ steps.stage.outputs['license-path'] }}
      • artifact-dir, binary-path, man-path
    • Simplify Windows handling by gating on shared action outputs instead of a separate step
  • release.yml
    • Replace manual Python steps with shared actions:
    • Update workflow outputs to match new shared action outputs:
      • bin_name: ${{ steps.bin_name.outputs['bin-name'] }}
      • should_publish: ${{ steps.release_modes.outputs['should-publish'] }}
      • dry_run: ${{ steps.release_modes.outputs['dry-run'] }}
      • should_upload_workflow_artifacts: ${{ steps.release_modes.outputs['should-upload-workflow-artifacts'] }}
    • Remove the separate Setup Python 3.11 step
  • docs/netsuke-design.md
    • Update release automation description to reflect using leynos/shared-actions with explicit SHAs and the stage-release-artefacts composable from shared-actions
    • Mention Windows artefact staging now relies on the shared stage composite and outputs from that shared action
    • Clarify that the tooling is now more reproducible due to pinned SHAs and shared-composites

Why

  • Centralize release workflow logic in reusable, pinned shared actions to improve maintainability, reproducibility, and consistency across platforms.
  • Reduce local workflow complexity by delegating staging, packaging, and mode-detection to shared composites.

Testing plan

  • Trigger a release workflow and verify that:
    • Artefacts are staged using the shared stage-release-artefacts action
    • Windows artefact paths are correctly resolved from stage outputs (binary-path, license-path, artifact-dir, man-path)
    • Release mode is determined via the shared determine-release-modes action
    • Cargo metadata is read via the shared export-cargo-metadata action and that bin-name is correctly surfaced
    • Packaging steps use the updated outputs for paths and naming
  • Ensure the final release artefacts (deb, rpm, msi, and pkg) are created and uploaded as expected
  • Validate that the docs reflect the new workflow design and that downstream references to outputs align with the new naming

Notes

  • SHAs for shared actions are pinned (e.g., 9b84b9fda7ac050cc5565bfa065740bf73b50c30) to ensure reproducibility.
  • This change is purely infrastructural wiring; no functional behavior changes in release logic beyond the switch to shared actions.

🌿 Generated by Terry


ℹ️ Tag @terragon-labs to ask questions and address PR feedback

📎 Task: https://www.terragonlabs.com/task/fe6889ba-b3ae-45dc-8bbb-80d586190fdf

Summary by Sourcery

Refactor release workflows to consume shared reusable actions for staging, metadata, and packaging while simplifying local tooling and keeping automation reproducible via pinned SHAs.

Enhancements:

  • Replace custom staging, metadata, and release upload logic with shared leynos/shared-actions composites across release and build-and-package workflows.
  • Align workflow outputs and inputs with shared action contracts, including updated output names and Windows/macOS artefact handling.
  • Remove now-unneeded local GitHub composite actions, Python helper scripts, and associated Makefile targets to reduce maintenance overhead.
  • Update CI workflows and other jobs to use newer pinned SHAs of shared leynos actions for Rust setup, coverage generation, and Codescene uploads.

Documentation:

  • Refresh release automation documentation to describe the shared-actions based staging and packaging flow, emphasising pinned SHAs and shared Windows staging behavior.

- Replace local custom actions in release and build workflows with
  pinned versions from `leynos/shared-actions` repository to ensure
  reproducibility and maintainability.
- Update staging workflow to use a generic `stage-release-artefacts`
  composite action with improved Windows path handling.
- Refactor metadata extraction and release mode determination to shared
  composites to reduce code duplication.
- Update documentation to reflect changes in release automation tooling.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 29, 2025

Warning

Rate limit exceeded

@leynos has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 37 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 6c9775b and b33f306.

📒 Files selected for processing (6)
  • tests/common/mod.rs
  • tests/fixtures/mod.rs
  • tests/runner_tests.rs
  • tests/runner_tool_subcommands_tests.rs
  • tests/workflow_build_and_package.rs
  • tests/workflow_release.rs

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Consolidate local GitHub Actions and Python staging/upload helpers into external shared actions; remove local composite actions, CLI scripts, staging library modules and many related tests; update workflows to reference leynos/shared-actions and rename stage outputs/inputs.

Changes

Cohort / File(s) Summary
GitHub Actions composites
\.github/actions/export-bin-name/action.yml, \.github/actions/stage/action.yml, \.github/actions/upload-release-assets/action.yml
Remove three local composite actions and their inputs/outputs and run steps (bin-name export, stage-release artefacts, upload-release-assets).
Staging pipeline library & CLI
\.github/actions/stage/scripts/stage.py, \.github/actions/stage/scripts/stage_common/*, \.github/actions/stage/scripts/stage_common/staging/*
Delete CLI entrypoint, config loader, pipeline implementation, glob/template/resolution utilities, checksum/fs/environment helpers and GitHub-output writers; strip public exports.
Release helper scripts & manifest readers
\.github/workflows/scripts/determine_release_modes.py, \.github/workflows/scripts/normalise_windows_paths.py, \.github/workflows/scripts/read_manifest.py, scripts/upload_release_assets.py, scripts/_release_upload_deps.py
Remove scripts for release-mode computation, Windows path normalisation, manifest reading, asset upload CLI and optional-dependency guards.
Workflows
\.github/workflows/build-and-package.yml, \.github/workflows/ci.yml, \.github/workflows/netsukefile-test.yml, \.github/workflows/release.yml
Update workflow action refs to new shared-actions SHA, replace local stage/upload actions with shared actions, rename stage outputs/inputs (e.g., binary_pathbinary-path) and adjust consumers; remove intermediate normalisation step.
Tests removed (Python)
tests_python/conftest.py, tests_python/stage_test_helpers.py, tests_python/test_stage_*.py (multiple), tests_python/test_normalise_windows_paths.py, tests_python/test_read_manifest.py, tests_python/test_release_modes.py, scripts/tests/test_upload_release_assets.py
Remove 20+ Python tests covering staging, glob resolution, config loading, CLI behaviour, manifest reading and upload scripts.
Makefile & quality scripts
Makefile, codex/refactor-python-staging-scripts-into-github-action
Remove typecheck Makefile target and drop the aggregated quality-gate bash script.
Documentation & design notes
docs/netsuke-design.md
Update docs to reference shared actions, explicit SHAs and revised staging/packaging narrative.
Workflow tests (added)
tests/workflow_build_and_package.rs, tests/workflow_release.rs, tests/workflow_shared_actions_pins.rs, tests/common/mod.rs
Add Rust tests verifying workflow wiring: shared-actions pins, renamed stage outputs, and consistent shared-action pinning; add helper to load workflow contents.
Test helpers & fixtures removed
tests_python/* (many helpers/fixtures)
Remove multiple pytest fixtures and helpers that supported the staging and release script tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

Scripts set sail, locals fade away,
Actions pooled beneath a single sway,
Tests and helpers left upon the shore,
Workflows point to shared actions evermore,
New pins lock time, pipelines find their way.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Refactor release workflow to use shared reusable actions' accurately summarises the primary change: migrating from local release automation to pinned shared GitHub Actions.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, detailing the replacement of local workflows with shared actions, specific file changes, motivations, and testing plans.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Dec 29, 2025

Reviewer's Guide

Refactors release and packaging workflows to consume pinned reusable actions from leynos/shared-actions for staging, metadata, and release-mode handling, while deleting the local Python-based staging/upload toolchain and aligning docs and workflow outputs with the shared composites.

Sequence diagram for release metadata job using shared actions

sequenceDiagram
  participant GH as GitHub_Actions
  participant REL as workflow_release
  participant META as job_metadata
  participant DRM as determine_release_modes
  participant ECV as ensure_cargo_version
  participant ECM as export_cargo_metadata

  GH->>REL: trigger on release_tag
  REL->>META: start job_metadata

  META->>DRM: uses determine_release_modes
  DRM-->>META: outputs should-publish, dry-run, should-upload-workflow-artifacts

  META->>ECV: uses ensure_cargo_version
  Note over META,ECV: input check-tag = fromJSON(release_modes.outputs['should-publish'])
  ECV-->>META: output crate-version

  META->>ECM: uses export_cargo_metadata
  Note over META,ECM: inputs manifest-path, fields=bin-name, export-to-env=false
  ECM-->>META: output bin-name

  META-->>REL: set job outputs
  REL-->>REL: expose version, bin_name, should_publish, dry_run, should_upload_workflow_artifacts
Loading

Flow diagram for build_and_package job using shared stage_release_artefacts

graph TD
  A[Start_job_build_and_package] --> B[Setup_Rust_and_Python]
  B --> C[Build_release_binary_using_rust_build_release]

  C --> D{Platform}

  D -->|linux| E_linux[Package_with_linux_packages]
  E_linux --> Z[End_job]

  D -->|windows| S_stage_win[Stage_artefacts_using_stage_release_artefacts]
  S_stage_win --> S1[Shared_action_normalizes_windows_paths]
  S1 --> F_win[Build_Windows_MSI_using_windows_package]
  F_win --> G_win[Upload_Windows_artefacts]
  G_win --> Z

  D -->|macos| S_stage_mac[Stage_artefacts_using_stage_release_artefacts]
  S_stage_mac --> F_mac[Build_macOS_pkg_using_macos_package]
  F_mac --> G_mac[Upload_macOS_artefacts]
  G_mac --> Z

  subgraph WindowsOutputs
    S_stage_win --> O1_stage_bin[binary-path]
    S_stage_win --> O2_stage_license[license-path]
    F_win --> O3_msi_path[msi-path]
  end

  subgraph MacOSOutputs
    S_stage_mac --> O4_stage_bin[binary-path]
    S_stage_mac --> O5_stage_man[man-path]
  end

  subgraph SharedUploadInputs
    S_stage_win --> O6_stage_dir_win[artifact-dir]
    S_stage_mac --> O7_stage_dir_mac[artifact-dir]
  end
Loading

File-Level Changes

Change Details Files
Switch release metadata job to shared reusable actions and update workflow outputs to match their contracts.
  • Replace Python script step for determining release modes with leynos/shared-actions determine-release-modes composite, removing the explicit setup-python step.
  • Use ensure-cargo-version and export-cargo-metadata shared actions to read crate version and binary name instead of local manifest-parsing scripts.
  • Rewire metadata job outputs (bin_name, should_publish, dry_run, should_upload_workflow_artifacts) to use the new shared action output keys and JSON fields.
  • Use shared upload-release-assets action from leynos/shared-actions instead of the local upload-release-assets composite and associated Python helper scripts.
.github/workflows/release.yml
Replace local staging and packaging wiring in build-and-package workflow with shared staging composite outputs.
  • Swap local .github/actions/stage composite for leynos/shared-actions stage-release-artefacts, passing the staging config and target plus normalize-windows-paths flag.
  • Remove the bespoke Windows path normalisation script and consume normalized paths directly from stage-release-artefacts outputs.
  • Update windows-package and macos-package steps to use new output names (binary-path, license-path, man-path, artifact-dir) and correct upload-artefact input key.
  • Bump rust-build-release, linux-packages, windows-package, macos-package action SHAs to the new pinned df81280… revision across the workflow.
.github/workflows/build-and-package.yml
Align CI and auxiliary workflows with the new shared-actions revision.
  • Update setup-rust, generate-coverage, and upload-codescene-coverage actions to the new df81280… SHA.
  • Ensure netsukefile-test workflow uses the updated setup-rust composite.
.github/workflows/ci.yml
.github/workflows/netsukefile-test.yml
Update design documentation to describe the shared staging composite and generic pinned SHAs instead of local staging action details.
  • Describe release automation as using leynos/shared-actions with explicit pinned SHAs instead of a single hardcoded SHA value.
  • Document that Windows builds now call the shared stage-release-artefacts composite from leynos/shared-actions rather than the repo-local .github/actions/stage.
  • Remove the explicit windows-package SHA from the docs and refer to the shared composite generically, while preserving behavioural details (WiX configuration, MSI semantics, artefact uploader gating).
docs/netsuke-design.md
Remove deprecated local staging, metadata, and upload implementations and their tests.
  • Delete the local export-bin-name and stage composite actions plus all associated Python staging scripts and helpers under .github/actions/stage.
  • Remove workflow helper scripts for determining release modes, normalising Windows paths, reading Cargo manifest metadata, and uploading release assets.
  • Delete the release upload dependency script, upload_release_assets entry point, and all Python tests covering staging, normalisation, manifest reading, and release modes.
  • Drop the Makefile typecheck target that ran ty against the now-deleted staging scripts.
.github/actions/export-bin-name/action.yml
.github/actions/stage/action.yml
.github/actions/stage/scripts/stage.py
.github/actions/stage/scripts/stage_common/__init__.py
.github/actions/stage/scripts/stage_common/checksum_utils.py
.github/actions/stage/scripts/stage_common/config.py
.github/actions/stage/scripts/stage_common/environment.py
.github/actions/stage/scripts/stage_common/errors.py
.github/actions/stage/scripts/stage_common/fs_utils.py
.github/actions/stage/scripts/stage_common/github_output.py
.github/actions/stage/scripts/stage_common/glob_utils.py
.github/actions/stage/scripts/stage_common/staging/__init__.py
.github/actions/stage/scripts/stage_common/staging/output.py
.github/actions/stage/scripts/stage_common/staging/pipeline.py
.github/actions/stage/scripts/stage_common/staging/resolution.py
.github/actions/stage/scripts/stage_common/template_utils.py
.github/actions/upload-release-assets/action.yml
.github/workflows/scripts/determine_release_modes.py
.github/workflows/scripts/normalise_windows_paths.py
.github/workflows/scripts/read_manifest.py
codex/refactor-python-staging-scripts-into-github-action
scripts/_release_upload_deps.py
scripts/tests/test_upload_release_assets.py
scripts/upload_release_assets.py
tests_python/conftest.py
tests_python/stage_test_helpers.py
tests_python/test_normalise_windows_paths.py
tests_python/test_read_manifest.py
tests_python/test_release_modes.py
tests_python/test_stage_action.py
tests_python/test_stage_artefacts.py
tests_python/test_stage_cli.py
tests_python/test_stage_common_config.py
tests_python/test_stage_common_module.py
tests_python/test_stage_common_staging.py
tests_python/test_stage_config.py
tests_python/test_stage_glob.py
tests_python/test_stage_helpers.py
tests_python/test_stage_integration.py
tests_python/test_stage_output.py
Makefile

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

This commit deletes the entire Python-based staging helper under
.github/actions/stage and the upload-release-assets action and related
scripts and tests. It also updates workflow YAMLs to remove references
to these deleted actions, replacing them with updated composite actions.

The staging logic implemented in Python has been fully removed,
including configuration loading, artifact staging, checksum generation,
environment helpers, output formatting, path resolution, and tests.

Additionally, scripts for reading Cargo manifests, normalising Windows
paths, uploading release assets, determining release modes, and their
tests have been deleted.

Workflows now reference updated actions via explicit SHA revisions,
reflecting a migration away from the removed Python-based components.

This refactor cleans up the repository by removing obsolete staging
helper code and streamlining CI workflows with maintained action
releases.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
Updated the GitHub workflow files to use a newer commit hash (6cae1ffdbb88) for all leynos/shared-actions references, replacing the previous commit hash (9b84b9fda7ac). This ensures consistent action versions across build-and-package.yml, ci.yml, netsukefile-test.yml, and release.yml workflows.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
Updated several GitHub workflow action references from commit 6cae1ffdbb88 to f870d9959d5f039d5b705856428103ea52d28d2f to use latest shared-actions versions in CI, build, package, and release workflows.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
Updated all leynos/shared-actions usages in GitHub workflows to commit 1e80300db7c46478d398deae4f48c3d0e61ac571 to ensure latest action versions are used.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
Updated multiple GitHub workflow files to reference the latest commit SHA of shared-actions repository, ensuring use of up-to-date CI and release automation steps.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos marked this pull request as ready for review January 3, 2026 19:53
Copy link
Copy Markdown
Contributor

@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:

  • Double-check the upload-artefact input name in the windows-package step matches the shared action’s expected input (previously upload-artifact), and consider standardising artifact/artefact spelling across workflow inputs/outputs to avoid subtle wiring mistakes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Double-check the `upload-artefact` input name in the `windows-package` step matches the shared action’s expected input (previously `upload-artifact`), and consider standardising `artifact/artefact` spelling across workflow inputs/outputs to avoid subtle wiring mistakes.

## Individual Comments

### Comment 1
<location> `.github/workflows/release.yml:63` </location>
<code_context>
-      should_publish: ${{ steps.release_modes.outputs.should_publish }}
-      dry_run: ${{ steps.release_modes.outputs.dry_run }}
-      should_upload_workflow_artifacts: ${{ steps.release_modes.outputs.should_upload_workflow_artifacts }}
+      bin_name: ${{ steps.bin_name.outputs['bin-name'] }}
+      should_publish: ${{ steps.release_modes.outputs['should-publish'] }}
+      dry_run: ${{ steps.release_modes.outputs['dry-run'] }}
</code_context>

<issue_to_address>
**issue (review_instructions):** Add behavioural and unit tests that exercise the new shared-actions-based metadata and release-mode logic introduced in this workflow.

You replace in-repo Python scripts and custom actions with shared actions (`determine-release-modes`, `ensure-cargo-version`, `export-cargo-metadata`, and `upload-release-assets`) while also changing output names and wiring (e.g. `bin-name`, `should-publish`, `dry-run`). This is a change to the existing release feature, but the diff does not introduce any new tests that validate the updated behaviour (e.g. correct `should_publish`/`dry_run` resolution, tag checking, bin name extraction, or asset upload wiring). Add both behavioural tests (end-to-end or high-level integration checks around the release process) and unit-level tests (covering the logic that you still own and can exercise, e.g. wrapper scripts or configuration validation) to demonstrate that the new workflow behaviour is correct.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*`

**Instructions:**
For any new feature or change to an existing feature, both behavioural *and* unit tests are required.

</details>
</issue_to_address>

### Comment 2
<location> `.github/workflows/build-and-package.yml:111` </location>
<code_context>
         name: Determine repository name
         run: echo "value=${GITHUB_REPOSITORY#*/}" >>"$GITHUB_OUTPUT"
-      - name: Setup Python 3.11
-        uses: >-
-          actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
-        # v5
</code_context>

<issue_to_address>
**issue (review_instructions):** Add tests that validate the new staging and packaging behaviour now delegated to shared actions and the updated output/parameter wiring.

You change the implementation of the build-and-package feature by swapping the local `stage` composite and helper scripts for the shared `stage-release-artefacts`, `windows-package`, `macos-package`, and updated `rust-build-release`/`linux-packages` actions, and you rename or rewire multiple outputs/inputs (e.g. `binary-path`, `man-path`, `artifact-dir`, `upload-artefact`). This materially changes how artefacts are staged and installers are produced, yet the diff shows no new behavioural or unit tests that assert the new behaviour. Add behavioural tests (for example, a workflow or script-driven test that builds and stages artefacts and verifies expected outputs/paths) and unit tests for any remaining in-repo logic that participates in this pipeline to ensure the feature still behaves as intended.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*`

**Instructions:**
For any new feature or change to an existing feature, both behavioural *and* unit tests are required.

</details>
</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.

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: 6

Caution

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

⚠️ Outside diff range comments (1)
docs/netsuke-design.md (1)

2121-2135: Expand acronym: PEP.

Line 2124 introduces "PEP 723" without expanding it. Expand "Python Enhancement Proposal" on first use.

🔎 Proposed acronym expansion
- macOS releases execute the shared action twice: once on an Intel runner and
- again on Apple Silicon. The same composite action interprets the TOML
- configuration, emits checksums, and exposes artefact metadata via JSON outputs
- before feeding the resulting paths into the `macos-package` action. Embedding
- the PEP 723 metadata keeps Cyclopts discoverable without a repository-level
+ macOS releases execute the shared action twice: once on an Intel runner and
+ again on Apple Silicon. The same composite action interprets the TOML
+ (Tom's Obvious, Minimal Language) configuration, emits checksums, and exposes
+ artefact metadata via JSON outputs before feeding the resulting paths into the
+ `macos-package` action. Embedding the PEP (Python Enhancement Proposal) 723
+ metadata keeps Cyclopts discoverable without a repository-level
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8bcee3d and f9bb547.

📒 Files selected for processing (46)
  • .github/actions/export-bin-name/action.yml
  • .github/actions/stage/action.yml
  • .github/actions/stage/scripts/stage.py
  • .github/actions/stage/scripts/stage_common/__init__.py
  • .github/actions/stage/scripts/stage_common/checksum_utils.py
  • .github/actions/stage/scripts/stage_common/config.py
  • .github/actions/stage/scripts/stage_common/environment.py
  • .github/actions/stage/scripts/stage_common/errors.py
  • .github/actions/stage/scripts/stage_common/fs_utils.py
  • .github/actions/stage/scripts/stage_common/github_output.py
  • .github/actions/stage/scripts/stage_common/glob_utils.py
  • .github/actions/stage/scripts/stage_common/staging/__init__.py
  • .github/actions/stage/scripts/stage_common/staging/output.py
  • .github/actions/stage/scripts/stage_common/staging/pipeline.py
  • .github/actions/stage/scripts/stage_common/staging/resolution.py
  • .github/actions/stage/scripts/stage_common/template_utils.py
  • .github/actions/upload-release-assets/action.yml
  • .github/workflows/build-and-package.yml
  • .github/workflows/ci.yml
  • .github/workflows/netsukefile-test.yml
  • .github/workflows/release.yml
  • .github/workflows/scripts/determine_release_modes.py
  • .github/workflows/scripts/normalise_windows_paths.py
  • .github/workflows/scripts/read_manifest.py
  • Makefile
  • codex/refactor-python-staging-scripts-into-github-action
  • docs/netsuke-design.md
  • scripts/_release_upload_deps.py
  • scripts/tests/test_upload_release_assets.py
  • scripts/upload_release_assets.py
  • tests_python/conftest.py
  • tests_python/stage_test_helpers.py
  • tests_python/test_normalise_windows_paths.py
  • tests_python/test_read_manifest.py
  • tests_python/test_release_modes.py
  • tests_python/test_stage_action.py
  • tests_python/test_stage_artefacts.py
  • tests_python/test_stage_cli.py
  • tests_python/test_stage_common_config.py
  • tests_python/test_stage_common_module.py
  • tests_python/test_stage_common_staging.py
  • tests_python/test_stage_config.py
  • tests_python/test_stage_glob.py
  • tests_python/test_stage_helpers.py
  • tests_python/test_stage_integration.py
  • tests_python/test_stage_output.py
💤 Files with no reviewable changes (40)
  • scripts/tests/test_upload_release_assets.py
  • .github/actions/stage/scripts/stage_common/errors.py
  • tests_python/test_stage_helpers.py
  • .github/actions/stage/scripts/stage_common/fs_utils.py
  • tests_python/test_stage_artefacts.py
  • .github/actions/stage/scripts/stage_common/init.py
  • .github/actions/stage/scripts/stage_common/checksum_utils.py
  • .github/workflows/scripts/normalise_windows_paths.py
  • tests_python/test_stage_common_module.py
  • .github/actions/stage/scripts/stage.py
  • .github/actions/export-bin-name/action.yml
  • .github/actions/stage/action.yml
  • tests_python/test_normalise_windows_paths.py
  • tests_python/test_stage_action.py
  • tests_python/stage_test_helpers.py
  • scripts/upload_release_assets.py
  • .github/actions/upload-release-assets/action.yml
  • .github/actions/stage/scripts/stage_common/config.py
  • .github/actions/stage/scripts/stage_common/environment.py
  • .github/actions/stage/scripts/stage_common/glob_utils.py
  • tests_python/test_stage_glob.py
  • codex/refactor-python-staging-scripts-into-github-action
  • tests_python/test_release_modes.py
  • .github/actions/stage/scripts/stage_common/staging/resolution.py
  • tests_python/test_stage_common_staging.py
  • tests_python/test_stage_output.py
  • tests_python/test_stage_cli.py
  • .github/workflows/scripts/read_manifest.py
  • .github/workflows/scripts/determine_release_modes.py
  • tests_python/test_stage_common_config.py
  • tests_python/test_read_manifest.py
  • .github/actions/stage/scripts/stage_common/template_utils.py
  • .github/actions/stage/scripts/stage_common/staging/init.py
  • .github/actions/stage/scripts/stage_common/staging/output.py
  • .github/actions/stage/scripts/stage_common/github_output.py
  • .github/actions/stage/scripts/stage_common/staging/pipeline.py
  • scripts/_release_upload_deps.py
  • tests_python/test_stage_integration.py
  • tests_python/test_stage_config.py
  • tests_python/conftest.py
🧰 Additional context used
📓 Path-based instructions (4)
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: When new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve, proactively update the relevant file(s) in the docs/ directory to reflect the latest state.
Documentation must use en-GB-oxendict spelling and grammar ("-ize" / "-yse" / "-our"), with exception for the LICENSE filename.

docs/**/*.md: Use British English (en-GB) spelling with -ize endings (realize, organization), -lyse endings (analyse, paralyse, catalyse), -our endings (colour, behaviour), -re endings (calibre, centre, fibre), double 'l' (cancelled, counsellor), maintained 'e' (likeable, liveable), and -ogue endings (analogue, catalogue)
Use the Oxford comma in documentation: 'ships, planes, and hovercraft'
Treat company names as collective nouns in documentation: 'Concordat Industries are expanding'
Write headings in sentence case in documentation
Use Markdown headings (#, ##, ###) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
Provide code blocks and lists using standard Markdown syntax
Always provide a language identifier for fenced code blocks; use plaintext for non-code text
Use - as the first level bullet and renumber lists when items change in documentation
Prefer inline links using [text](url) or angle brackets around the URL in documentation
Ensure blank lines before and after bulleted lists and fenced blocks in documentation
Ensure tables have a delimiter line below the header row in documentation
Expand any uncommon acronym on first use in documentation (e.g., Continuous Integration (CI))
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use GitHub-flavoured numeric footnotes referenced as [^1] in documentation
Number footnotes in order of appearance in the document
Caption every table and every diagram in documentation
Use ![alt text](path/to/image) for embedding figures with brief alt te...

Files:

  • docs/netsuke-design.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns.
Code blocks in Markdown must be wrapped at 120 columns.
Tables and headings in Markdown must not be wrapped.
Use dashes (-) for list bullets in Markdown.
Use GitHub-flavoured Markdown footnotes ([^1]) for references and footnotes.

Files:

  • docs/netsuke-design.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/netsuke-design.md
docs/**/{README,readme,GUIDE,guide,*.md}

📄 CodeRabbit inference engine (docs/adr-001-replace-serde-yml-with-serde-saphyr.md)

Document in Netsuke's README and user guide that the project now supports YAML 1.2 (not YAML 1.1) and that duplicate keys in manifests are no longer permitted

Files:

  • docs/netsuke-design.md
docs/**/!(README).md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

Avoid first and second person personal pronouns outside the README.md file in documentation

Files:

  • docs/netsuke-design.md
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: release / build-linux (x86_64-unknown-linux-gnu, linux-amd64, amd64) / Build linux artefacts
  • GitHub Check: release / build-linux (aarch64-unknown-linux-gnu, linux-arm64, arm64) / Build linux artefacts
  • GitHub Check: release / build-macos (aarch64-apple-darwin, macos-15, macos-arm64, macos-aarch64) / Build macos artefacts
  • GitHub Check: release / build-macos (x86_64-apple-darwin, macos-15-intel, macos-x86_64, macos-x86_64) / Build macos artefacts
  • GitHub Check: release / build-windows (x86_64-pc-windows-msvc, amd64, x64, windows-x86_64) / Build windows artefacts
  • GitHub Check: release / build-windows (aarch64-pc-windows-msvc, arm64, arm64, windows-aarch64) / Build windows artefacts
  • GitHub Check: Sourcery review
  • GitHub Check: Sourcery review
🔇 Additional comments (12)
Makefile (1)

1-1: Verify no orphaned references to the removed typecheck target.

The removal aligns with eliminating Python tooling from the repository. Ensure that CI workflows and documentation do not invoke make typecheck.

Run the following script to verify no references remain:

#!/bin/bash
# Description: Search for references to the removed typecheck target.

# Search GitHub Actions workflows
echo "=== Checking GitHub Actions workflows ==="
fd -e yml -e yaml . .github/workflows/ --exec rg -n 'make\s+typecheck'

# Search documentation
echo "=== Checking documentation ==="
fd -e md . --exec rg -n 'make\s+typecheck|`typecheck`'

# Search for any other Makefile references
echo "=== Checking for typecheck references in all files ==="
rg -n '\btypecheck\b' -g '!Makefile'
.github/workflows/netsukefile-test.yml (1)

24-24: Verify the updated SHA is valid and consistent across workflows.

The SHA update aligns with the PR's goal of keeping shared-actions references current.

Run the following script to verify the new SHA exists in leynos/shared-actions and that setup-rust usage remains compatible:

#!/bin/bash
# Description: Verify the new shared-actions SHA exists and check consistency across workflows.

NEW_SHA="df81280dcc1d6e66134114dbc924313328b15f05"

# Verify SHA exists in leynos/shared-actions repository
echo "Checking if SHA exists in leynos/shared-actions..."
gh api repos/leynos/shared-actions/commits/$NEW_SHA --jq '.sha' || echo "ERROR: SHA not found"

# Check if setup-rust action exists at this commit
echo -e "\nChecking setup-rust action at new SHA..."
gh api repos/leynos/shared-actions/contents/.github/actions/setup-rust/action.yml?ref=$NEW_SHA --jq '.name' || echo "ERROR: Action not found at SHA"

# Verify consistency: check if this SHA is used consistently across all workflows
echo -e "\nSearching for any other shared-actions SHA references in workflows..."
rg -n "leynos/shared-actions.*@[a-f0-9]{40}" .github/workflows/ | grep -v "$NEW_SHA" || echo "All references use the new SHA"
.github/workflows/ci.yml (1)

24-24: Consistent SHA pinning across all shared actions is good practice.

All three action references (setup-rust, generate-coverage, upload-codescene-coverage) have been updated to the same commit SHA (df81280d...), which ensures consistency and aligns with the PR's goal to centralise and pin shared actions for reproducibility. Using explicit commit SHAs is a security best practice for GitHub Actions as it prevents supply chain attacks.

Verify that the new SHA exists in the leynos/shared-actions repository and that the actions at this commit are compatible with the current inputs and usage.

#!/bin/bash
# Description: Verify the new shared-actions commit exists and inspect changes.

# Check that the commit exists in leynos/shared-actions
echo "Checking if commit df81280dcc1d6e66134114dbc924313328b15f05 exists..."
gh api repos/leynos/shared-actions/commits/df81280dcc1d6e66134114dbc924313328b15f05 \
  --jq '{sha: .sha, author: .commit.author.name, date: .commit.author.date, message: .commit.message}' \
  2>/dev/null || echo "ERROR: Commit not found in leynos/shared-actions"

# Compare the old and new commits to check for breaking changes
echo -e "\n--- Comparing old (dd56f18c) vs new (df81280d) commits ---"
gh api repos/leynos/shared-actions/compare/dd56f18c...df81280d \
  --jq '{status: .status, ahead_by: .ahead_by, behind_by: .behind_by, total_commits: .total_commits, files_changed: [.files[].filename]}' \
  2>/dev/null || echo "ERROR: Unable to compare commits"

Also applies to: 43-43, 51-51

.github/workflows/release.yml (4)

63-66: LGTM: Output mappings correctly use bracket notation.

The dictionary-style output access with hyphenated keys is the correct GitHub Actions syntax for retrieving outputs from the shared actions.


78-79: Verify the shared-actions repository and pinned commit SHA.

Ensure that:

  1. The repository leynos/shared-actions is accessible from GitHub Actions runners
  2. The commit df81280dcc1d6e66134114dbc924313328b15f05 exists and contains the referenced actions
  3. The action inputs/outputs at that SHA match the usage in this workflow
#!/bin/bash
# Verify shared-actions repository and commit SHA exist

set -euo pipefail

REPO="leynos/shared-actions"
SHA="df81280dcc1d6e66134114dbc924313328b15f05"

echo "Checking if repository ${REPO} is accessible..."
gh repo view "${REPO}" --json nameWithOwner,isPrivate

echo -e "\nVerifying commit ${SHA} exists..."
gh api "repos/${REPO}/commits/${SHA}" --jq '.sha, .commit.message'

echo -e "\nChecking for action files at this commit..."
ACTIONS=(
  ".github/actions/determine-release-modes/action.yml"
  ".github/actions/ensure-cargo-version/action.yml"
  ".github/actions/export-cargo-metadata/action.yml"
  ".github/actions/upload-release-assets/action.yml"
)

for action in "${ACTIONS[@]}"; do
  echo "Checking ${action}..."
  gh api "repos/${REPO}/contents/${action}?ref=${SHA}" --jq '.name, .type' || echo "  ❌ Not found"
done

Also applies to: 83-83, 102-103, 216-217


85-85: LGTM: Correct use of fromJSON for boolean conversion.

The fromJSON function properly converts the string output from the shared action to a boolean value for the check-tag input.


105-105: Verify CARGO_TOML_PATH is defined in the repository.

Check whether CARGO_TOML_PATH is set as a repository variable, secret, or defined elsewhere in the workflows. If it's not used, simply remove the reference and use the default path.

#!/bin/bash
# Search for CARGO_TOML_PATH usage and definition

set -euo pipefail

echo "Searching for CARGO_TOML_PATH in workflow files..."
rg -n 'CARGO_TOML_PATH' -g '*.yml' -g '*.yaml' -C 3

echo -e "\nSearching for CARGO_TOML_PATH in environment files..."
rg -n 'CARGO_TOML_PATH' -g '.env*' -C 2 || echo "No .env files found with CARGO_TOML_PATH"

echo -e "\nChecking repository variables..."
gh api "repos/${GITHUB_REPOSITORY}/actions/variables" --jq '.variables[] | select(.name == "CARGO_TOML_PATH")'

echo -e "\nNote: Cannot check secrets directly, but if CARGO_TOML_PATH is not found above, consider removing the reference."
.github/workflows/build-and-package.yml (5)

82-82: Verify the shared-actions repository and pinned commit exist.

The workflow now depends on external actions from leynos/shared-actions. Confirm that the repository is accessible and the commit df81280dcc1d6e66134114dbc924313328b15f05 exists with the expected action definitions.

#!/bin/bash
# Description: Verify leynos/shared-actions repository and commit validity
set -euo pipefail

REPO="leynos/shared-actions"
SHA="df81280dcc1d6e66134114dbc924313328b15f05"

echo "Checking if repository ${REPO} exists..."
gh repo view "${REPO}" --json name,isArchived,isFork,visibility || {
  echo "ERROR: Repository ${REPO} not found or inaccessible"
  exit 1
}

echo "Checking if commit ${SHA} exists..."
gh api "repos/${REPO}/commits/${SHA}" --jq '.sha' || {
  echo "ERROR: Commit ${SHA} not found in ${REPO}"
  exit 1
}

echo "Verifying action paths exist at ${SHA}..."
ACTIONS=(
  ".github/actions/rust-build-release/action.yml"
  ".github/actions/linux-packages/action.yml"
  ".github/actions/stage-release-artefacts/action.yml"
  ".github/actions/windows-package/action.yml"
  ".github/actions/macos-package/action.yml"
)

for action in "${ACTIONS[@]}"; do
  echo "Checking ${action}..."
  gh api "repos/${REPO}/contents/${action}?ref=${SHA}" --jq '.name' || {
    echo "ERROR: Action ${action} not found at ${SHA}"
    exit 1
  }
done

echo "All actions verified successfully"

Also applies to: 90-90, 112-112, 121-121, 139-139


108-116: Verify the stage-release-artefacts action interface.

The normalize-windows-paths input is newly introduced and depends on the shared action's implementation. Confirm that the action at the pinned SHA accepts this input and that the output names (binary-path, license-path, man-path, artifact-dir) match the expected interface.

#!/bin/bash
# Description: Examine stage-release-artefacts action definition
set -euo pipefail

REPO="leynos/shared-actions"
SHA="df81280dcc1d6e66134114dbc924313328b15f05"
ACTION_PATH=".github/actions/stage-release-artefacts/action.yml"

echo "Fetching action definition..."
gh api "repos/${REPO}/contents/${ACTION_PATH}?ref=${SHA}" \
  --jq '.content' | base64 -d > /tmp/stage-action.yml

echo "Checking for normalize-windows-paths input..."
grep -q "normalize-windows-paths" /tmp/stage-action.yml || {
  echo "ERROR: normalize-windows-paths input not found"
  exit 1
}

echo "Checking for required outputs..."
REQUIRED_OUTPUTS=("binary-path" "license-path" "man-path" "artifact-dir")
for output in "${REQUIRED_OUTPUTS[@]}"; do
  grep -q "${output}:" /tmp/stage-action.yml || {
    echo "ERROR: Output ${output} not found in action definition"
    exit 1
  }
done

echo "Action interface verified successfully"
cat /tmp/stage-action.yml

126-127: Output references correctly updated to kebab-case format.

All stage output references use the new hyphenated naming convention consistently. The bracket notation with quotes (steps.stage.outputs['binary-path']) is the correct syntax for accessing hyphenated output keys.

Note: Line 127 maps license-path output to license-rtf-path input, implying the staged license file is already in RTF format. Verify that the staging action produces RTF-formatted licences for Windows.

Also applies to: 143-144, 176-176, 186-186


133-133: Spelling aligns with British English conventions.

The rename from upload-artifact to upload-artefact adopts British English spelling, consistent with the repository's nomenclature (e.g., "artefacts" in job names, output descriptions, and step names throughout the workflow).


108-187: Migration to shared staging action is complete and logically sound.

The refactoring correctly:

  • Preserves the Linux direct-packaging flow (bypassing staging)
  • Migrates Windows and macOS to use the shared staging action
  • Updates all output references to the new kebab-case format
  • Maintains conditional upload logic based on platform and workflow inputs

The workflow should function identically to the previous implementation, assuming the shared actions provide the expected interfaces.

Comment thread .github/workflows/build-and-package.yml
Comment thread .github/workflows/build-and-package.yml
Comment thread .github/workflows/release.yml
Comment thread .github/workflows/release.yml Outdated
Comment thread docs/netsuke-design.md Outdated
Comment thread docs/netsuke-design.md Outdated
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: f9bb5473b4

ℹ️ 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/workflows/build-and-package.yml Outdated
…sistency

Add new Rust-based tests to verify the wiring and behavior of the build-and-package, release, and shared-actions pinning workflows. These tests ensure workflows use shared actions correctly and maintain consistent action version pins to prevent drift. Also improve release workflow outputs verification and enhance robustness of workflow configuration validation.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
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

♻️ Duplicate comments (2)
.github/workflows/release.yml (1)

100-114: Approve the manifest path resolution; refine the step name.

The manifest_path step correctly works around GitHub Actions' lack of a || operator, and the subsequent use of steps.manifest_path.outputs.value is the proper pattern.

The step name "Export Cargo bin name" on line 108 is an improvement over the previous "Export Cargo metadata", but it remains slightly imprecise. The action extracts the binary name rather than exporting general metadata. Align the step name with the action's specific purpose.

🔎 Suggested refinement
       - id: bin_name
-        name: Export Cargo bin name
+        name: Extract binary name from Cargo.toml
         uses: >-
           leynos/shared-actions/.github/actions/export-cargo-metadata@df81280dcc1d6e66134114dbc924313328b15f05
tests/workflow_build_and_package.rs (1)

6-15: Extract duplicated helper to shared test utilities.

This function is identical to workflow_contents in tests/workflow_release.rs (lines 6-15). See the review comment on that file for the recommended refactor to extract this helper to a shared test utilities module.

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f9bb547 and 3068ccc.

📒 Files selected for processing (5)
  • .github/workflows/release.yml
  • docs/netsuke-design.md
  • tests/workflow_build_and_package.rs
  • tests/workflow_release.rs
  • tests/workflow_shared_actions_pins.rs
🧰 Additional context used
📓 Path-based instructions (5)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Clippy warnings MUST be disallowed in Rust code.
Fix any warnings emitted during Rust tests in the code itself rather than silencing them.
In Rust, extract meaningfully named helper functions when a function is too long, adhering to separation of concerns and CQRS.
In Rust, group related parameters in meaningfully named structs when a function has too many parameters.
In Rust, consider using Arc to reduce data returned when a function is returning a large error.
Every Rust module must begin with a module level (//!) comment explaining the module's purpose and utility.
Document public APIs in Rust using Rustdoc comments (///) so documentation can be generated with cargo doc.
In Rust, prefer immutable data and avoid unnecessary mut bindings.
In Rust, handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code in Rust unless absolutely necessary, and document any usage clearly.
In Rust, place function attributes after doc comments.
In Rust, do not use return in single-line functions.
In Rust, use predicate functions for conditional criteria with more than two branches.
Lints in Rust must not be silenced except as a last resort.
Lint rule suppressions in Rust must be tightly scoped and include a clear reason.
In Rust, prefer expect over allow.
In Rust tests, use rstest fixtures for shared setup.
In Rust tests, replace duplicated tests with #[rstest(...)] parameterized cases.
In Rust, prefer mockall for mocks and stubs.
In Rust, use concat!() to combine long string literals rather than escaping newlines with a backslash.
In Rust, prefer single line versions of functions where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) } instead of multi-line).
Use NewTypes in Rust to model domain values and eliminate 'integer soup'. Reach for newt-hype when introducing many homogeneous wrappers; add small shims for string-backed wrappers. For path-centric wrappers implement AsRef<Path> along...

Files:

  • tests/workflow_build_and_package.rs
  • tests/workflow_shared_actions_pins.rs
  • tests/workflow_release.rs

⚙️ CodeRabbit configuration file

**/*.rs: * Seek to keep the cognitive complexity of functions no more than 9.

  • Adhere to single responsibility and CQRS
  • Place function attributes after doc comments.
  • Do not use return in single-line functions.
  • Move conditionals with >2 branches into a predicate function.
  • Avoid unsafe unless absolutely necessary.
  • Every module must begin with a //! doc comment that explains the module's purpose and utility.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lints must not be silenced except as a last resort.
    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.
  • Replace duplicated tests with #[rstest(...)] parameterised cases.
  • Prefer mockall for mocks/stubs.
  • Prefer .expect() over .unwrap() in tests.
  • .expect() and .unwrap() are forbidden outside of tests. Errors must be propagated.
  • Ensure that any API or behavioural changes are reflected in the documentation in docs/
  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/
  • Files must not exceed 400 lines in length
    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such
    • For testing of functionality depending upon environment variables, dependency injection and...

Files:

  • tests/workflow_build_and_package.rs
  • tests/workflow_shared_actions_pins.rs
  • tests/workflow_release.rs
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: When new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve, proactively update the relevant file(s) in the docs/ directory to reflect the latest state.
Documentation must use en-GB-oxendict spelling and grammar ("-ize" / "-yse" / "-our"), with exception for the LICENSE filename.

docs/**/*.md: Use British English (en-GB) spelling with -ize endings (realize, organization), -lyse endings (analyse, paralyse, catalyse), -our endings (colour, behaviour), -re endings (calibre, centre, fibre), double 'l' (cancelled, counsellor), maintained 'e' (likeable, liveable), and -ogue endings (analogue, catalogue)
Use the Oxford comma in documentation: 'ships, planes, and hovercraft'
Treat company names as collective nouns in documentation: 'Concordat Industries are expanding'
Write headings in sentence case in documentation
Use Markdown headings (#, ##, ###) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
Provide code blocks and lists using standard Markdown syntax
Always provide a language identifier for fenced code blocks; use plaintext for non-code text
Use - as the first level bullet and renumber lists when items change in documentation
Prefer inline links using [text](url) or angle brackets around the URL in documentation
Ensure blank lines before and after bulleted lists and fenced blocks in documentation
Ensure tables have a delimiter line below the header row in documentation
Expand any uncommon acronym on first use in documentation (e.g., Continuous Integration (CI))
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use GitHub-flavoured numeric footnotes referenced as [^1] in documentation
Number footnotes in order of appearance in the document
Caption every table and every diagram in documentation
Use ![alt text](path/to/image) for embedding figures with brief alt te...

Files:

  • docs/netsuke-design.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns.
Code blocks in Markdown must be wrapped at 120 columns.
Tables and headings in Markdown must not be wrapped.
Use dashes (-) for list bullets in Markdown.
Use GitHub-flavoured Markdown footnotes ([^1]) for references and footnotes.

Files:

  • docs/netsuke-design.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/netsuke-design.md
docs/**/{README,readme,GUIDE,guide,*.md}

📄 CodeRabbit inference engine (docs/adr-001-replace-serde-yml-with-serde-saphyr.md)

Document in Netsuke's README and user guide that the project now supports YAML 1.2 (not YAML 1.1) and that duplicate keys in manifests are no longer permitted

Files:

  • docs/netsuke-design.md
docs/**/!(README).md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

Avoid first and second person personal pronouns outside the README.md file in documentation

Files:

  • docs/netsuke-design.md
🧠 Learnings (2)
📚 Learning: 2025-12-29T19:00:20.890Z
Learnt from: leynos
Repo: leynos/netsuke PR: 251
File: tests/bdd/types.rs:309-318
Timestamp: 2025-12-29T19:00:20.890Z
Learning: In the netsuke repository, rustfmt formatting rules take precedence over manual formatting preferences. Ensure that functions like HelperName::as_str() and From trait implementations remain in multi-line format as enforced by cargo fmt, even if internal coding guidelines suggest single-line forms, to avoid breaking make check-fmt.

Applied to files:

  • tests/workflow_build_and_package.rs
  • tests/workflow_shared_actions_pins.rs
  • tests/workflow_release.rs
📚 Learning: 2026-01-03T20:51:29.799Z
Learnt from: leynos
Repo: leynos/netsuke PR: 253
File: .github/workflows/build-and-package.yml:82-82
Timestamp: 2026-01-03T20:51:29.799Z
Learning: In GitHub Actions workflows, the uses: value must be a static string (no runtime interpolation). Do not use expressions like ${{ env.VARIABLE }} or ${{ vars.VARIABLE }} inside uses:. This ensures deterministic action references and supports policy enforcement. If you need to parameterize actions, use inputs or job-level variables, not dynamic action references.

Applied to files:

  • .github/workflows/release.yml
🧬 Code graph analysis (2)
tests/workflow_build_and_package.rs (1)
tests/workflow_release.rs (1)
  • workflow_contents (6-15)
tests/workflow_release.rs (1)
tests/workflow_build_and_package.rs (1)
  • workflow_contents (6-15)
🔍 Remote MCP

Let me search for more specific information about the terragon project and the specific actions being used:Based on the comprehensive pull request context provided, I can now offer a summary of relevant facts that would help in reviewing this PR:

Relevant Context for PR #253 Review

Architecture & Pattern

This PR implements a common GitHub Actions best practice: centralizing custom actions by storing them in a separate repository and calling them from other repositories, allowing actions and reusable workflows to be shared with organizations without publishing them publicly.

Scope of Changes

The refactoring consolidates local implementation logic into external shared actions from leynos/shared-actions. Key removals include:

  1. Local GitHub Actions: Three composite actions removed:

    • export-bin-name: Derived binary names from Cargo.toml via inline Python
    • stage (composite): Coordinated artifact staging with TOML configuration
    • upload-release-assets: Discovered and validated release artifacts for upload
  2. Python Helper Scripts: Complete removal of workflow orchestration scripts:

    • determine_release_modes.py: Release mode logic (dry-run, publish flags)
    • normalise_windows_paths.py: Windows path normalization
    • read_manifest.py: Cargo manifest field extraction
    • upload_release_assets.py: Release artifact upload CLI
  3. Staging Pipeline Package: Entire stage_common Python package removed, including:

    • Configuration loaders and validators
    • Artifact resolution and templating utilities
    • GitHub Actions output formatting
    • Filesystem safety checks and glob utilities
    • Checksum computation
  4. Tests: Corresponding test files deleted (~15 test modules covering configuration, staging, output formatting, and Windows path normalization)

Workflow Updates

build-and-package.yml:

  • Replaces local staging with leynos/shared-actions/.github/actions/stage-release-artefacts
  • Removes separate Windows path normalization step
  • Updates output references to use new naming convention (e.g., binary_pathbinary-path)

release.yml:

  • Replaces Python helpers with shared actions:
    • determine-release-modes (release mode detection)
    • ensure-cargo-version (version management)
    • export-cargo-metadata (manifest introspection, replaces read_manifest.py)
    • upload-release-assets (replaces local Python script)
  • Removes Setup Python 3.11 step previously used for Python helpers

CI Workflows (ci.yml, netsukefile-test.yml):

  • Updates action references to pinned shared-actions commits for consistency

Testing & Validation

Three new Rust-based test files validate the refactoring:

  • tests/workflow_build_and_package.rs: Verifies build-and-package workflow wiring (stage action outputs, path references)
  • tests/workflow_release.rs: Validates release workflow uses shared actions and exports correct fields
  • tests/workflow_shared_actions_pins.rs: Enforces consistent action pinning across all workflows

Risk Considerations for Review

  1. Dependency on External Repository: All release and packaging logic now depends on leynos/shared-actions being accessible and maintained. Pinned SHAs reduce flexibility but ensure reproducibility.

  2. Behavioral Equivalence: The PR claims no intended functional behavior changes—shared actions should replicate local implementations exactly. Verify:

    • Output field names and formats match (especially binary-path, man-path, artifact-dir)
    • Windows path normalization behavior is equivalent
    • Artifact discovery and checksumming logic remains consistent
  3. Removed Python Dependencies: No longer requires Python environment for workflows (except shared actions internally). Makefile's typecheck target removed—verify type checking is handled elsewhere if needed.

  4. Integration Points: Windows packaging and packaging step inputs now depend on shared action outputs; verify all downstream references are correctly updated.

[::web_search::] for shared actions pattern documentation

⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: release / build-macos (x86_64-apple-darwin, macos-15-intel, macos-x86_64, macos-x86_64) / Build macos artefacts
  • GitHub Check: release / build-linux (x86_64-unknown-linux-gnu, linux-amd64, amd64) / Build linux artefacts
  • GitHub Check: release / build-linux (aarch64-unknown-linux-gnu, linux-arm64, arm64) / Build linux artefacts
  • GitHub Check: release / build-windows (x86_64-pc-windows-msvc, amd64, x64, windows-x86_64) / Build windows artefacts
  • GitHub Check: release / build-windows (aarch64-pc-windows-msvc, arm64, arm64, windows-aarch64) / Build windows artefacts
  • GitHub Check: Sourcery review
  • GitHub Check: build-test (ubuntu-latest, 1.89.0)
  • GitHub Check: build-test (ubuntu-latest, stable)
  • GitHub Check: build-test (ubuntu-latest, nightly, true)
🔇 Additional comments (8)
docs/netsuke-design.md (1)

2051-2137: Release automation sections are well-structured and documentation guidelines are met.

The section properly expands all acronyms on first use (Tom's Obvious, Minimal Language (TOML), Astral's Python package manager (uv), Windows Installer XML (WiX), Rich Text Format (RTF), Microsoft Installer (MSI)), maintains consistent 80-column paragraph wrapping, and uses en-GB spelling throughout ("artefacts", "licence"). The technical narrative of the shared-actions refactoring, staging pipeline, and cross-platform packaging flows is clear and accurate.

.github/workflows/release.yml (2)

63-66: LGTM: Dictionary-key access pattern correctly applied.

The migration to dictionary-key access for action outputs (steps.bin_name.outputs['bin-name'], steps.release_modes.outputs['should-publish'], etc.) follows the correct GitHub Actions pattern. The fromJSON conversion on line 85 properly transforms the string output to a boolean for the check-tag input.

Also applies to: 78-85


223-224: LGTM: Shared upload action properly integrated.

The migration to leynos/shared-actions/.github/actions/upload-release-assets is correctly configured with the necessary inputs (release-tag, bin-name, dist-dir) and environment variables. The SHA pinning ensures reproducibility.

tests/workflow_release.rs (1)

17-74: LGTM: Tests correctly validate workflow wiring.

The three test functions thoroughly verify that the release workflow uses the shared actions correctly, exports the bin-name field, and wires the release_modes outputs to downstream steps. The assertion messages provide clear diagnostics when failures occur.

tests/workflow_shared_actions_pins.rs (3)

7-18: LGTM: Helper functions appropriately scoped.

The repo_root, workflow_dir, and read_workflow helpers provide clean abstractions for locating and reading workflow files. The read_workflow function's panic message provides clear diagnostics when file access fails.


20-37: LGTM: Pin extraction logic correctly implemented.

The extract_shared_actions_pins function correctly parses workflow YAML lines to extract commit SHAs following the @ delimiter. The use of filter_map with appropriate edge-case handling (whitespace trimming, empty value filtering) ensures robust extraction.


39-78: LGTM: Tests enforce consistent pinning policy.

The unit test provides regression coverage for the pin extraction logic, whilst the behavioural test enforces that all shared-actions references across workflows use identical commit SHAs. The use of BTreeSet for uniqueness checking provides deterministic diagnostics when pins diverge.

tests/workflow_build_and_package.rs (1)

17-53: LGTM: Test comprehensively validates workflow integration.

The test verifies that build-and-package.yml correctly integrates with the shared stage-release-artefacts action, consumes its outputs (binary-path, license-path, man-path, artifact-dir), and properly gates Windows-specific behaviour. The assertion messages provide clear diagnostics for each integration point.

Comment thread tests/workflow_release.rs Outdated
- Introduce a dedicated step to capture staging outputs as 'stage_paths'
- Update build-and-package workflow to use unified 'stage_paths' outputs
- Minor naming cleanup in release workflow
- Add common test utilities for reading workflow files
- Update tests to use common utilities and verify path output usage

This improves clarity and maintenance of artifact paths usage across OS platforms in CI.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
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

♻️ Duplicate comments (1)
.github/workflows/build-and-package.yml (1)

111-112: Single-line uses: is preferred for consistency.

The >- block scalar for the uses: field works but is unconventional compared to other action references in this workflow. Flatten to a single line for consistency.

🔎 Proposed simplification
-        uses: >-
-          leynos/shared-actions/.github/actions/stage-release-artefacts@df81280dcc1d6e66134114dbc924313328b15f05
+        uses: leynos/shared-actions/.github/actions/stage-release-artefacts@df81280dcc1d6e66134114dbc924313328b15f05
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3068ccc and 9d86529.

📒 Files selected for processing (5)
  • .github/workflows/build-and-package.yml
  • .github/workflows/release.yml
  • tests/common/mod.rs
  • tests/workflow_build_and_package.rs
  • tests/workflow_release.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Clippy warnings MUST be disallowed in Rust code.
Fix any warnings emitted during Rust tests in the code itself rather than silencing them.
In Rust, extract meaningfully named helper functions when a function is too long, adhering to separation of concerns and CQRS.
In Rust, group related parameters in meaningfully named structs when a function has too many parameters.
In Rust, consider using Arc to reduce data returned when a function is returning a large error.
Every Rust module must begin with a module level (//!) comment explaining the module's purpose and utility.
Document public APIs in Rust using Rustdoc comments (///) so documentation can be generated with cargo doc.
In Rust, prefer immutable data and avoid unnecessary mut bindings.
In Rust, handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code in Rust unless absolutely necessary, and document any usage clearly.
In Rust, place function attributes after doc comments.
In Rust, do not use return in single-line functions.
In Rust, use predicate functions for conditional criteria with more than two branches.
Lints in Rust must not be silenced except as a last resort.
Lint rule suppressions in Rust must be tightly scoped and include a clear reason.
In Rust, prefer expect over allow.
In Rust tests, use rstest fixtures for shared setup.
In Rust tests, replace duplicated tests with #[rstest(...)] parameterized cases.
In Rust, prefer mockall for mocks and stubs.
In Rust, use concat!() to combine long string literals rather than escaping newlines with a backslash.
In Rust, prefer single line versions of functions where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) } instead of multi-line).
Use NewTypes in Rust to model domain values and eliminate 'integer soup'. Reach for newt-hype when introducing many homogeneous wrappers; add small shims for string-backed wrappers. For path-centric wrappers implement AsRef<Path> along...

Files:

  • tests/common/mod.rs
  • tests/workflow_release.rs
  • tests/workflow_build_and_package.rs

⚙️ CodeRabbit configuration file

**/*.rs: * Seek to keep the cognitive complexity of functions no more than 9.

  • Adhere to single responsibility and CQRS
  • Place function attributes after doc comments.
  • Do not use return in single-line functions.
  • Move conditionals with >2 branches into a predicate function.
  • Avoid unsafe unless absolutely necessary.
  • Every module must begin with a //! doc comment that explains the module's purpose and utility.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lints must not be silenced except as a last resort.
    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.
  • Replace duplicated tests with #[rstest(...)] parameterised cases.
  • Prefer mockall for mocks/stubs.
  • Prefer .expect() over .unwrap() in tests.
  • .expect() and .unwrap() are forbidden outside of tests. Errors must be propagated.
  • Ensure that any API or behavioural changes are reflected in the documentation in docs/
  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/
  • Files must not exceed 400 lines in length
    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such
    • For testing of functionality depending upon environment variables, dependency injection and...

Files:

  • tests/common/mod.rs
  • tests/workflow_release.rs
  • tests/workflow_build_and_package.rs
🧠 Learnings (2)
📚 Learning: 2025-12-29T19:00:20.890Z
Learnt from: leynos
Repo: leynos/netsuke PR: 251
File: tests/bdd/types.rs:309-318
Timestamp: 2025-12-29T19:00:20.890Z
Learning: In the netsuke repository, rustfmt formatting rules take precedence over manual formatting preferences. Ensure that functions like HelperName::as_str() and From trait implementations remain in multi-line format as enforced by cargo fmt, even if internal coding guidelines suggest single-line forms, to avoid breaking make check-fmt.

Applied to files:

  • tests/common/mod.rs
  • tests/workflow_release.rs
  • tests/workflow_build_and_package.rs
📚 Learning: 2026-01-03T20:51:29.799Z
Learnt from: leynos
Repo: leynos/netsuke PR: 253
File: .github/workflows/build-and-package.yml:82-82
Timestamp: 2026-01-03T20:51:29.799Z
Learning: In GitHub Actions workflows, the uses: value must be a static string (no runtime interpolation). Do not use expressions like ${{ env.VARIABLE }} or ${{ vars.VARIABLE }} inside uses:. This ensures deterministic action references and supports policy enforcement. If you need to parameterize actions, use inputs or job-level variables, not dynamic action references.

Applied to files:

  • .github/workflows/release.yml
  • .github/workflows/build-and-package.yml
🧬 Code graph analysis (2)
tests/workflow_release.rs (1)
tests/common/mod.rs (1)
  • workflow_contents (39-44)
tests/workflow_build_and_package.rs (2)
tests/common/mod.rs (1)
  • workflow_contents (39-44)
src/stdlib/which/lookup/workspace/mod.rs (1)
  • contains (44-46)
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: release / build-windows (aarch64-pc-windows-msvc, arm64, arm64, windows-aarch64) / Build windows artefacts
  • GitHub Check: release / build-linux (x86_64-unknown-linux-gnu, linux-amd64, amd64) / Build linux artefacts
  • GitHub Check: release / build-macos (x86_64-apple-darwin, macos-15-intel, macos-x86_64, macos-x86_64) / Build macos artefacts
  • GitHub Check: release / build-linux (aarch64-unknown-linux-gnu, linux-arm64, arm64) / Build linux artefacts
  • GitHub Check: release / build-windows (x86_64-pc-windows-msvc, amd64, x64, windows-x86_64) / Build windows artefacts
  • GitHub Check: Sourcery review
  • GitHub Check: build-test (ubuntu-latest, nightly, true)
  • GitHub Check: build-test (ubuntu-latest, 1.89.0)
  • GitHub Check: build-test (ubuntu-latest, stable)
🔇 Additional comments (5)
tests/workflow_build_and_package.rs (1)

1-43: LGTM!

The test correctly validates the build-and-package workflow wiring by checking for expected shared action references and output mappings. The helper extraction to common::workflow_contents addresses the prior duplication concern.

tests/workflow_release.rs (1)

1-64: LGTM!

The tests comprehensively validate the release workflow's shared action wiring, bin-name export flow, and release modes output mapping. The refactored helper usage via common::workflow_contents eliminates the previously flagged duplication.

.github/workflows/build-and-package.yml (2)

118-129: Good approach to bridge output naming conventions.

The stage_paths step effectively translates from the shared action's hyphenated output names (binary-path, man-path, etc.) to underscore-based names (binary_path, man_path) for consumption by downstream steps. This addresses the naming mismatch concern raised in prior review.


82-82: Ensure all shared action references maintain consistent SHA pinning.

All five shared action references correctly use the same SHA df81280dcc1d6e66134114dbc924313328b15f05:

  • rust-build-release (line 82)
  • linux-packages (line 90)
  • stage-release-artefacts (line 112)
  • windows-package (line 134)
  • macos-package (line 152)

This approach maintains reproducibility across the workflow.

.github/workflows/release.yml (1)

78-79: All shared-actions references consistently pinned to single SHA.

Four shared actions reference df81280dcc1d6e66134114dbc924313328b15f05:

  • determine-release-modes (line 79)
  • ensure-cargo-version (line 83)
  • export-cargo-metadata (line 110)
  • upload-release-assets (line 224)

This consistency is correct. The uses: field cannot be parameterised, so the duplication is necessary. Workflow wiring is sound.

Comment thread tests/common/mod.rs Outdated
Comment thread tests/common/mod.rs Outdated
- Changed workflow_contents to return Result with context on error
- Added unit tests to verify reading of release.yml workflow file
- Added unit tests for build fixtures in common helpers
- Updated multiple test modules to use new workflow_contents signature and add tests
- Improves test coverage and error handling in common test utilities

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jan 4, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jan 4, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jan 4, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

♻️ Duplicate comments (2)
tests/runner_tool_subcommands_tests.rs (1)

71-74: Remove duplicate test.

This test is identical to the one in tests/runner_tests.rs (lines 65-68) and should be removed along with that one. See the review comment on tests/runner_tests.rs for the consolidation proposal.

tests/workflow_build_and_package.rs (1)

46-50: Remove unused fixture test.

This test exercises fixtures that aren't used by the workflow validation test in this file. See the identical issue and fix proposal in tests/workflow_release.rs (lines 66-70).

🔎 Proposed fix
-#[test]
-fn unit_common_helpers_build_fixtures() {
-    let _fixture = create_test_manifest().expect("test manifest fixture should build");
-    let _ninja = ninja_with_exit_code(0).expect("fake ninja fixture should build");
-}

Also remove the unused imports:

-use common::{create_test_manifest, ninja_with_exit_code, workflow_contents};
+use common::workflow_contents;
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d86529 and 6c9775b.

📒 Files selected for processing (5)
  • tests/common/mod.rs
  • tests/runner_tests.rs
  • tests/runner_tool_subcommands_tests.rs
  • tests/workflow_build_and_package.rs
  • tests/workflow_release.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Clippy warnings MUST be disallowed in Rust code.
Fix any warnings emitted during Rust tests in the code itself rather than silencing them.
In Rust, extract meaningfully named helper functions when a function is too long, adhering to separation of concerns and CQRS.
In Rust, group related parameters in meaningfully named structs when a function has too many parameters.
In Rust, consider using Arc to reduce data returned when a function is returning a large error.
Every Rust module must begin with a module level (//!) comment explaining the module's purpose and utility.
Document public APIs in Rust using Rustdoc comments (///) so documentation can be generated with cargo doc.
In Rust, prefer immutable data and avoid unnecessary mut bindings.
In Rust, handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code in Rust unless absolutely necessary, and document any usage clearly.
In Rust, place function attributes after doc comments.
In Rust, do not use return in single-line functions.
In Rust, use predicate functions for conditional criteria with more than two branches.
Lints in Rust must not be silenced except as a last resort.
Lint rule suppressions in Rust must be tightly scoped and include a clear reason.
In Rust, prefer expect over allow.
In Rust tests, use rstest fixtures for shared setup.
In Rust tests, replace duplicated tests with #[rstest(...)] parameterized cases.
In Rust, prefer mockall for mocks and stubs.
In Rust, use concat!() to combine long string literals rather than escaping newlines with a backslash.
In Rust, prefer single line versions of functions where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) } instead of multi-line).
Use NewTypes in Rust to model domain values and eliminate 'integer soup'. Reach for newt-hype when introducing many homogeneous wrappers; add small shims for string-backed wrappers. For path-centric wrappers implement AsRef<Path> along...

Files:

  • tests/workflow_build_and_package.rs
  • tests/workflow_release.rs
  • tests/runner_tests.rs
  • tests/common/mod.rs
  • tests/runner_tool_subcommands_tests.rs

⚙️ CodeRabbit configuration file

**/*.rs: * Seek to keep the cognitive complexity of functions no more than 9.

  • Adhere to single responsibility and CQRS
  • Place function attributes after doc comments.
  • Do not use return in single-line functions.
  • Move conditionals with >2 branches into a predicate function.
  • Avoid unsafe unless absolutely necessary.
  • Every module must begin with a //! doc comment that explains the module's purpose and utility.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lints must not be silenced except as a last resort.
    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.
  • Replace duplicated tests with #[rstest(...)] parameterised cases.
  • Prefer mockall for mocks/stubs.
  • Prefer .expect() over .unwrap() in tests.
  • .expect() and .unwrap() are forbidden outside of tests. Errors must be propagated.
  • Ensure that any API or behavioural changes are reflected in the documentation in docs/
  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/
  • Files must not exceed 400 lines in length
    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such
    • For testing of functionality depending upon environment variables, dependency injection and...

Files:

  • tests/workflow_build_and_package.rs
  • tests/workflow_release.rs
  • tests/runner_tests.rs
  • tests/common/mod.rs
  • tests/runner_tool_subcommands_tests.rs
🧠 Learnings (1)
📚 Learning: 2025-12-29T19:00:20.890Z
Learnt from: leynos
Repo: leynos/netsuke PR: 251
File: tests/bdd/types.rs:309-318
Timestamp: 2025-12-29T19:00:20.890Z
Learning: In the netsuke repository, rustfmt formatting rules take precedence over manual formatting preferences. Ensure that functions like HelperName::as_str() and From trait implementations remain in multi-line format as enforced by cargo fmt, even if internal coding guidelines suggest single-line forms, to avoid breaking make check-fmt.

Applied to files:

  • tests/workflow_build_and_package.rs
  • tests/workflow_release.rs
  • tests/runner_tests.rs
  • tests/common/mod.rs
  • tests/runner_tool_subcommands_tests.rs
🧬 Code graph analysis (2)
tests/workflow_release.rs (1)
tests/common/mod.rs (3)
  • create_test_manifest (17-23)
  • ninja_with_exit_code (29-36)
  • workflow_contents (39-44)
tests/runner_tool_subcommands_tests.rs (2)
tests/common/mod.rs (2)
  • create_test_manifest (17-23)
  • workflow_contents (39-44)
tests/runner_tests.rs (1)
  • unit_workflow_contents_reads_release_workflow (66-68)
🔍 Remote MCP Deepwiki

Let me search for information about composite actions and their benefits for workflow refactoring:

Summary of Relevant Context for PR Review

SHA Pinning Best Practices

Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release. The PR's approach of pinning shared actions to specific SHAs (like 9b84b9fda7ac050cc5565bfa065740bf73b50c30) aligns with security best practices. Pinning an action to a full-length commit SHA is currently the only way to use an action as an immutable release.

Why this matters for the PR: The workflow files now use full SHA pins across all shared-actions references (e.g., determine-release-modes@9b84b9f..., stage-release-artefacts@...), which provides reproducibility and protects against tag mutations.

Composite Actions vs. Reusable Workflows

The PR uses reusable actions from leynos/shared-actions. Understanding the architectural choice:

  • Composite actions are designed to encapsulate a sequence of actions into a singular, reusable entity, enhancing the modularity and efficiency of workflows.
  • Reusable workflows and composite actions both help you avoid duplicating workflow content. Whereas reusable workflows allow you to reuse an entire workflow, with multiple jobs and steps, composite actions combine multiple steps that you can then run within a job step, just like any other action.

Implication: The refactoring centralizes workflow logic in a shared repository, reducing maintenance burden and ensuring consistency across multiple projects.

Transitive Dependency Security Considerations

A notable concern when adopting shared actions: Research on JavaScript Actions found that 54% contain at least one security weakness, with most vulnerabilities coming from indirect dependencies. Additionally, the addition of composite actions and reusable workflows created a dependency system, but the implementation ignored lessons from package management: lockfiles, integrity verification, transitive pinning, dependency visibility.

Recommendation for review: While SHA pinning mitigates direct action tampering, verify that the shared actions repository (leynos/shared-actions) and its internal dependencies are well-maintained and trusted. Consider establishing a dependency management strategy for the shared actions themselves.

Workflow Output Mapping Changes

The PR refactors output references from property-style access (e.g., steps.bin_name.outputs.value) to dictionary-key access (e.g., steps.bin_name.outputs['bin-name']). This aligns with modern GitHub Actions syntax and improves consistency when shared actions export outputs via standardized naming conventions.

Key Test Coverage Points

The PR adds tests that validate:

  • Shared action wiring (e.g., verifying stage-release-artefacts is invoked)
  • Consistent SHA pinning across all workflows
  • Workflow output field availability and naming consistency

This provides confidence that the refactoring maintains functional parity with the original implementation.

[::web_search::],,

⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (5)
tests/common/mod.rs (1)

38-44: LGTM!

The helper properly returns Result<String> and propagates errors with context, addressing the previous review feedback. The implementation correctly uses env!("CARGO_MANIFEST_DIR") to locate workflow files and provides clear error messages.

tests/workflow_release.rs (3)

7-27: LGTM!

The test properly validates that the release workflow references the expected shared actions: determine-release-modes, ensure-cargo-version, export-cargo-metadata, and upload-release-assets. The assertions align with the PR's objective to centralize workflow logic in shared actions.


29-41: LGTM!

The test correctly verifies that bin-name field export is configured and properly wired through to the upload-release-assets action via the needs.metadata.outputs.bin_name reference.


43-64: LGTM!

The test thoroughly validates the release mode outputs wiring, checking that should-publish, dry-run, and should-upload-workflow-artifacts are captured from the shared action's dictionary-style outputs and properly referenced in the workflow.

tests/workflow_build_and_package.rs (1)

7-44: LGTM!

The test comprehensively validates the build-and-package workflow wiring:

  • Confirms usage of the shared stage-release-artefacts action
  • Verifies Windows path normalisation logic
  • Checks that staged outputs (binary_path, license_path, man_path, artifact_dir) are properly consumed by downstream steps

The assertions align well with the PR's refactoring objectives.

Comment thread tests/runner_tests.rs Outdated
Comment thread tests/workflow_release.rs Outdated
…r tests

- Moved shared fixtures (create_test_manifest and ninja_with_exit_code) from tests/common/mod.rs to new tests/fixtures/mod.rs
- Updated runner_tests.rs and runner_tool_subcommands_tests.rs to use fixtures module
- Simplified tests/common/mod.rs to contain only workflow validation helpers
- Removed duplicate tests verifying workflow_contents in multiple test files

This separation clarifies the distinction between general workflow helpers and runner-specific fixtures, improving code organization and reducing duplication.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos merged commit cf36eee into main Jan 4, 2026
16 checks passed
@leynos leynos deleted the terragon/refactor-release-workflow-shared-actions-x1sf00 branch January 4, 2026 20:44
leynos added a commit that referenced this pull request Jan 15, 2026
The rust-build-release shared action only accepts target, project-dir,
and bin-name inputs. The version parameter was incorrectly passed during
the PR #253 refactor, causing the CI warning "Unexpected input(s)
'version'" and subsequent "Unable to locate executable file: undefined"
error during macOS builds.

The version input remains correctly passed to packaging actions
(macos-package, windows-package, linux-packages) where it is a valid
parameter.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
leynos added a commit that referenced this pull request Jan 16, 2026
* Remove invalid version input from rust-build-release action

The rust-build-release shared action only accepts target, project-dir,
and bin-name inputs. The version parameter was incorrectly passed during
the PR #253 refactor, causing the CI warning "Unexpected input(s)
'version'" and subsequent "Unable to locate executable file: undefined"
error during macOS builds.

The version input remains correctly passed to packaging actions
(macos-package, windows-package, linux-packages) where it is a valid
parameter.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update shared-actions to bd92b1e for macOS x86_64 sccache fix

Updates shared-actions pin from df81280dcc to bd92b1e6f7. The new
version includes a fix for sccache no longer being published for
macOS x86_64, which was causing the "Unable to locate executable file:
undefined" error during macOS builds.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update shared-actions to bd92b1e for macOS x86_64 sccache fix

Updates shared-actions pin from df81280dcc to bd92b1e6f7. The new
version includes a fix for sccache no longer being published for
macOS x86_64, which was causing the "Unable to locate executable file:
undefined" error during macOS builds.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Update shared-actions to 7f4cc57 for macOS build fix

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
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