Skip to content

Expose PowerShell help staging output#265

Merged
leynos merged 28 commits into
mainfrom
feat/powershell-help-dir-output
May 19, 2026
Merged

Expose PowerShell help staging output#265
leynos merged 28 commits into
mainfrom
feat/powershell-help-dir-output

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented May 13, 2026

Summary

This branch extends stage-release-artefacts so callers that stage PowerShell MAML sidecars can receive a dedicated powershell_help_dir output instead of reconstructing the staged module path themselves. It also keeps MSI embedding outwith this change: windows-package only receives a TODO that points to the follow-up enhancement issue.

Follow-up issue: #264.

Review walkthrough

Validation

  • uv run pytest .github/actions/stage-release-artefacts/tests/test_stage.py 2>&1 | tee /tmp/stage-release-artefacts-focused-powershell-help-dir.out: passed, 36 passed.
  • make check-fmt 2>&1 | tee /tmp/shared-actions-check-fmt-powershell-help-dir.out: passed.
  • make typecheck 2>&1 | tee /tmp/shared-actions-typecheck-powershell-help-dir.out: passed.
  • make test 2>&1 | tee /tmp/shared-actions-test-powershell-help-dir.out: passed, 697 passed and 93 skipped.
  • make lint 2>&1 | tee /tmp/shared-actions-lint-powershell-help-dir.out: passed.
  • grep -r 'powershell_help_dir' .github/actions/stage-release-artefacts/: confirmed action metadata, README, tests and implementation references.
  • grep -RIn "ps-help-dir\|powershell_help_dir\|powershell-help" .github/actions/windows-package || true: confirmed windows-package only contains the TODO and no new input wiring.

Notes

This branch deliberately uses the explicit ps-module-name input rather than heuristic module-name detection. The action only exports powershell_help_dir when at least one artefact is staged under artifact_dir/<module>, so non-Windows callers can leave the input empty and receive an empty output.

Summary by Sourcery

Expose a new PowerShell help directory output from the stage-release-artefacts action and support a short dest alias in artefact configs while keeping behaviour safe and backwards compatible.

New Features:

  • Add ps-module-name input and powershell_help_dir output to the stage-release-artefacts action so workflows can consume staged PowerShell module sidecars directly.
  • Expose the staged PowerShell module directory path via the Python staging pipeline and CLI, including propagation into GitHub Action outputs.

Enhancements:

  • Allow artefact configuration entries to use a dest alias for destination while rejecting configurations that specify both destination and dest to prevent ambiguity.
  • Document configuration and usage patterns for staging PowerShell MAML sidecar artefacts, including examples for multi-platform workflows.
  • Extend reserved output key validation and output preparation to account for the new powershell_help_dir field.

Documentation:

  • Update the stage-release-artefacts README with documentation and examples for ps-module-name, powershell_help_dir, and PowerShell MAML sidecar staging.
  • Annotate the windows-package action with a TODO documenting future MSI PowerShell help embedding support.

Tests:

  • Add tests covering dest alias handling, validation of conflicting destination keys, PowerShell help directory staging on Windows, optional sidecars on non-Windows platforms, and behaviour when no module name is provided.

Add an explicit `ps-module-name` input to `stage-release-artefacts` and
export `powershell_help_dir` when matching sidecar files are staged beneath
that module directory.

Accept `dest` as a TOML alias for `destination` so target-specific
PowerShell artefact entries can use the documented compact shape. Keep
`windows-package` unchanged apart from a TODO that tracks future MSI
embedding work in issue #264.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d26536ec-3607-4f0c-a77e-f06351301deb

📥 Commits

Reviewing files that changed from the base of the PR and between 2126f64 and 55db24e.

📒 Files selected for processing (4)
  • .github/actions/stage-release-artefacts/scripts/stage_common/pipeline.py
  • .github/actions/stage-release-artefacts/tests/test_pipeline.py
  • .github/actions/stage-release-artefacts/tests/test_stage_cli.py
  • docs/developers-guide.md

Walkthrough

Add optional ps-module-name input and powershell_help_dir output; support dest alias; refactor outputs into StagingOutputData; centralise artefact collection; resolve PowerShell help directory with safety checks; add focused tests and a Windows workflow job.

Changes

PowerShell Module Sidecar Support

Layer / File(s) Summary
Action interface and documentation
.github/actions/stage-release-artefacts/action.yml, .github/actions/stage-release-artefacts/README.md, .github/actions/windows-package/action.yml, docs/adr/0002-explicit-ps-module-name.md
Add ps-module-name input and powershell_help_dir output; document PowerShell MAML sidecar rules and destination/dest alias; include ADR and README guidance.
CLI wiring and logging
.github/actions/stage-release-artefacts/scripts/stage.py
Add ps_module_name kwarg to main(), initialise logging and correlation id, emit warnings for skipped optional artefacts, and centralise writing workflow outputs via _write_stage_outputs.
Pipeline core: artefact collection & PowerShell resolution
.github/actions/stage-release-artefacts/scripts/stage_common/pipeline.py
Turn stage_artefacts() into a pure pipeline returning StageResult; centralise staging into _collect_artefacts; extend StageResult with powershell_help_dir and skipped_artefacts; implement _resolve_powershell_help_dir() with validation and staging-root escape prevention.
Output dataclass and writer helpers
.github/actions/stage-release-artefacts/scripts/stage_common/output.py, .github/actions/stage-release-artefacts/tests/test_output.py
Introduce StagingOutputData dataclass; reserve powershell_help_dir; refactor prepare_output_data() to accept the dataclass and serialise powershell_help_dir (empty string when unset); add writer and reserved-key tests.
Configuration loading and dest alias
.github/actions/stage-release-artefacts/scripts/stage_common/config.py, .github/actions/stage-release-artefacts/tests/test_config.py
Require caller-supplied workspace in load_config; remove internal env lookup; accept dest as alias for destination and error when both are present; add tests for parsing, defaults and error cases.
Tests: env, resolution, pipeline and CLI snapshots
.github/actions/stage-release-artefacts/tests/*, tests/workflows/test_action_behaviors.py
Add focused tests for require_env_path, match_candidate_path, pipeline behaviour including PowerShell resolution, output serialisation, CLI snapshot tests for powershell_help_dir, and workload validations; update snapshots and add Hypothesis-based property tests.
Workflows and dev deps
.github/workflows/test-stage-release-artefacts.yml, pyproject.toml, .github/workflows/rust-toy-app.yml
Add test-stage-artefacts-powershell-help job exercising Windows PowerShell staging and assert staged files and powershell_help_dir; add hypothesis to dev dependencies; add conditional FreeBSD skip steps in rust workflow.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Pipeline as stage_artefacts
  participant Collector as _collect_artefacts
  participant Resolver as _resolve_powershell_help_dir
  participant OutputPrep as prepare_output_data
  Caller->>Pipeline: call stage_artefacts(config, ps_module_name, corr_id)
  Pipeline->>Collector: collect and stage artefacts
  Collector-->>Pipeline: staged_paths, outputs, checksums, skipped_artefacts
  Pipeline->>Resolver: resolve powershell_help_dir(staging_root, ps_module_name)
  Resolver-->>Pipeline: powershell_help_dir or None
  Pipeline->>OutputPrep: build StagingOutputData
  OutputPrep-->>Pipeline: output dict (includes powershell_help_dir)
  Pipeline-->>Caller: return StageResult
Loading

Possibly related issues

Poem

🎩 A module tucked in output's care,
Sidecars placed with tidy flair,
Dest aliased, paths kept straight,
Tests assert each gated state,
Stage your artefacts; let releases sing!

🚥 Pre-merge checks | ✅ 16 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
User-Facing Documentation ⚠️ Warning PR adds new user-facing functionality (ps-module-name input, powershell_help_dir output) but does not create docs/users-guide.md as mandated by the custom check. Create docs/users-guide.md documenting the new ps-module-name input and powershell_help_dir output with clear usage examples for the stage-release-artefacts action.
Domain Architecture ❓ Inconclusive No result was produced after verification. Marking as INCONCLUSIVE. Re-run the check or adjust instructions to produce a final result.
✅ Passed checks (16 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'Expose PowerShell help staging output' clearly summarises the main change: adding a dedicated output for staged PowerShell module help directories.
Description check ✅ Passed The pull request description thoroughly documents the feature addition, implementation walkthrough, validation results, and design rationale, all directly related to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Testing (Overall) ✅ Passed All new functionality is guarded by substantive tests validating actual behaviour, not implementation details. Critical assertions would fail if ps_module_name was ignored or resolution logic removed.
Developer Documentation ✅ Passed Internal APIs documented: load_config workspace, stage_artefacts, StageResult, StagingOutputData, correlation IDs, PowerShell resolution rules. ADR 0002 and README updated comprehensively.
Module-Level Documentation ✅ Passed All 14 Python modules (8 source + 6 test) have module-level docstrings. Key ones document purpose, relationships (pipeline interdependencies), example usage, and key behaviours.
Testing (Unit And Behavioural) ✅ Passed Added 43 unit tests covering edge cases, error paths and invariants plus behavioural tests exercising staging pipeline and CLI with snapshots and integration test verifying real workflow execution.
Testing (Property / Proof) ✅ Passed Property tests using Hypothesis cover path safety, module naming, and help directory resolution invariants. Strategies hardened against platform-specific edge cases.
Testing (Compile-Time / Ui) ✅ Passed Snapshot tests appropriately used for CLI output with _redact_paths redaction. Snapshots encode meaningful behavioural differences and capture the new powershell_help_dir field.
Unit Architecture ✅ Passed Architecture maintains clear query/command boundaries. Queries (load_config, prepare_output_data) are pure. Commands explicit. Dependencies injected. Fallibility visible. Tests verify separation.
Observability ✅ Passed Correlation IDs logged at decision points, informative error messages with context, skipped artefacts surface as GitHub warnings, observability documented for operators.
Security And Privacy ✅ Passed No secrets or injection risks. Path validation blocks traversal; ps-module-name never executes as shell code; workspace from GitHub env; output paths via .as_posix(); tests isolated.
Performance And Resource Use ✅ Passed Staging loop is O(N) bounded by artefact count. PowerShell help resolution runs once post-staging with short-circuit. No algorithmic regression, unbounded growth, or unnecessary allocation detected.
Concurrency And State ✅ Passed No concurrency or shared mutable state introduced. Action runs sequentially in a single job step; all state is local and single-threaded; environment dependencies are now explicit parameters.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/powershell-help-dir-output

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


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

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 13, 2026

Reviewer's Guide

Extends the stage-release-artefacts action to accept an explicit PowerShell module name and emit a new powershell_help_dir output, including wiring through the Python staging pipeline, configuration parsing, and tests, while leaving windows-package with just a TODO for future MSI embedding.

Sequence diagram for PowerShell help dir staging output

sequenceDiagram
    actor Workflow
    participant StageReleaseArtefactsAction as stage-release-artefacts action
    participant StageScript as stage.py main
    participant Pipeline as stage_artefacts
    participant Output as prepare_output_data

    Workflow->>StageReleaseArtefactsAction: inputs.ps-module-name
    StageReleaseArtefactsAction->>StageScript: INPUT_PS_MODULE_NAME env
    StageScript->>StageScript: parse ps_module_name
    StageScript->>Pipeline: stage_artefacts(config, github_output_file, normalize_windows_paths, ps_module_name)

    Pipeline->>Pipeline: _resolve_powershell_help_dir(staging_dir, staged_paths, ps_module_name)
    alt ps_module_name set and artefacts under module_dir
        Pipeline-->>Pipeline: powershell_help_dir = staging_dir/ps_module_name
    else no matching module artefacts
        Pipeline-->>Pipeline: powershell_help_dir = None
    end

    Pipeline->>Output: prepare_output_data(staging_dir, staged_paths, outputs, checksums, powershell_help_dir)
    Output-->>Pipeline: output_data with powershell_help_dir

    Pipeline-->>StageScript: StageResult(powershell_help_dir)
    StageScript-->>StageReleaseArtefactsAction: write GITHUB_OUTPUT powershell_help_dir
    StageReleaseArtefactsAction-->>Workflow: outputs.powershell_help_dir
Loading

Flow diagram for destination and dest artefact config parsing

flowchart TD
    A[Start _parse_artefact_entry] --> B[Read entry.destination]
    B --> C[Read entry.dest]
    C --> D{destination and dest both present?}
    D -->|Yes| E[Raise StageError: Artefact must not define both destination and dest]
    D -->|No| F[Set destination = entry.destination or entry.dest]
    F --> G[Create ArtefactConfig with destination]
    G --> H[End _parse_artefact_entry]
Loading

File-Level Changes

Change Details Files
Expose a powershell_help_dir output from stage-release-artefacts based on an explicit PowerShell module name input.
  • Add ps-module-name input and powershell_help_dir output wiring to the composite action metadata and shell wrapper environment.
  • Thread a ps_module_name parameter through stage.py into stage_artefacts and compute the module directory based on the staging_dir and staged artefacts.
  • Extend StageResult and prepare_output_data to carry and export a normalized powershell_help_dir string output, defaulting to empty when unset.
  • Update tests to cover reserved key handling, JSON output contents, and multiple scenarios for presence/absence of PowerShell sidecar artefacts.
.github/actions/stage-release-artefacts/action.yml
.github/actions/stage-release-artefacts/scripts/stage.py
.github/actions/stage-release-artefacts/scripts/stage_common/pipeline.py
.github/actions/stage-release-artefacts/scripts/stage_common/output.py
.github/actions/stage-release-artefacts/tests/test_stage.py
Allow artefact entries to use a dest alias for destination and validate against conflicting keys.
  • Parse artefact config entries using destination or dest with dest as an alias, while rejecting entries that specify both.
  • Document the destination/dest dual spelling in the README and add tests for dest-only and destination+dest error cases.
.github/actions/stage-release-artefacts/scripts/stage_common/config.py
.github/actions/stage-release-artefacts/tests/test_stage.py
.github/actions/stage-release-artefacts/README.md
Document PowerShell MAML sidecar handling and future MSI embedding in project docs and windows-package metadata.
  • Add README guidance and a worked example for staging PowerShell MAML sidecar artefacts with ps-module-name and powershell_help_dir.
  • Clarify that MAML is not currently embedded in the Windows MSI and that embedding should be handled in a follow-up issue.
  • Add an explicit TODO comment in windows-package/action.yml referencing the follow-up issue for adding ps-help-dir input and MSI embedding.
.github/actions/stage-release-artefacts/README.md
.github/actions/windows-package/action.yml

Tips and commands

Interacting with Sourcery

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

Customizing Your Experience

Access your dashboard to:

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

Getting Help

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 16, 2026


@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 16, 2026

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

.github/actions/stage-release-artefacts/tests/test_stage.py

Comment on lines +496 to +576

    def test_stages_windows_powershell_help_dir(self, tmp_path: Path) -> None:
        """Windows PowerShell sidecars are staged under the module directory."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        source_dir = (
            workspace
            / "target"
            / "orthohelp"
            / "x86_64-pc-windows-msvc"
            / "release"
            / "powershell"
            / "MyTool"
        )
        help_dir = source_dir / "en-US"
        help_dir.mkdir(parents=True)
        files = [
            source_dir / "MyTool.psm1",
            source_dir / "MyTool.psd1",
            help_dir / "MyTool-help.xml",
            help_dir / "about_MyTool.help.txt",
        ]
        for file in files:
            file.write_text(file.name, encoding="utf-8")
        output_file = tmp_path / "output"

        config = StagingConfig(
            workspace=workspace,
            bin_name="mytool",
            dist_dir="dist",
            checksum_algorithm="sha256",
            artefacts=[
                ArtefactConfig(
                    source=(
                        "target/orthohelp/{target}/release/powershell/"
                        "MyTool/MyTool.psm1"
                    ),
                    destination="MyTool/MyTool.psm1",
                    required=False,
                ),
                ArtefactConfig(
                    source=(
                        "target/orthohelp/{target}/release/powershell/"
                        "MyTool/MyTool.psd1"
                    ),
                    destination="MyTool/MyTool.psd1",
                    required=False,
                ),
                ArtefactConfig(
                    source=(
                        "target/orthohelp/{target}/release/powershell/"
                        "MyTool/en-US/MyTool-help.xml"
                    ),
                    destination="MyTool/en-US/MyTool-help.xml",
                    required=False,
                ),
                ArtefactConfig(
                    source=(
                        "target/orthohelp/{target}/release/powershell/"
                        "MyTool/en-US/about_MyTool.help.txt"
                    ),
                    destination="MyTool/en-US/about_MyTool.help.txt",
                    required=False,
                ),
            ],
            platform="windows",
            arch="x86_64",
            target="x86_64-pc-windows-msvc",
        )

        result = stage_artefacts(config, output_file, ps_module_name="MyTool")

        assert len(result.staged_artefacts) == 4
        assert (result.staging_dir / "MyTool" / "MyTool.psm1").exists()
        assert (result.staging_dir / "MyTool" / "MyTool.psd1").exists()
        assert (result.staging_dir / "MyTool" / "en-US" / "MyTool-help.xml").exists()
        assert (
            result.staging_dir / "MyTool" / "en-US" / "about_MyTool.help.txt"
        ).exists()
        assert result.powershell_help_dir == result.staging_dir / "MyTool"
        output = output_file.read_text(encoding="utf-8")
        assert f"powershell_help_dir={result.staging_dir / 'MyTool'}" in output

❌ New issue: Large Method
test_stages_windows_powershell_help_dir has 78 lines, threshold = 70

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 16, 2026

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

.github/actions/stage-release-artefacts/tests/test_stage.py

Comment on lines +171 to +196

    def test_rejects_dest_and_destination_together(
        self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
    ) -> None:
        """Artefact entries must not provide both destination spellings."""
        monkeypatch.setenv("GITHUB_WORKSPACE", str(tmp_path))
        config_file = tmp_path / "config.toml"
        config_file.write_text(
            """
[common]
bin_name = "myapp"

[[common.artefacts]]
source = "binary"
dest = "short"
destination = "long"

[targets.linux]
platform = "linux"
arch = "x86_64"
target = "x86_64-unknown-linux-gnu"
""",
            encoding="utf-8",
        )

        with pytest.raises(StageError, match="both 'destination' and 'dest'"):
            load_config(config_file, "linux")

❌ New issue: Code Duplication
The module contains 4 functions with similar structure: TestLoadConfig.test_rejects_dest_and_destination_together,TestStageArtefacts.test_stages_artefact,test_generates_checksum_sidecar,test_raises_for_missing_target

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 16, 2026

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

.github/actions/stage-release-artefacts/tests/test_stage.py

Comment on file

        assert config.platform == "linux"
        assert len(config.artefacts) == 1

    def test_loads_target_artefacts_with_dest_alias(

❌ New issue: Low Cohesion
This module has at least 36 different responsibilities amongst its 36 functions, threshold = 4

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 16, 2026

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

.github/actions/stage-release-artefacts/scripts/stage_common/output.py

Comment on lines +38 to +39

    *,
    powershell_help_dir: Path | None = None,

❌ New issue: Excess Number of Function Arguments
prepare_output_data has 5 arguments, max arguments = 4

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

Move the monolithic `test_stage.py` coverage into focused modules for
environment, config, resolution, output, and pipeline behaviour.

Extract shared staging config and PowerShell workspace helpers so the
pipeline tests keep the same assertions with less duplicated setup.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 17, 2026

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

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

Excess Number of Function Arguments

.github/actions/stage-release-artefacts/scripts/stage_common/output.py: prepare_output_data

What lead to degradation?

prepare_output_data has 5 arguments, max arguments = 4

Why does this problem occur?

Functions with many arguments indicate either a) low cohesion where the function has too many responsibilities, or b) a missing abstraction that encapsulates those arguments.
The threshold for the Python language is 4 function arguments.

How to fix it?

Start by investigating the responsibilities of the function. Make sure it doesn't do too many things, in which case it should be split into smaller and more cohesive functions. Consider the refactoring INTRODUCE PARAMETER OBJECT to encapsulate arguments that refer to the same logical concept.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 17, 2026

@coderabbitai Please investigate the cause of the following issue using codegraph exploration and research, identify a fix and provide an AI coding agent prompt for the fix:

Run uv sync --group dev
  uv sync --group dev
  uv run pytest
  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
  env:
    UV_TOOL_BIN_DIR: D:\a\_temp\uv-tool-bin-dir
    UV_TOOL_DIR: D:\a\_temp\uv-tool-dir
    UV_PYTHON: 3.13
    UV_CACHE_DIR: D:\a\_temp\setup-uv-cache
    PYTHONIOENCODING: utf-8
Using CPython 3.13.13 interpreter at: C:\hostedtoolcache\windows\Python\3.13.13\x64\python.exe
Creating virtual environment at: .venv
Resolved 39 packages in 406ms
   Updating https://github.com/leynos/polythene.git (61b4566130305fcb32f419f09ae8b3940ceb4107)
   Building shared-actions @ file:///D:/a/shared-actions/shared-actions
Downloading pygments (1.2MiB)
Downloading lxml (3.6MiB)
Downloading ty (11.1MiB)
Downloading pywin32 (9.1MiB)
 Downloaded ty
 Downloaded lxml
 Downloaded pygments
 Downloaded pywin32
    Updated https://github.com/leynos/polythene.git (61b4566130305fcb32f419f09ae8b3940ceb4107)
   Building polythene @ git+https://github.com/leynos/polythene.git@61b4566130305fcb32f419f09ae8b3940ceb4107
      Built shared-actions @ file:///D:/a/shared-actions/shared-actions
      Built polythene @ git+https://github.com/leynos/polythene.git@61b4566130305fcb32f419f09ae8b3940ceb4107
Prepared 38 packages in 3.43s
Installed 38 packages in 202ms
 + annotated-doc==0.0.4
 + anyio==4.13.0
 + attrs==26.1.0
 + certifi==2026.4.22
 + click==8.3.3
 + cmd-mox==0.2.0
 + colorama==0.4.6
 + cyclopts==3.24.0
 + docstring-parser==0.18.0
 + docutils==0.22.4
 + h11==0.16.0
 + httpcore==1.0.9
 + httpx==0.28.1
 + idna==3.15
 + iniconfig==2.3.0
 + jinja2==3.1.6
 + lxml==5.4.0
 + lxml-stubs==0.5.1
 + markdown-it-py==4.2.0
 + markupsafe==3.0.3
 + mdurl==0.1.2
 + packaging==26.2
 + pluggy==1.6.0
 + plumbum==1.10.0
 + polythene==0.1.0 (from git+https://github.com/leynos/polythene.git@61b4566130305fcb32f419f09ae8b3940ceb4107)
 + pygments==2.20.0
 + pytest==8.4.2
 + pywin32==311
 + pyyaml==6.0.3
 + rich==15.0.0
 + rich-rst==1.3.2
 + shared-actions==1.2.2 (from file:///D:/a/shared-actions/shared-actions)
 + shellingham==1.5.4
 + syspath-hack==0.4.0
 + tenacity==8.5.0
 + ty==0.0.37
 + typer==0.25.1
 + uuid6==2025.0.1
============================= test session starts =============================
platform win32 -- Python 3.13.13, pytest-8.4.2, pluggy-1.6.0
rootdir: D:\a\shared-actions\shared-actions
configfile: pytest.ini
testpaths: .github/actions, workflow_scripts/tests
plugins: anyio-4.13.0
collected 696 items / 3 skipped

.github\actions\determine-release-modes\tests\test_determine_release_modes.py . [  0%]
..........................                                               [  3%]
.github\actions\ensure-cargo-version\scripts\tests\test_ensure_cargo_version.py . [  4%]
..............                                                           [  6%]
.github\actions\export-cargo-metadata\tests\test_read_manifest.py ...... [  6%]
........                                                                 [  8%]
.github\actions\generate-coverage\scripts\tests\test_run_rust_windows.py . [  8%]
.                                                                        [  8%]
.github\actions\linux-packages\tests\test_action_workdir.py .....        [  9%]
.github\actions\linux-packages\tests\test_deb_package.py s               [  9%]
.github\actions\linux-packages\tests\test_package_cli.py ....ss.s....... [ 11%]
...ss....s..                                                             [ 13%]
.github\actions\linux-packages\tests\test_rpm_package.py s               [ 13%]
.github\actions\linux-packages\tests\test_script_utils_helpers.py ...... [ 14%]
.....                                                                    [ 14%]
.github\actions\macos-package\tests\test_build_component.py ..           [ 15%]
.github\actions\macos-package\tests\test_build_product.py ....           [ 15%]
.github\actions\macos-package\tests\test_check_platform.py ..            [ 15%]
.github\actions\macos-package\tests\test_compute_version.py .....        [ 16%]
.github\actions\macos-package\tests\test_prepare_license_resources.py .. [ 16%]
                                                                         [ 16%]
.github\actions\macos-package\tests\test_prepare_payload.py .....        [ 17%]
.github\actions\macos-package\tests\test_shared_utils.py .........       [ 18%]
.github\actions\macos-package\tests\test_sign_package.py ...             [ 19%]
.github\actions\release-to-pypi-uv\tests\test_action_python_version.py . [ 19%]
....                                                                     [ 20%]
.github\actions\release-to-pypi-uv\tests\test_check_github_release.py .. [ 20%]
..........                                                               [ 21%]
.github\actions\release-to-pypi-uv\tests\test_confirm_release.py ..      [ 22%]
.github\actions\release-to-pypi-uv\tests\test_determine_release.py ..... [ 22%]
......                                                                   [ 23%]
.github\actions\release-to-pypi-uv\tests\test_publish_release.py ....... [ 24%]
                                                                         [ 24%]
.github\actions\release-to-pypi-uv\tests\test_validate_toml_versions.py . [ 24%]
...................................................                      [ 32%]
.github\actions\release-to-pypi-uv\tests\test_write_summary.py ...       [ 32%]
.github\actions\rust-build-release\tests\test_action_setup.py .......... [ 34%]
...........                                                              [ 35%]
.github\actions\rust-build-release\tests\test_command_wrapper.py sss     [ 36%]
.github\actions\rust-build-release\tests\test_cross_install.py sssssssss [ 37%]
ss                                                                       [ 37%]
.github\actions\rust-build-release\tests\test_features.py ssssssssssssss [ 39%]
ss                                                                       [ 39%]
.github\actions\rust-build-release\tests\test_linux_package_step.py .    [ 40%]
.github\actions\rust-build-release\tests\test_manifest_input_step.py ... [ 40%]
...                                                                      [ 40%]
.github\actions\rust-build-release\tests\test_manifest_path.py sssssssss [ 42%]
sssssss                                                                  [ 43%]
.github\actions\rust-build-release\tests\test_runtime.py ............... [ 45%]
.............................                                            [ 49%]
.github\actions\rust-build-release\tests\test_rust_toy_workflow.py ..    [ 49%]
.github\actions\rust-build-release\tests\test_setup_rust_reference.py .. [ 50%]
                                                                         [ 50%]
.github\actions\rust-build-release\tests\test_smoke.py ......            [ 51%]
.github\actions\rust-build-release\tests\test_stage_artifacts_step.py .. [ 51%]
..                                                                       [ 51%]
.github\actions\rust-build-release\tests\test_stage_script_behaviour.py s [ 51%]
sssss                                                                    [ 52%]
.github\actions\rust-build-release\tests\test_target_install.py ssssssss [ 53%]
sssssssssssssssssssssssss......                                          [ 58%]
.github\actions\rust-build-release\tests\test_toolchain_helpers.py ..... [ 58%]
.....                                                                    [ 59%]
.github\actions\rust-build-release\tests\test_utils.py ....              [ 60%]
.github\actions\stage-release-artefacts\tests\test_config.py ........    [ 61%]
.github\actions\stage-release-artefacts\tests\test_environment.py ...    [ 61%]
.github\actions\stage-release-artefacts\tests\test_output.py .........   [ 62%]
.github\actions\stage-release-artefacts\tests\test_pipeline.py .....FF.. [ 64%]
....                                                                     [ 64%]
.github\actions\stage-release-artefacts\tests\test_resolution.py ...     [ 65%]
.github\actions\tests\test_actions_common.py ....                        [ 65%]
.github\actions\upload-release-assets\tests\test_upload_release_assets.py . [ 65%]
..................................                                       [ 70%]
.github\actions\validate-linux-packages\tests\deb\test_validate_packages.py . [ 70%]
...                                                                      [ 71%]
.github\actions\validate-linux-packages\tests\locators\test_locators.py . [ 71%]
...                                                                      [ 71%]
.github\actions\validate-linux-packages\tests\metadata\test_metadata_validators.py . [ 72%]
.....                                                                    [ 72%]
.github\actions\validate-linux-packages\tests\rpm\test_validate_packages.py . [ 72%]
......                                                                   [ 73%]
.github\actions\validate-linux-packages\tests\test_action_manifest.py .s [ 74%]
                                                                         [ 74%]
.github\actions\validate-linux-packages\tests\test_validate_architecture.py . [ 74%]
..                                                                       [ 74%]
.github\actions\validate-linux-packages\tests\test_validate_cli.py ..... [ 75%]
...........................                                              [ 79%]
.github\actions\validate-linux-packages\tests\test_validate_commands.py . [ 79%]
...                                                                      [ 79%]
.github\actions\validate-linux-packages\tests\test_validate_exceptions.py . [ 79%]
                                                                         [ 79%]
.github\actions\validate-linux-packages\tests\test_validate_helpers.py . [ 80%]
...                                                                      [ 80%]
.github\actions\validate-linux-packages\tests\test_validate_metadata.py . [ 80%]
.ss                                                                      [ 81%]
.github\actions\validate-linux-packages\tests\test_validate_normalise.py . [ 81%]
......                                                                   [ 82%]
.github\actions\validate-linux-packages\tests\test_validate_packages_diagnostics.py . [ 82%]
..                                                                       [ 82%]
.github\actions\validate-linux-packages\tests\test_validate_polythene.py . [ 82%]
...............                                                          [ 84%]
.github\actions\windows-package\tests\test_manifest.py ..                [ 85%]
.github\actions\windows-package\tests\test_plaintext_to_rtf.py ......... [ 86%]
.........                                                                [ 87%]
.github\actions\windows-package\tests\test_resolve_version_ps1.py ...... [ 88%]
.............                                                            [ 90%]
.github\actions\windows-package\tests\test_validate_inputs_ps1.py ...... [ 91%]
.........                                                                [ 92%]
.github\actions\windows-package\tests\test_windows_installer_template.py . [ 92%]
..............                                                           [ 94%]
workflow_scripts\tests\test_dependabot_automerge.py .................... [ 97%]
.................                                                        [100%]

================================== FAILURES ===================================
_________ TestStageArtefacts.test_stages_windows_powershell_help_dir __________

self = <test_pipeline.TestStageArtefacts object at 0x000002138D38B020>
tmp_path = WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_stages_windows_powershell0')

    def test_stages_windows_powershell_help_dir(self, tmp_path: Path) -> None:
        """Windows PowerShell sidecars are staged under the module directory."""
        workspace, output_file = self._make_powershell_workspace(tmp_path)
    
        config = StagingConfig(
            workspace=workspace,
            bin_name="mytool",
            dist_dir="dist",
            checksum_algorithm="sha256",
            artefacts=self._powershell_artefact_configs(),
            platform="windows",
            arch="x86_64",
            target="x86_64-pc-windows-msvc",
        )
    
        result = stage_artefacts(config, output_file, ps_module_name="MyTool")
    
        assert len(result.staged_artefacts) == 4
        assert (result.staging_dir / "MyTool" / "MyTool.psm1").exists()
        assert (result.staging_dir / "MyTool" / "MyTool.psd1").exists()
        assert (result.staging_dir / "MyTool" / "en-US" / "MyTool-help.xml").exists()
        assert (
            result.staging_dir / "MyTool" / "en-US" / "about_MyTool.help.txt"
        ).exists()
        assert result.powershell_help_dir == result.staging_dir / "MyTool"
        output = output_file.read_text(encoding="utf-8")
>       assert f"powershell_help_dir={result.staging_dir / 'MyTool'}" in output
E       AssertionError: assert 'powershell_help_dir=C:\\Users\\runneradmin\\AppData\\Local\\Temp\\pytest-of-runneradmin\\pytest-0\\test_stages_windows_powershell0\\workspace\\dist\\mytool_windows_x86_64\\MyTool' in 'artefact_map={}\nartifact_dir=C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_stages_wind...ol\nstaged_files<<gh_STAGED_FILES\nabout_MyTool.help.txt\nMyTool-help.xml\nMyTool.psd1\nMyTool.psm1\ngh_STAGED_FILES\n'

.github\actions\stage-release-artefacts\tests\test_pipeline.py:219: AssertionError
_____ TestStageArtefacts.test_linux_skips_absent_optional_powershell_help _____

self = <test_pipeline.TestStageArtefacts object at 0x000002138D38B130>
tmp_path = WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_linux_skips_absent_option0')

    def test_linux_skips_absent_optional_powershell_help(self, tmp_path: Path) -> None:
        """Linux staging succeeds when optional PowerShell sidecars are absent."""
        workspace = tmp_path / "workspace"
        workspace.mkdir()
        binary = workspace / "mytool"
        binary.write_text("binary content", encoding="utf-8")
        output_file = tmp_path / "output"
    
        config = self._make_linux_config(
            workspace,
            [
                ArtefactConfig(source="mytool"),
                ArtefactConfig(
                    source=(
                        "target/orthohelp/{target}/release/powershell/"
                        "MyTool/MyTool.psm1"
                    ),
                    destination="MyTool/MyTool.psm1",
                    required=False,
                ),
            ],
        )
    
        result = stage_artefacts(config, output_file, ps_module_name="MyTool")
    
        assert len(result.staged_artefacts) == 1
>       assert result.powershell_help_dir is None
E       AssertionError: assert WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_linux_skips_absent_option0/workspace/dist/myapp_linux_x86_64/MyTool') is None
E        +  where WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_linux_skips_absent_option0/workspace/dist/myapp_linux_x86_64/MyTool') = StageResult(staging_dir=WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_linux...a/Local/Temp/pytest-of-runneradmin/pytest-0/test_linux_skips_absent_option0/workspace/dist/myapp_linux_x86_64/MyTool')).powershell_help_dir

.github\actions\stage-release-artefacts\tests\test_pipeline.py:247: AssertionError
---------------------------- Captured stdout call -----------------------------
Warning: Optional artefact missing: target/orthohelp/{target}/release/powershell/MyTool/MyTool.psm1
------------------------------ Captured log call ------------------------------
WARNING  stage_common.pipeline:pipeline.py:204 Optional artefact missing: target/orthohelp/{target}/release/powershell/MyTool/MyTool.psm1
=========================== short test summary info ===========================
FAILED .github/actions/stage-release-artefacts/tests/test_pipeline.py::TestStageArtefacts::test_stages_windows_powershell_help_dir - AssertionError: assert 'powershell_help_dir=C:\\Users\\runneradmin\\AppData\\Local\\Temp\\pytest-of-runneradmin\\pytest-0\\test_stages_windows_powershell0\\workspace\\dist\\mytool_windows_x86_64\\MyTool' in 'artefact_map={}\nartifact_dir=C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_stages_wind...ol\nstaged_files<<gh_STAGED_FILES\nabout_MyTool.help.txt\nMyTool-help.xml\nMyTool.psd1\nMyTool.psm1\ngh_STAGED_FILES\n'
FAILED .github/actions/stage-release-artefacts/tests/test_pipeline.py::TestStageArtefacts::test_linux_skips_absent_optional_powershell_help - AssertionError: assert WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_linux_skips_absent_option0/workspace/dist/myapp_linux_x86_64/MyTool') is None
 +  where WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_linux_skips_absent_option0/workspace/dist/myapp_linux_x86_64/MyTool') = StageResult(staging_dir=WindowsPath('C:/Users/runneradmin/AppData/Local/Temp/pytest-of-runneradmin/pytest-0/test_linux...a/Local/Temp/pytest-of-runneradmin/pytest-0/test_linux_skips_absent_option0/workspace/dist/myapp_linux_x86_64/MyTool')).powershell_help_dir
============ 2 failed, 598 passed, 99 skipped in 214.38s (0:03:34) ============
Error: Process completed with exit code 1.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

Require the staged PowerShell module directory to exist before reporting
`powershell_help_dir`. This prevents Windows path comparisons from treating
a staged binary with different casing as a module directory.

Assert the serialized output path with POSIX separators to match the action
output format.
codescene-delta-analysis[bot]

This comment was marked as outdated.

Add `StagingOutputData` to bundle the values needed by
`prepare_output_data` and update the pipeline caller and output tests to
use the new parameter object.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 18, 2026

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

.github/actions/stage-release-artefacts/scripts/stage_common/pipeline.py

Comment on file

    github_output_file: Path,
    *,
    normalize_windows_paths: bool = False,
    ps_module_name: str = "",

❌ New issue: Large Method
stage_artefacts has 70 lines, threshold = 70

@coderabbitai

This comment was marked as resolved.

Move the artefact collection loop out of `stage_artefacts` into
`_collect_artefacts` so the staging orchestration stays below the large
method threshold while preserving the existing staging behaviour.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos leynos marked this pull request as ready for review May 18, 2026 19:29
sourcery-ai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 19, 2026

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

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

.github/actions/stage-release-artefacts/tests/test_pipeline.py

Comment on lines +485 to +503

    def test_parent_traversal_destinations_are_rejected_through_staging(
        self, tmp_path: Path, destination: str
    ) -> None:
        """Generated parent traversal destinations cannot escape staging."""
        workspace = tmp_path / "workspace"
        workspace.mkdir(exist_ok=True)
        (workspace / "myapp").write_text("binary content", encoding="utf-8")
        config = self._make_linux_config(
            workspace,
            [
                ArtefactConfig(
                    source="myapp",
                    destination=f"../{destination}",
                )
            ],
        )

        with pytest.raises(StageError, match="escapes staging directory"):
            stage_artefacts(config)

❌ New issue: Code Duplication
The module contains 4 functions with similar structure: test_empty_ps_module_name_leaves_powershell_help_dir_empty,test_parent_traversal_destinations_are_rejected_through_staging,test_path_traversal_destination_raises,test_valid_ps_module_names_resolve_when_staged

@leynos

This comment was marked as resolved.

Replace repeated Windows staging config setup in pipeline tests with a shared
helper, and apply the requested PowerShell documentation wording fixes.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

Oops, something went wrong! Please try again later. 🐰 💔

@coderabbitai

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/actions/stage-release-artefacts/tests/test_pipeline.py:
- Around line 227-244: Make _make_windows_config a staticmethod: add the
`@staticmethod` decorator and remove the implicit self parameter, update its body
to compute artefacts before calling StagingConfig (e.g. artefacts_to_use =
artefacts if artefacts is not None else
TestStageArtefacts._powershell_artefact_configs()), and replace any
self._powershell_artefact_configs() calls with the class-qualified call
TestStageArtefacts._powershell_artefact_configs(); then pass
artefacts=artefacts_to_use into the StagingConfig constructor so the helper no
longer depends on instance state.
- Around line 47-55: TRAVERSAL_DESTINATIONS currently only blacklists "\x00"
which is inconsistent with PS_MODULE_NAMES and PATH_SEGMENTS and can generate
Windows-illegal/path-separator chars that cause OS errors; update the Hypothesis
strategy TRAVERSAL_DESTINATIONS to use the same blacklist_characters string as
PS_MODULE_NAMES and PATH_SEGMENTS (i.e. '/\\\x00:*?"<>|') while keeping the
existing blacklist_categories, max_codepoint, min_size/max_size and the existing
filter(lambda value: "{" not in value and "}" not in value) so generated values
avoid POSIX separators and Windows-illegal filename characters and prevent
platform-specific test failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: dd49a12a-75e9-4591-8f5a-fa95135c3416

📥 Commits

Reviewing files that changed from the base of the PR and between 0049f15 and 57d15c1.

📒 Files selected for processing (3)
  • .github/actions/stage-release-artefacts/README.md
  • .github/actions/stage-release-artefacts/tests/test_pipeline.py
  • docs/adr/0002-explicit-ps-module-name.md

Comment thread .github/actions/stage-release-artefacts/tests/test_pipeline.py
Comment thread .github/actions/stage-release-artefacts/tests/test_pipeline.py
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 19, 2026

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

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

.github/actions/stage-release-artefacts/tests/test_pipeline.py

Comment on lines +468 to +486

    def test_parent_traversal_destinations_are_rejected_through_staging(
        self, tmp_path: Path, destination: str
    ) -> None:
        """Generated parent traversal destinations cannot escape staging."""
        workspace = tmp_path / "workspace"
        workspace.mkdir(exist_ok=True)
        (workspace / "myapp").write_text("binary content", encoding="utf-8")
        config = self._make_linux_config(
            workspace,
            [
                ArtefactConfig(
                    source="myapp",
                    destination=f"../{destination}",
                )
            ],
        )

        with pytest.raises(StageError, match="escapes staging directory"):
            stage_artefacts(config)

❌ New issue: Code Duplication
The module contains 2 functions with similar structure: test_parent_traversal_destinations_are_rejected_through_staging,test_path_traversal_destination_raises

@coderabbitai

This comment was marked as resolved.

Require callers to inject the workspace when loading stage-release
configuration, removing the fallback read from `GITHUB_WORKSPACE` in the
configuration layer.

Split artefact path resolution from copy and checksum writes in the staging
pipeline, while keeping `_iter_staged_artefacts` as a compatibility wrapper for
later removal. Add correlation IDs and per-artefact DEBUG logging so staging
runs can be traced across pipeline and CLI failure logs.
codescene-delta-analysis[bot]

This comment was marked as outdated.

Make the Windows staging config helper independent of instance state and align
the traversal destination strategy with the platform-safe filename character
policy used by the related Hypothesis strategies.
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/developers-guide.md`:
- Line 169: Edit the sentence "Pipeline INFO, WARNING and DEBUG records include
that `corr_id` so" and insert the Oxford (serial) comma before the final item so
it reads "Pipeline INFO, WARNING, and DEBUG records include that `corr_id` so",
ensuring the Markdown file uses en-GB-oxendict styling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 85b388a4-34ae-40d1-8c0f-9165902743bf

📥 Commits

Reviewing files that changed from the base of the PR and between 57d15c1 and b8c02eb.

📒 Files selected for processing (6)
  • .github/actions/stage-release-artefacts/scripts/stage.py
  • .github/actions/stage-release-artefacts/scripts/stage_common/config.py
  • .github/actions/stage-release-artefacts/scripts/stage_common/pipeline.py
  • .github/actions/stage-release-artefacts/tests/test_config.py
  • .github/actions/stage-release-artefacts/tests/test_pipeline.py
  • docs/developers-guide.md

Comment thread docs/developers-guide.md Outdated
Add the Oxford comma to the stage-release observability log-level list in the
developer guide.
codescene-delta-analysis[bot]

This comment was marked as outdated.

Share the minimal workspace setup and StageError assertion between the
parametrized and Hypothesis traversal rejection tests.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

Tip

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

🧩 Analysis chain

@leynos

Status against current PR head:

  • Module-Level Documentation — Resolved

    • pipeline.py and output.py now carry multi-paragraph module docstrings describing purpose, responsibilities, relationships, and usage examples, modelled on resolution.py.
  • Unit Architecture — Resolved

    • load_config accepts an explicit workspace: Path and is called from stage.py, which reads GITHUB_WORKSPACE.
    • The staging pipeline separates concerns: resolution vs I/O are split via helpers (_iter_resolved_artefacts, _stage_resolved_artefact, _collect_artefacts), and stage_artefacts returns a pure StageResult. No GitHub Actions formatting remains in the domain layer.
  • Developer Documentation — Resolved

    • ADR 0002 exists under docs/adr and documents the explicit ps-module-name design, constraints, and export rules.
  • Testing (Compile-Time / UI) — Resolved

    • test_stage_cli.py asserts complete, redacted GITHUB_OUTPUT snapshots; path normalisation and heredoc structure are covered. Tests no longer rely on brittle substrings.
  • Domain Architecture — Resolved

    • Environment access is confined to stage.py; config loading and pipeline logic are free of infrastructure concerns.
  • Observability — Resolved

    • pipeline.py adds start/end INFO logs with timing and counts, per-artefact DEBUG logs, and a correlation ID; stage.py logs exceptions and emits GitHub annotation warnings at the CLI layer. Developers’ guide includes the logging/observability guidance.
  • Testing (Overall) — Inconclusive (meta-check)

    • Re-run the analyser; the code changes above are present. No code change is needed for this item.

No further code work is required for this PR to satisfy the listed checks. If your CI gate still shows stale warnings, re-trigger the checks to pick up the updated files.

If anything still flags, say the word and I will generate targeted diffs.


---

🏁 Script executed:
```
#!/bin/bash
set -euo pipefail

echo "=== pipeline.py: first 60 lines (docstring) ==="
sed -n '1,60p' .github/actions/stage-release-artefacts/scripts/stage_common/pipeline.py || true

echo
echo "=== output.py: first 60 lines (docstring) ==="
sed -n '1,60p' .github/actions/stage-release-artefacts/scripts/stage_common/output.py || true

echo
echo "=== config.load_config signature and any GITHUB_WORKSPACE usage ==="
rg -nP 'def\s+load_config\(' .github/actions/stage-release-artefacts/scripts/stage_common/config.py || true
rg -n 'GITHUB_WORKSPACE|require_env_path' .github/actions/stage-release-artefacts/scripts/stage_common/config.py || true

echo
echo "=== stage.py loads workspace and passes to load_config ==="
rg -n 'load_config\(.+workspace=' .github/actions/stage-release-artefacts/scripts/stage.py || true
sed -n '1,160p' .github/actions/stage-release-artefacts/scripts/stage.py | sed -n '1,140p' || true

echo
echo "=== ADR 0002 presence ==="
ls -l docs/adr || true
rg -n 'ps-?module-?name|powershell_help_dir' docs/adr 2>/dev/null || true

echo
echo "=== Snapshot tests and redaction ==="
ls -l .github/actions/stage-release-artefacts/tests/__snapshots__ 2>/dev/null || true
rg -n 'snapshot|_redact_paths|ambr' .github/actions/stage-release-artefacts/tests/test_stage_cli.py .github/actions/stage-release-artefacts/tests/test_pipeline.py 2>/dev/null || true

echo
echo "=== Observability: logging/timing/correlation id in pipeline/stage ==="
rg -n 'import time|time\.monotonic|uuid|correlation|corr_id|logger\.(info|warning|error|exception|debug)' \
  .github/actions/stage-release-artefacts/scripts/stage_common/pipeline.py \
  .github/actions/stage-release-artefacts/scripts/stage.py || true
```

Length of output: 15674

---



</details>

`@leynos`

Status against the current codegraph (validated by your script output):

- Module-Level Documentation — Resolved
  - pipeline.py and output.py now include multi-paragraph docstrings stating purpose, key behaviours, relationships, and examples.

- Unit Architecture — Resolved
  - load_config no longer reads GITHUB_WORKSPACE; stage.py reads the env and injects workspace into load_config.
  - The staging pipeline is split into orchestration and helpers; GitHub Actions formatting is out of the domain layer.

- Developer Documentation — Resolved
  - docs/adr/0002-explicit-ps-module-name.md exists and documents rationale, constraints, and behaviour.

- Testing (Compile-Time / UI) — Resolved
  - test_stage_cli uses redacted snapshot assertions; a snapshot file is present. Structure and POSIX path normalisation are covered.

- Domain Architecture — Resolved
  - Environment access is confined to stage.py; pipeline/config are infrastructure-free.

- Observability — Resolved
  - Correlation ID, start/end INFO with timing and counts, per-artefact DEBUG lines, and exception logging in stage.py are present.

- Testing (Overall) — Inconclusive (meta-check only)
  - Re-run the analyser/check suite to refresh its status; no code change is required.

No further work is required for these items. If any gate still flags stale results, re-trigger that check to pick up the updated files.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented May 19, 2026

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

Excess Number of Function Arguments

.github/actions/stage-release-artefacts/scripts/stage_common/pipeline.py: _ensure_source_available, _stage_configured_artefact, _resolve_configured_artefact, _iter_resolved_artefacts, _stage_resolved_artefact

What lead to degradation?

_ensure_source_available has 5 arguments, max arguments = 4
_stage_configured_artefact has 5 arguments, max arguments = 4
_resolve_configured_artefact has 5 arguments, max arguments = 4
_iter_resolved_artefacts has 5 arguments, max arguments = 4
_stage_resolved_artefact has 5 arguments, max arguments = 4

Why does this problem occur?

Functions with many arguments indicate either a) low cohesion where the function has too many responsibilities, or b) a missing abstraction that encapsulates those arguments.
The threshold for the Python language is 4 function arguments.

How to fix it?

Start by investigating the responsibilities of the function. Make sure it doesn't do too many things, in which case it should be split into smaller and more cohesive functions. Consider the refactoring INTRODUCE PARAMETER OBJECT to encapsulate arguments that refer to the same logical concept.

Assert that missing optional artefacts populate `StageResult.skipped_artefacts`
and that the CLI warning helper emits GitHub Actions warning annotations to
stderr.

Document the required `workspace` argument on `load_config` and the CLI's
responsibility for injecting `GITHUB_WORKSPACE`.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@coderabbitai

This comment was marked as resolved.

Group the shared staging configuration, resolved artefact data, and mutable
collection state into small dataclasses so the internal pipeline helpers no
longer pass repeated argument bundles around.

Keep the public staging entry points and existing error/log message text
unchanged while preserving the compatibility wrapper for staged artefact
iteration.
@leynos leynos merged commit e4c6b0e into main May 19, 2026
24 checks passed
@leynos leynos deleted the feat/powershell-help-dir-output branch May 19, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant