Skip to content

Add end-to-end tests for lading; extend test suite and docs - #46

Merged
leynos merged 11 commits into
mainfrom
terragon/e2e-tests-bump-publish-l8k03f
Dec 19, 2025
Merged

Add end-to-end tests for lading; extend test suite and docs#46
leynos merged 11 commits into
mainfrom
terragon/e2e-tests-bump-publish-l8k03f

Conversation

@leynos

@leynos leynos commented Dec 14, 2025

Copy link
Copy Markdown
Owner

Summary

  • Adds a comprehensive end-to-end test suite for the lading CLI in a realistic multi-crate workspace, executed in a temporary Git repository with cargo interactions stubbed via cmd-mox.
  • Expands unit tests to cover E2E-related logic (workspace builder, topological sorting deduplication, and readme/workspace flag handling) and tests for the workspace metadata payload used by tests.
  • Extends cmd-mox integration tests and tightens workspace graph handling, environment propagation, and deterministic command invocation in tests.
  • Updates documentation (lading design, roadmap, and usage notes) to reflect the newly added E2E approach and test coverage.

Changes

End-to-end framework and fixtures

  • Adds tests/e2e with init.py, conftest.py, a feature file (tests/e2e/features/e2e.feature), and a test runner.
  • Provides helpers for Git operations (tests/e2e/helpers/git_helpers.py) and a workspace builder (tests/e2e/helpers/workspace_builder.py) to generate a non-trivial Rust workspace fixture.
  • Fixtures provision a Git repo with an initial commit and a realistic workspace (core, utils, app).

Scenario definitions (BDD)

  • Adds tests/e2e/features/e2e.feature defining two scenarios:
    • Bumping versions in a non-trivial workspace marks the repo dirty.
    • Publishing crates in dry-run mode validates the full workflow.

Step definitions and test runner

  • Adds tests/e2e/steps/test_e2e_steps.py with Given/When/Then steps to:
    • Create/configure a workspace, stub cargo metadata via cmd-mox, and run lading bump/publish.
    • Validate outcomes including version bumps, dependency version updates, README content, and git-dirty state.
    • Verify publish flow: crate packaging order, dry-run publishes, and staging of README files.

Command-mox integration and tests

  • Verifies how lading constructs the cmd-mox invocation environment and how PWD/CWD are handled during passthrough, ensuring deterministic command execution in tests (unit tests in tests/unit/publish/test_publish_execution_helpers.py).

Unit tests enhancements

  • Adds unit tests that cover end-to-end related logic, including topological sorting of workspace crates and readme workspace flag handling in models.
  • Adds tests for the E2E workspace builder to verify the generated file structure and cargo metadata payload consistency.
  • Adds a unit test to validate that topological sorting of workspace crates correctly handles duplicate dependencies without creating spurious cycles.
  • Adds a unit test that validates that topological sorting of workspace crates correctly handles duplicate dependencies and preserves the expected crate order.

Documentation and roadmap alignment

  • Roadmap updated to reflect completion of the end-to-end test suite (docs/roadmap.md).
  • Usage/design notes clarified to describe the e2e approach (docs/usage-guide.md).

Rationale

  • This PR provides automated end-to-end verification of the lading CLI’s core workflows (bump and publish) in an environment close to real usage, while keeping Rust toolchain dependencies out of the test environment by stubbing cargo interactions. It improves test coverage for workspace manifest handling, version propagation, dependency pinning, and staging/publishing workflows.

Testing plan

  • Run the end-to-end suite along with unit tests:
    • pytest -k e2e
    • pytest tests/unit -q
  • The e2e tests exercise:
    • Bump flow: version propagation across root and crates, README updates, and dirty git state detection.
    • Publish flow: crate packaging order, per-crate cargo package/publish invocations, and staging of README files in the staging directory.
  • Cargo interactions are stubbed via cmd-mox; the tests verify call patterns and environment propagation without requiring a Rust toolchain.

Notes

  • The end-to-end suite relies on realistic git operations but stubs external cargo commands for determinism and speed.
  • If needed, additional scenarios can be added under tests/e2e/features/e2e.feature to cover more edge cases or larger workspace graphs.

🌿 Generated by Terry


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

📎 Task: https://www.terragonlabs.com/task/be42d73b-9afd-4f5b-ac88-6cf7912fef7c

Summary by Sourcery

Add an end-to-end testing framework for the lading CLI using a realistic multi-crate workspace, and tighten cmd-mox integration, workspace graph handling, and documentation around these workflows.

New Features:

  • Introduce an end-to-end test suite under tests/e2e that exercises lading bump and publish workflows in a temporary Git repository.

Bug Fixes:

  • Ensure workspace dependency graph topological sorting correctly deduplicates duplicate dependency edges to avoid false cycles.
  • Ensure cmd-mox passthrough subprocesses run with cwd derived from the invocation PWD and that explicit cwd overrides take precedence over PWD in invocation environments.

Enhancements:

  • Add a reusable workspace builder and Git helper utilities to construct realistic multi-crate workspaces and repositories for tests.
  • Improve cmd-mox invocation environment construction to centralise environment building and make PWD handling explicit for publish executions.

Documentation:

  • Document the new end-to-end testing approach and its use of real Git and stubbed cargo operations in the lading design and usage guides.
  • Mark the roadmap item for creating an end-to-end test suite as completed.

Tests:

  • Add pytest-bdd end-to-end scenarios and step definitions that validate version bumping, dependency updates, README propagation, Git dirtiness, and publish staging behaviour.
  • Extend unit tests for cmd-mox publish execution helpers to cover environment merging and cwd/PWD behaviour during passthrough.
  • Add unit tests for the E2E workspace builder to verify generated file structure and cargo metadata payload consistency.
  • Add a unit test that validates topological sorting deduplicates duplicate dependencies and preserves the expected crate order.

- Introduce an end-to-end test suite under `tests/e2e/` that tests full lading CLI workflows
- Tests run in temporary Git repos, performing real git operations
- Cargo commands (metadata, check, test, package, publish) stubbed with cmd-mox for control
- Add supporting fixtures, helpers (git_helpers, workspace_builder), step definitions, and feature files
- Update documentation and roadmap to reflect the new E2E testing approach
- Fix publish execution environment handling for cmd-mox passthrough
- Add unit tests for the new E2E workspace builder and publish helpers
- Ensure duplicate dependencies do not cause dependency cycles in workspace model sorting

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

coderabbitai Bot commented Dec 14, 2025

Copy link
Copy Markdown

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.

Summary by CodeRabbit

  • New Features

    • Added a comprehensive end-to-end BDD test suite (workspace builder, Git helpers, step definitions and scenarios) to exercise bump and publish flows.
  • Bug Fixes

    • Publish passthroughs now respect the intended working directory.
    • Topological dependency ordering now deduplicates duplicate edges to preserve correct ordering.
  • Documentation

    • Reworked design and usage docs: publish flow, preflight sequence, diagrams, formatting and testing strategy; roadmap marks E2E tasks complete.
  • Tests

    • Added E2E and unit tests, fixtures and test helpers.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Add end-to-end behavioural tests (fixtures, helpers, feature, steps, unit tests), adjust cmd‑mox passthrough to respect explicit cwd/PWD handling in publish execution, and deduplicate+sort dependency names when building the workspace dependency graph.

Changes

Cohort / File(s) Summary
Documentation updates
docs/lading-design.md, docs/roadmap.md, docs/usage-guide.md
Rework publish workflow wording and ordering; add Publish data‑flow and preflight details (including patch‑stripping logic and dry‑run vs live behaviour); reformat large diffs inline; mark E2E roadmap tasks complete; clarify E2E testing approach and cargo‑stubbing behaviour.
Publish command execution
lading/commands/publish_execution.py
Build cmd‑mox invocation environment from None and append PWD only when a cwd is provided; derive cwd from passthrough env (PWD) and pass it to the subprocess invoker so passthrough commands execute in the intended directory.
Workspace model change
lading/workspace/models.py
Deduplicate dependency names using a set comprehension and return a sorted tuple for per‑crate dependency lists when constructing the dependency graph.
Pytest config
tests/conftest.py
Register E2E step plugin by adding "tests.e2e.steps.test_e2e_steps" to pytest_plugins.
E2E package & loader
tests/e2e/__init__.py, tests/e2e/test_e2e.py
Add E2E package initializer and a pytest‑bdd scenario loader referencing features/e2e.feature.
E2E fixtures
tests/e2e/conftest.py
Add fixtures: e2e_workspace_root, e2e_workspace, e2e_git_repo, e2e_workspace_with_git, and staging_cleanup.
E2E feature
tests/e2e/features/e2e.feature
Add BDD scenarios for bumping versions and dry‑run publish asserting manifest updates, dependency propagation, staging and publish ordering.
E2E helpers (git & workspace builders)
tests/e2e/helpers/*
Add package init; add Git helpers with GitCommandError, checked runners and convenience functions; add create_nontrivial_workspace and NonTrivialWorkspace that write workspace files and produce a cargo metadata payload.
E2E step implementations
tests/e2e/steps/*
Add BDD step definitions to stub cargo, run CLI (bump/publish), and assert manifests, dependency updates, staging behaviour and publish invocations.
E2E test helpers
tests/e2e/helpers/e2e_steps_helpers.py
Add CLI runner, dependency extraction, cargo metadata stubbing, staging root finder, record filtering, and E2EExpectationError helpers.
Unit tests
tests/unit/publish/test_publish_execution_helpers.py, tests/unit/test_e2e_workspace_builder.py, tests/unit/test_workspace_models_validation.py
Add tests for cwd vs PWD behaviour in publish execution, workspace builder structure and serialisability, and topological sort deduplication of duplicate dependency edges.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Tester as pytest‑bdd
    participant CLI as lading CLI
    participant CmdMox as CmdMox (cargo stub)
    participant Git as Git repo
    participant FS as Filesystem

    Tester->>CLI: trigger bump / publish scenario
    CLI->>CmdMox: request cargo metadata (stubbed)
    CmdMox-->>CLI: return metadata & record invocations
    CLI->>FS: update Cargo.toml, README, write staging files
    CLI->>Git: run git add/commit/status (real git helpers)
    Git-->>CLI: commit/status responses
    CLI->>CmdMox: run cargo package / publish (passthrough or stub) with cwd from PWD when provided
    CmdMox-->>CLI: record package/publish invocations
    CLI-->>Tester: emit stdout (includes staging root) and exit code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect lading/commands/publish_execution.py to confirm PWD injection and subprocess cwd use do not alter other environment behaviour.
  • Verify lading/workspace/models.py deduplication preserves intended topological ordering and semantics.
  • Review tests/e2e/helpers/git_helpers.py subprocess handling and GitCommandError message clarity.
  • Validate tests/e2e/helpers/workspace_builder.py writes correct Cargo.toml, lading.toml, README and produces the declared cargo metadata payload.
  • Audit BDD steps in tests/e2e/steps/test_e2e_steps.py for brittle assertions, correct cargo stubbing, and proper cleanup.
  • Confirm pytest plugin registration in tests/conftest.py does not conflict with existing discovery.

Poem

In testbeds where the crates align,
Git hums a tune and cargo signs,
Steps march through bump and staged deploy,
Mocks keep publish snug and coy,
Green lights blink — let pipelines shine. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and comprehensively describes the main changes: adding end-to-end tests for lading and extending the test suite and documentation.
Description check ✅ Passed The description is detailed and clearly related to the changeset, covering the E2E framework, fixtures, scenarios, step definitions, unit tests, and documentation updates.
Docstring Coverage ✅ Passed Docstring coverage is 88.57% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch terragon/e2e-tests-bump-publish-l8k03f

📜 Recent review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6349394 and 650fedb.

📒 Files selected for processing (1)
  • docs/lading-design.md (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Use the markdown files within the docs/ directory as a knowledge base and source of truth for project requirements, dependency choices, and architectural decisions.
Proactively update relevant files in the docs/ directory when new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve to keep documentation accurate and current.

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-GB-oxendict) with suffixes: -ize in words like 'realize' and 'organization', -lyse in words like 'analyse' and 'paralyse', -our in words like 'colour' and 'behaviour', -re in words like 'centre' and 'calibre', double 'l' in words like 'cancelled' and 'counsellor', maintain 'e' in words like 'likeable', -ogue in words like 'catalogue'
Use the Oxford comma in documentation: 'ships, planes, and hovercraft' where it aids comprehension
Treat company names as collective nouns in documentation, for example 'Lille Industries are expanding'
Write headings in sentence case
Use Markdown headings (#, ##, ###, and so on) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
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 Markdown
Prefer inline links using text or angle brackets around the URL in Markdown
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown
Ensure tables have a delimiter line below the header row in Markdown
Expand any uncommon acronym on first use, for example, Continuous Integration (CI)
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use footnotes referenced with [^label] in Markdown documentation
Include Mermaid diagrams in documentation where they add clarity
When embedding figures in documentation, use ![alt text](path/to...

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: For Markdown files (.md only), ensure changes pass lint checks via make markdownlint.
For Markdown files (.md only), ensure Mermaid diagrams pass validation using nixie via make nixie.

Files:

  • docs/lading-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/lading-design.md
🪛 LanguageTool
docs/lading-design.md

[grammar] ~188-~188: Did you mean the noun “publishing”?
Context: ...edictable. #### Publish data flow The publish data flow shows how the publish command...

(PREPOSITION_VERB)


[grammar] ~483-~483: Did you mean the noun “publishing”?
Context: ...s applied. Preflight failures abort the publish workflow; success advances to crate-by-...

(PREPOSITION_VERB)

🔍 Remote MCP Deepwiki

The repository is not yet indexed. Let me search for broader context about the project structure and E2E testing practices.Based on my research, I now have sufficient context to provide a focused summary of relevant information for reviewing this PR.

Summary of Relevant Context for PR Review

Project Context

The lading project is a Rust CLI tool for managing workspace-based crate versioning and publishing workflows. Similar tools like cargo-workspaces optimize the workflow around cargo workspaces with git and cargo by providing utilities to version, publish, execute commands and more. The PR introduces comprehensive end-to-end tests to verify the version bumping and publishing workflows.

pytest-bdd Testing Framework

This PR adopts pytest-bdd for E2E tests. Key framework principles relevant to the review:

  • pytest-bdd implements a subset of the Gherkin language to enable automating project requirements testing and to facilitate behavioral driven development. Unlike many other BDD tools, it does not require a separate runner and benefits from the power and flexibility of pytest.

  • Pytest fixtures written for unit tests can be reused for setup and actions mentioned in feature steps with dependency injection.

  • As a best practice, put commonly shared steps in "conftest.py" and feature-specific steps in the test module. To share steps across multiple feature files, add them to the "conftest.py" file instead of the test modules.

Testing Architecture Observations

The PR's structure aligns with best practices:

  • Shared fixtures in tests/e2e/conftest.py (e2e_workspace_root, e2e_workspace, e2e_git_repo, e2e_workspace_with_git)
  • Feature files in tests/e2e/features/e2e.feature with Gherkin-style scenarios
  • Step definitions organized in tests/e2e/steps/ with helper extraction to tests/e2e/helpers/ (workspace builder, git helpers, step helpers)
  • Mocking strategy using cmd-mox for deterministic cargo command stubbing

Key Changes Summary

  1. Workspace builder (workspace_builder.py): Creates a realistic 3-crate workspace (core, utils, app) with dependencies
  2. Git helpers (git_helpers.py): Provides real Git operations (init, commit, status checks) for E2E tests
  3. Step helpers (e2e_steps_helpers.py): Extracts assertion builders and CLI runners from step logic
  4. Publish execution fix (publish_execution.py): Corrects PWD/CWD handling for passthrough commands
  5. Workspace model fix (workspace/models.py): Deduplicates and sorts dependency lists in topological sort
  6. Two E2E scenarios: Version bump (marks repo dirty) and publish dry-run (validates workflow)

Code Quality Notes for Review

  • The PR addressed reviewer comments on: helper extraction (moved to separate files), PWD/CWD derivation correction, added preflight cargo assertions, and strengthened workspace-builder unit tests
  • Fixture composition pattern (returning tuple (workspace, repo_root) in e2e_workspace_with_git) simplifies step function signatures
  • Documentation updates track E2E approach and mark roadmap items complete

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

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

@sourcery-ai

sourcery-ai Bot commented Dec 14, 2025

Copy link
Copy Markdown

Reviewer's Guide

Implements a new end-to-end testing framework for the lading CLI using a realistic multi-crate Rust workspace in a temporary Git repo, tightens cmd-mox integration around environment/cwd handling, hardens workspace graph topological sorting, and updates docs/roadmap to reflect the new E2E coverage model.

Sequence diagram for cmd-mox invocation and PWD-based cwd handling

sequenceDiagram
    actor Developer
    participant Pytest as Pytest_E2E
    participant Steps as E2E_Steps
    participant CLI as Lading_CLI
    participant Exec as Publish_Execution
    participant Meta as Metadata_Module
    participant CmdMox as Cmd_Mox
    participant Subproc as Subprocess_Context

    Developer->>Pytest: run pytest -k e2e
    Pytest->>Steps: execute BDD scenarios
    Steps->>Steps: create temporary git workspace
    Steps->>CLI: invoke lading publish --stub-cargo

    CLI->>Exec: run_publish_workflow

    Exec->>Exec: _build_cmd_mox_invocation_env(cwd, env)
    Exec->>Meta: _build_invocation_environment(None)
    Meta-->>Exec: base_env
    Exec->>Exec: merge env overrides
    Exec->>Exec: if cwd is not None set PWD in base_env
    Exec-->>CmdMox: invoke stubbed cargo with env (includes PWD)

    CmdMox-->>Exec: passthrough_invocation(invocation)
    Exec->>Exec: _handle_cmd_mox_passthrough(invocation, passthrough_env)
    Exec->>Exec: cwd_value = invocation.env.PWD
    Exec->>Exec: cwd = None if not cwd_value else Path(cwd_value)
    Exec->>Subproc: create _SubprocessContext(cwd, passthrough_env, stdin_data)
    Subproc-->>Exec: result
    Exec-->>CLI: publish result
    CLI-->>Steps: command exit status and outputs
    Steps-->>Pytest: assertions on git status, call order, env
    Pytest-->>Developer: e2e suite result
Loading

Class diagram for workspace models and E2E workspace builder

classDiagram
    class WorkspaceBuilder {
        +Path root_dir
        +build_workspace()
        +write_cargo_toml()
        +write_lading_toml()
        +create_crate(name, version, dependencies)
        +initial_git_commit()
        +generate_metadata_payload()
    }

    class E2EWorkspaceMetadataPayload {
        +dict raw_metadata
        +from_workspace(root_dir)
        +to_cmd_mox_fixture()
    }

    class Workspace {
        +str root_path
        +list~Crate~ crates
        +build_dependency_graph()
    }

    class Crate {
        +str name
        +str version
        +list~Dependency~ dependencies
    }

    class Dependency {
        +str name
        +str requirement
        +bool workspace_local
    }

    class DependencyGraphBuilder {
        +dict~str, tuple~str~~ build_dependency_graph(crates_by_name)
        -bool _is_ordering_dependency(dependency, crates_by_name)
    }

    WorkspaceBuilder --> Workspace : generates
    WorkspaceBuilder --> E2EWorkspaceMetadataPayload : generates
    Workspace "1" -- "*" Crate : contains
    Crate "*" -- "*" Dependency : depends on
    DependencyGraphBuilder --> Workspace : used_by
    DependencyGraphBuilder --> Crate : inspects
    DependencyGraphBuilder --> Dependency : deduplicates by name
Loading

Architecture diagram for lading E2E test stack with cmd-mox and git

graph TD
    Dev[Developer] --> PY[Pytest Runner]

    subgraph E2E_Test_Suite
        PY --> FEAT[BDD Feature Files tests/e2e/features]
        PY --> STEPS[Step Definitions tests/e2e/steps]
        PY --> WB[WorkspaceBuilder helpers/workspace_builder]
        PY --> GH[GitHelpers helpers/git_helpers]
    end

    STEPS --> WB
    STEPS --> GH

    subgraph Temp_Git_Repo
        WS[Multi-crate Rust Workspace]
        GIT[Git History and Status]
    end

    WB --> WS
    GH --> GIT

    STEPS --> CLI[Lading CLI bump/publish]

    subgraph Lading_Internal
        CLI --> PE[Publish_Execution]
        CLI --> WM[Workspace Models]
    end

    PE --> CMENV[Build cmd-mox invocation env]
    CMENV --> CMDM[Cmd-Mox Server]

    subgraph Cmd_Mox
        CMDM --> CARGO_STUB[Stubbed cargo metadata/check/test/package/publish]
        CMDM --> GIT_SPY[Passthrough spy git status]
    end

    CARGO_STUB -.no real Rust toolchain.- X[Rust Toolchain]

    GIT_SPY --> GIT
    WS --> WM

    STEPS --> ASSERT[Assertions on versions, README, git-dirty state]
    ASSERT --> PY
    PY --> Dev
Loading

File-Level Changes

Change Details Files
Ensure cmd-mox invocations and passthroughs use deterministic environments and working directories.
  • Introduce minimal in-test cmd-mox environment, IPC, and command runner stubs to exercise passthrough handling.
  • Change _build_cmd_mox_invocation_env to build from a neutral base environment and explicitly set PWD from the provided cwd, while still merging user overrides.
  • Update _handle_cmd_mox_passthrough so subprocesses run with cwd derived from the invocation’s PWD, and add unit tests to verify PWD precedence and cwd propagation.
tests/unit/publish/test_publish_execution_helpers.py
lading/commands/publish_execution.py
Deduplicate dependency edges in the workspace graph so topological sorting is stable in the presence of multiple dependency kinds.
  • Update _build_dependency_graph to construct dependency name sets before sorting, eliminating duplicate edges arising from multiple dependency kinds on the same crate.
  • Add a unit test that builds a three-crate graph with duplicate dependencies and asserts the topological order core → utils → app.
lading/workspace/models.py
tests/unit/test_workspace_models_validation.py
Add an end-to-end testing scaffold that builds a non-trivial Rust workspace in a real Git repo and drives the lading CLI through bump and publish flows with cmd-mox stubbing cargo.
  • Introduce tests/e2e package with pytest-bdd feature file, step definitions, fixtures, and a thin test runner to execute CLI flows in a temporary Git repository.
  • Implement a NonTrivialWorkspace builder that writes a three-crate workspace (core, utils, app), a shared workspace README, lading.toml, and a cargo metadata JSON payload suitable for stubbing.
  • Provide git_helpers that wrap real git init/config/add/commit/status operations and safe directory cleanup for E2E tests.
  • Add BDD feature scenarios that cover bumping versions (including manifest/README updates and dirty working tree) and dry-run publish (including package/publish call ordering and README staging).
  • Wire the new E2E step module into the global pytest-bdd plugin discovery via tests/conftest.py and add unit tests for the workspace builder.
tests/conftest.py
tests/e2e/__init__.py
tests/e2e/conftest.py
tests/e2e/features/e2e.feature
tests/e2e/test_e2e.py
tests/e2e/steps/__init__.py
tests/e2e/steps/test_e2e_steps.py
tests/e2e/helpers/__init__.py
tests/e2e/helpers/workspace_builder.py
tests/e2e/helpers/git_helpers.py
tests/unit/test_e2e_workspace_builder.py
Document the new E2E testing approach and mark the roadmap item as complete.
  • Adjust lading-design.md to reflow the proposed directory structure snippet and describe that end-to-end behavioural coverage now lives under tests/e2e/ using real git and stubbed cargo via cmd-mox.
  • Clarify usage-guide.md with a note that E2E tests keep git real but stub cargo operations with cmd-mox passthrough spies for git status in stub mode.
  • Update docs/roadmap.md to mark the “Create End-to-End Test Suite” item as completed.
docs/lading-design.md
docs/usage-guide.md
docs/roadmap.md

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.

@macroscopeapp

macroscopeapp Bot commented Dec 14, 2025

Copy link
Copy Markdown

Add end-to-end tests for lading and update publish execution to pass PWD as cwd for cmd-mox passthroughs in publish_execution.py

Add E2E suite under tests/e2e/ covering bump and dry-run publish; update publish_execution._build_cmd_mox_invocation_env to set PWD when cwd is provided and change passthroughs to use PWD as subprocess cwd; deduplicate workspace dependency edges in workspace.models.WorkspaceGraph._build_dependency_graph; update docs to reflect E2E coverage and publish flow.

📍Where to Start

Start with publish_execution._build_cmd_mox_invocation_env and publish_execution._handle_cmd_mox_passthrough in publish_execution.py, then review E2E scenarios in tests/e2e/features/e2e.feature.


Macroscope summarized 6349394.

@leynos

leynos commented Dec 14, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/e2e/steps/test_e2e_steps.py

Comment on lines +159 to +160

            if require_target_dir and (
                len(args) < 3 or not args[2].startswith("--target-dir=")

❌ New issue: Complex Conditional
given_cargo_commands_stubbed has 1 complex conditionals with 2 branches, threshold = 2

@leynos

leynos commented Dec 14, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/e2e/steps/test_e2e_steps.py

Comment on lines +121 to +133

def given_nontrivial_workspace_in_git_repo(
    version: str,
    cmd_mox: CmdMox,
    monkeypatch: pytest.MonkeyPatch,
    e2e_git_repo: Path,
    e2e_workspace: workspace_builder.NonTrivialWorkspace,
) -> dict[str, typ.Any]:
    """Create a non-trivial workspace fixture and stub cargo metadata."""
    if version != "0.1.0":
        raise E2EExpectationError.unsupported_fixture_version(version)
    monkeypatch.setenv("LADING_USE_CMD_MOX_STUB", "1")
    _stub_cargo_metadata(cmd_mox, e2e_workspace)
    return {"workspace": e2e_workspace, "git_repo": e2e_git_repo}

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

@leynos

leynos commented Dec 14, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/unit/publish/test_publish_execution_helpers.py

Comment on lines +188 to +275

def test_handle_cmd_mox_passthrough_uses_pwd_for_cwd(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
) -> None:
    """Passthrough subprocesses should run with cwd derived from PWD."""

    class _Env:
        CMOX_IPC_SOCKET_ENV = "CMOX_IPC_SOCKET"
        CMOX_REAL_COMMAND_ENV_PREFIX = "CMOX_REAL_"

    class _IPC:
        class Response:
            pass

        class PassthroughResult:
            def __init__(
                self, invocation_id: str, stdout: str, stderr: str, exit_code: int
            ) -> None:
                self.invocation_id = invocation_id
                self.stdout = stdout
                self.stderr = stderr
                self.exit_code = exit_code

        def report_passthrough_result(self, result: object, timeout: float) -> object:
            return result

    class _CommandRunner:
        def prepare_environment(
            self,
            lookup_path: str,
            extra_env: dict[str, str],
            invocation_env: dict[str, str],
        ) -> dict[str, str]:
            return {"PATH": lookup_path} | extra_env | invocation_env

        def resolve_command_with_override(
            self, command: str, path: str, override: str | None
        ) -> Path:
            return Path(sys.executable)

    shim_socket = tmp_path / "cmox" / "shim" / "socket"
    shim_socket.parent.mkdir(parents=True, exist_ok=True)
    monkeypatch.setenv("CMOX_IPC_SOCKET", str(shim_socket))

    directive = SimpleNamespace(
        invocation_id="cwd-test",
        lookup_path=str(tmp_path / "cmox" / "bin"),
        extra_env={},
    )
    expected_cwd = tmp_path / "workspace"
    invocation = SimpleNamespace(
        env={"PATH": str(tmp_path / "cmox" / "bin"), "PWD": str(expected_cwd)},
        command="git",
        args=("status",),
        stdin="",
    )
    modules = publish_execution.CmdMoxModules(
        ipc=_IPC(),
        env=_Env,
        command_runner=_CommandRunner(),
    )

    captured: dict[str, Path | None] = {"cwd": None}

    def _fake_invoke_via_subprocess(
        program: str,
        args: tuple[str, ...],
        context: publish_execution._SubprocessContext,
    ) -> tuple[int, str, str]:
        del program, args
        captured["cwd"] = context.cwd
        return 0, "", ""

    monkeypatch.setattr(
        publish_execution, "_invoke_via_subprocess", _fake_invoke_via_subprocess
    )
    response = SimpleNamespace(passthrough=directive)

    returned, streamed = publish_execution._handle_cmd_mox_passthrough(
        response,
        invocation,
        timeout=1.0,
        modules=modules,
    )

    assert streamed is True
    assert isinstance(returned, _IPC.PassthroughResult)
    assert captured["cwd"] == expected_cwd

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

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

- Introduced standalone mock classes for cmd-mox environment, IPC, and command runner
- Replaced nested classes inside test with these reusable mocks
- Added helper function to check valid --target-dir flag in e2e step tests
- Improved clarity and maintainability of cmd-mox related test code

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Add end-to-end test suite for lading CLI Add end-to-end tests for lading CLI and adjust cmd-mox handling Dec 14, 2025
codescene-delta-analysis[bot]

This comment was marked as outdated.

Introduce e2e_workspace_with_git fixture that returns a tuple of the E2E workspace
and its Git repository root. Update the related test to use this fixture for
better clarity and reuse. Also fix instantiation in unit test mocks.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Add end-to-end tests for lading CLI and adjust cmd-mox handling Add end-to-end tests for lading CLI and improve cmd-mox, tests, and docs Dec 14, 2025
@leynos
leynos marked this pull request as ready for review December 14, 2025 22:17
sourcery-ai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

- Change publish command to ensure cwd is derived from passthrough_env
- Add E2E test step to verify cargo check and cargo test run before publish
- Refactor E2E step filtering logic for cleaner test code
- Enhance unit tests for workspace builder with detailed dependency and config assertions
- Improve test helpers with more explicit path handling and type refinements

These changes improve the publish workflow by enforcing cargo preflight steps
and strengthen the test suite coverage and maintainability.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Add end-to-end tests for lading CLI and improve cmd-mox, tests, and docs Add end-to-end tests for lading and expand unit tests/docs Dec 14, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68d4a8c and 385801d.

📒 Files selected for processing (5)
  • lading/commands/publish_execution.py (2 hunks)
  • tests/e2e/features/e2e.feature (1 hunks)
  • tests/e2e/helpers/git_helpers.py (1 hunks)
  • tests/e2e/steps/test_e2e_steps.py (1 hunks)
  • tests/unit/test_e2e_workspace_builder.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: For Python files, ensure changes pass all relevant unit and behavioral tests according to testing guidelines.
For Python files, ensure changes pass lint checks via make lint.
For Python files, ensure changes adhere to formatting standards via make check-fmt.
For Python files, ensure changes pass type checking via make typecheck.
For Python development, refer to detailed guidelines in the .rules/ directory including Python Code Style Guidelines, Context Managers, Exception Design/Raising/Handling/Logging, Generators, Project Configuration, Return Patterns, and Typing best practices.

**/*.py: Use snake_case.py for Python file names, naming them for their contents
Use PascalCase for class names
Use snake_case for variable and function names
Use UPPER_SNAKE_CASE for module-level constants
Prefix private or internal helpers with a single underscore (_)
Enable and maintain full static type coverage using Pyright; use typing everywhere
Use TypedDict or @DataClass(slots=True) for structured data
Avoid Any; use precise types (TypeVar, Protocol, Literal, Union) and typing.cast only when necessary with justification
Be explicit with return type annotations using -> None, -> str, etc., for all public functions and class methods
Prefer immutability: use tuples over lists and types.MappingProxyType for read-only mappings
Enforce strict mode in Pyright; treat all Pyright warnings as CI errors and use # pyright: ignore sparingly with explanation
Avoid side effects at import time; modules should not modify global state or perform actions on import
Document public functions, classes, and modules using NumPy-format docstrings
Use inline comments to explain tricky code and non-obvious logic

**/*.py: Use context managers (via contextlib.contextmanager or __enter__/__exit__ methods) to encapsulate setup and teardown logic for resource management (files, locks, connections, etc.)
Use @contextlib.contextmanager decorator for straightforward procedural setup...

Files:

  • tests/unit/test_e2e_workspace_builder.py
  • lading/commands/publish_execution.py
  • tests/e2e/helpers/git_helpers.py
  • tests/e2e/steps/test_e2e_steps.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep C90 / mccabe complexity ≤ 9

  • Follow single responsibility and CQRS (command/query segregation)
  • Prefer structural pattern matching to
  • Prefer structural pattern matching over isinstance() or imperative decomposition.
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename ele...

Files:

  • tests/unit/test_e2e_workspace_builder.py
  • lading/commands/publish_execution.py
  • tests/e2e/helpers/git_helpers.py
  • tests/e2e/steps/test_e2e_steps.py
**/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

**/test_*.py: Use pytest idioms: prefer fixtures over setup/teardown, parametrize broadly, avoid unnecessary mocks
Group related tests using class with method names prefixed by test_
Write tests from a user's perspective; test public behavior, not internals
Avoid mocking too much; prefer test doubles only for external services or non-deterministic behaviors

Files:

  • tests/unit/test_e2e_workspace_builder.py
  • tests/e2e/steps/test_e2e_steps.py
**/*test*.py

📄 CodeRabbit inference engine (.rules/python-exception-design-raising-handling-and-logging.md)

In tests, use narrow exception assertions with pytest.raises() specifying the expected type and optionally constraining the message via regex (B017)

Files:

  • tests/unit/test_e2e_workspace_builder.py
  • tests/e2e/steps/test_e2e_steps.py
🧬 Code graph analysis (3)
tests/unit/test_e2e_workspace_builder.py (2)
crate_tools/unittests/test_publish_workspace_dependencies.py (1)
  • workspace_root (16-21)
tests/e2e/helpers/workspace_builder.py (1)
  • create_nontrivial_workspace (26-91)
lading/commands/publish_execution.py (2)
lading/workspace/metadata.py (1)
  • _build_invocation_environment (161-168)
crate_tools/unittests/publish_check/conftest.py (1)
  • env (289-292)
tests/e2e/steps/test_e2e_steps.py (5)
tests/e2e/helpers/workspace_builder.py (1)
  • NonTrivialWorkspace (17-23)
tests/e2e/conftest.py (4)
  • e2e_workspace_with_git (43-48)
  • e2e_workspace (26-28)
  • e2e_git_repo (32-39)
  • staging_cleanup (52-60)
lading/testing/toml_utils.py (1)
  • load_manifest (166-188)
tests/e2e/helpers/git_helpers.py (1)
  • git_status_porcelain (68-71)
tests/unit/conftest.py (1)
  • staging_root (184-186)
⏰ 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 (14)
lading/commands/publish_execution.py (2)

133-142: Explicit PWD handling addresses environment consistency.

The refactored approach correctly builds the base environment without PWD, then explicitly sets it only when cwd is provided. This prevents stale or inherited PWD values from leaking into invocations.


295-298: cwd now derived from passthrough_env for consistency.

The subprocess working directory is correctly derived from passthrough_env["PWD"], ensuring the filesystem cwd matches the PWD visible to the child process. This addresses the prior concern about environment consistency.

tests/unit/test_e2e_workspace_builder.py (1)

16-42: LGTM! Comprehensive structure and content assertions.

The test correctly validates the workspace layout, README TOML snippet, and lading.toml configuration entries that the E2E scenarios depend on. This guards against accidental fixture changes breaking E2E tests.

tests/e2e/helpers/git_helpers.py (1)

11-31: LGTM! Well-structured exception class.

GitCommandError correctly stores structured attributes (command, exit_code, stdout, stderr) and formats a descriptive message. This follows the coding guideline to add structured attributes to exception classes.

tests/e2e/features/e2e.feature (1)

1-21: LGTM! Well-defined E2E scenarios.

Both scenarios clearly exercise the core workflows:

  1. Version bumping with manifest/dependency/README updates and git dirty-state verification
  2. Dry-run publishing with preflight, ordering, package, and staging assertions

The "cargo preflight was run for the workspace" step at line 17 addresses the prior review feedback about asserting preflight invocations.

tests/e2e/steps/test_e2e_steps.py (9)

23-32: LGTM! Properly typed protocols.

The _CmdMoxInvocation and _CmdMoxDouble protocols use precise types (Sequence[str], Mapping[str, str], list[_CmdMoxInvocation]) rather than Any, addressing the prior review feedback.


35-68: LGTM! Well-designed error class with factory methods.

E2EExpectationError follows the coding guideline to add structured error generation via factory classmethods. Each method produces a specific, descriptive message.


71-91: LGTM! Clean CLI invocation helper.

The helper correctly uses plumbum's context manager for cwd, copies the current environment, and returns a structured result dict capturing all relevant execution details.


94-103: Pattern matching addresses prior review feedback.

The structural match/case implementation is cleaner than the previous isinstance chain. The recursive handling for table entries correctly extracts nested version requirements.


116-132: Composite fixture reduces parameter count as requested.

The step function now accepts e2e_workspace_with_git composite fixture, reducing parameters from 5 to 4 and addressing the PR objective about excess function arguments.


146-148: Helper extraction addresses complexity concern.

The _has_valid_target_dir helper extracts the conditional logic as suggested in the PR objectives, improving readability of the _recording_handler closure.


289-293: Helper extraction eliminates record-filtering duplication.

The _filter_records helper centralises the repeated [record for record in publish_spies["records"] if record[0] == ...] pattern as suggested in prior review feedback.


296-302: Preflight assertion step addresses prior review concern.

The then_cargo_preflight_ran step verifies that both cargo::check and cargo::test preflight commands were invoked, addressing the prior feedback about asserting these calls.


337-361: LGTM! Proper cleanup with try/finally.

The then_readme_staged step correctly uses try/finally to ensure staging_cleanup runs regardless of assertion outcomes. The validation logic is clear and thorough.

Comment thread tests/e2e/helpers/git_helpers.py
Comment thread tests/e2e/helpers/git_helpers.py Outdated
Comment thread tests/e2e/steps/test_e2e_steps.py Outdated
Comment thread tests/unit/test_e2e_workspace_builder.py Outdated
Comment thread tests/unit/test_e2e_workspace_builder.py Outdated
@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

…steps

- Extract common E2E step helper functions and error classes into a new
  helpers file `e2e_steps_helpers.py` for improved modularity.
- Remove duplicate and inline definitions from test step file
  `test_e2e_steps.py`, importing them from the new helpers module.
- Update test step code to use centralized helper functions, reducing
  boilerplate and improving clarity.
- Minor improvements and cleanups in `git_helpers.py` and test utils.
- Clean up documentation formatting in `docs/lading-design.md`.

This refactor enhances maintainability and clarity of e2e tests by
centralizing shared logic and reducing duplication.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Add end-to-end tests for lading and expand unit tests/docs Add end-to-end tests for lading; broaden unit tests/docs and cmd-mox coverage Dec 15, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
tests/unit/test_e2e_workspace_builder.py (1)

10-11: Remove the unnecessary TYPE_CHECKING fallback for Path.

pathlib.Path is always available at runtime. Import it directly.

Apply this diff:

-if typ.TYPE_CHECKING:  # pragma: no cover
-    from pathlib import Path
+from pathlib import Path
In tests/unit/test_e2e_workspace_builder.py at lines 10-11, remove the TYPE_CHECKING guard around the Path import and replace it with a direct import statement (from pathlib import Path) at the module level, so Path is available at runtime without any conditional logic or type annotation fallback.

Based on past review comments.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 385801d and 332ed83.

📒 Files selected for processing (6)
  • docs/lading-design.md (4 hunks)
  • tests/e2e/conftest.py (1 hunks)
  • tests/e2e/helpers/e2e_steps_helpers.py (1 hunks)
  • tests/e2e/helpers/git_helpers.py (1 hunks)
  • tests/e2e/steps/test_e2e_steps.py (1 hunks)
  • tests/unit/test_e2e_workspace_builder.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: For Python files, ensure changes pass all relevant unit and behavioral tests according to testing guidelines.
For Python files, ensure changes pass lint checks via make lint.
For Python files, ensure changes adhere to formatting standards via make check-fmt.
For Python files, ensure changes pass type checking via make typecheck.
For Python development, refer to detailed guidelines in the .rules/ directory including Python Code Style Guidelines, Context Managers, Exception Design/Raising/Handling/Logging, Generators, Project Configuration, Return Patterns, and Typing best practices.

**/*.py: Use snake_case.py for Python file names, naming them for their contents
Use PascalCase for class names
Use snake_case for variable and function names
Use UPPER_SNAKE_CASE for module-level constants
Prefix private or internal helpers with a single underscore (_)
Enable and maintain full static type coverage using Pyright; use typing everywhere
Use TypedDict or @DataClass(slots=True) for structured data
Avoid Any; use precise types (TypeVar, Protocol, Literal, Union) and typing.cast only when necessary with justification
Be explicit with return type annotations using -> None, -> str, etc., for all public functions and class methods
Prefer immutability: use tuples over lists and types.MappingProxyType for read-only mappings
Enforce strict mode in Pyright; treat all Pyright warnings as CI errors and use # pyright: ignore sparingly with explanation
Avoid side effects at import time; modules should not modify global state or perform actions on import
Document public functions, classes, and modules using NumPy-format docstrings
Use inline comments to explain tricky code and non-obvious logic

**/*.py: Use context managers (via contextlib.contextmanager or __enter__/__exit__ methods) to encapsulate setup and teardown logic for resource management (files, locks, connections, etc.)
Use @contextlib.contextmanager decorator for straightforward procedural setup...

Files:

  • tests/unit/test_e2e_workspace_builder.py
  • tests/e2e/conftest.py
  • tests/e2e/helpers/git_helpers.py
  • tests/e2e/helpers/e2e_steps_helpers.py
  • tests/e2e/steps/test_e2e_steps.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep C90 / mccabe complexity ≤ 9

  • Follow single responsibility and CQRS (command/query segregation)
  • Prefer structural pattern matching to
  • Prefer structural pattern matching over isinstance() or imperative decomposition.
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename ele...

Files:

  • tests/unit/test_e2e_workspace_builder.py
  • tests/e2e/conftest.py
  • tests/e2e/helpers/git_helpers.py
  • tests/e2e/helpers/e2e_steps_helpers.py
  • tests/e2e/steps/test_e2e_steps.py
**/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

**/test_*.py: Use pytest idioms: prefer fixtures over setup/teardown, parametrize broadly, avoid unnecessary mocks
Group related tests using class with method names prefixed by test_
Write tests from a user's perspective; test public behavior, not internals
Avoid mocking too much; prefer test doubles only for external services or non-deterministic behaviors

Files:

  • tests/unit/test_e2e_workspace_builder.py
  • tests/e2e/steps/test_e2e_steps.py
**/*test*.py

📄 CodeRabbit inference engine (.rules/python-exception-design-raising-handling-and-logging.md)

In tests, use narrow exception assertions with pytest.raises() specifying the expected type and optionally constraining the message via regex (B017)

Files:

  • tests/unit/test_e2e_workspace_builder.py
  • tests/e2e/conftest.py
  • tests/e2e/steps/test_e2e_steps.py
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Use the markdown files within the docs/ directory as a knowledge base and source of truth for project requirements, dependency choices, and architectural decisions.
Proactively update relevant files in the docs/ directory when new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve to keep documentation accurate and current.

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-GB-oxendict) with suffixes: -ize in words like 'realize' and 'organization', -lyse in words like 'analyse' and 'paralyse', -our in words like 'colour' and 'behaviour', -re in words like 'centre' and 'calibre', double 'l' in words like 'cancelled' and 'counsellor', maintain 'e' in words like 'likeable', -ogue in words like 'catalogue'
Use the Oxford comma in documentation: 'ships, planes, and hovercraft' where it aids comprehension
Treat company names as collective nouns in documentation, for example 'Lille Industries are expanding'
Write headings in sentence case
Use Markdown headings (#, ##, ###, and so on) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
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 Markdown
Prefer inline links using text or angle brackets around the URL in Markdown
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown
Ensure tables have a delimiter line below the header row in Markdown
Expand any uncommon acronym on first use, for example, Continuous Integration (CI)
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use footnotes referenced with [^label] in Markdown documentation
Include Mermaid diagrams in documentation where they add clarity
When embedding figures in documentation, use ![alt text](path/to...

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: For Markdown files (.md only), ensure changes pass lint checks via make markdownlint.
For Markdown files (.md only), ensure Mermaid diagrams pass validation using nixie via make nixie.

Files:

  • docs/lading-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/lading-design.md
🧬 Code graph analysis (3)
tests/unit/test_e2e_workspace_builder.py (2)
crate_tools/unittests/test_publish_workspace_dependencies.py (1)
  • workspace_root (16-21)
tests/e2e/helpers/workspace_builder.py (1)
  • create_nontrivial_workspace (26-91)
tests/e2e/conftest.py (2)
tests/e2e/helpers/workspace_builder.py (2)
  • NonTrivialWorkspace (17-23)
  • create_nontrivial_workspace (26-91)
tests/e2e/helpers/git_helpers.py (5)
  • git_init (49-51)
  • git_config_user (54-57)
  • git_add_all (60-62)
  • git_commit (65-67)
  • rmtree (81-86)
tests/e2e/helpers/e2e_steps_helpers.py (4)
crate_tools/unittests/publish_check/conftest.py (1)
  • env (289-292)
tests/conftest.py (1)
  • repo_root (27-29)
crate_tools/unittests/test_publish_workspace_dependencies.py (1)
  • workspace_root (16-21)
tests/e2e/helpers/workspace_builder.py (1)
  • NonTrivialWorkspace (17-23)
🪛 LanguageTool
docs/lading-design.md

[grammar] ~421-~421: The verb ‘publish’ does not usually follow articles like ‘the’. Check that ‘publish’ is spelled correctly; using ‘publish’ as a noun may be non-standard.
Context: ...he patch stripping strategy based on the publish.strip_patches configuration and the ...

(A_INFINITIVE)

🔍 Remote MCP Ref

Let me search for general information about these technologies and testing patterns:Based on my search results, I now have sufficient context to provide a comprehensive summary of relevant technical information for this PR review.

Summary of Relevant Context for PR Review

pytest-bdd Framework Best Practices

Step definition module names do not need to be the same as feature file names, and any step definition can be used by any feature file within the same project. pytest-BDD seamlessly integrates with the powerful features of the Pytest framework, such as fixtures, plugins, and parameterization. Step definitions can have "yield" statements, which will be executed as normal fixtures with code after the yield executed during teardown of the test.

The PR's approach of organizing E2E tests using pytest-bdd follows established patterns: feature files describing scenarios in Gherkin syntax, step definitions using @given/@when/@then decorators, and pytest fixtures for test setup and state management.

Plumbum Library for Shell Command Execution

Plumbum is a small yet feature-rich library for shell script-like programs in Python that attempts to mimic the shell syntax while keeping it all Pythonic and cross-platform, with the motto of "Never write shell scripts again". The library provides local and remote command execution (over SSH), local and remote file-system paths, easy working-directory and environment manipulation, and a programmatic Command-Line Interface (CLI) application toolkit.

The PR's use of plumbum in tests/e2e/helpers/git_helpers.py to execute git commands (_run_git) is an appropriate choice for subprocess execution in Python, providing cleaner syntax and better error handling than raw subprocess calls.

Testing CLI Applications with Cargo/Rust

Integration tests live in /tests and only have access to the public interface of a crate, and one can run the binary using assert_cmd and assert various things about the execution and output. Binary targets are automatically built if there is an integration test or benchmark being selected to test, allowing an integration test to execute the binary to exercise and test its behavior, with the CARGO_BIN_EXE_ environment variable set when the integration test is built.

The PR's approach of creating a non-trivial Rust workspace fixture and running the lading CLI against it while stubbing cargo interactions aligns with standard Rust CLI testing practices.

Code Review Comments - Specific Issues Identified

The PR context indicates three code-quality issues raised in review:

  1. Complex conditional in given_cargo_commands_stubbed: The condition if require_target_dir and (len(args) < 3 or not args[2].startswith("--target-dir=")) should be extracted into a helper function for readability.

  2. Function parameter count in given_nontrivial_workspace_in_git_repo: Five parameters exceed the recommended threshold; the context notes a composite fixture e2e_workspace_with_git was already added to tests/e2e/conftest.py to address this.

  3. Large test function test_handle_cmd_mox_passthrough_uses_pwd_for_cwd: Mock classes should be moved to module level to reduce function length.

The context indicates some of these issues were partially resolved (cwd derivation in publish_execution.py, fixture addition), but the helpers extraction and documentation formatting remain unresolved.

Key Technical Insights for Review

  • The E2E test structure uses pytest fixtures with clear scoping (e2e_workspace_root, e2e_workspace, e2e_git_repo, e2e_workspace_with_git) for test isolation and reusability.
  • The cmd-mox integration pattern of stubbing cargo operations while keeping git interactions real is a sound approach for deterministic E2E testing.
  • The changes to _build_cmd_mox_invocation_env and _handle_cmd_mox_passthrough to respect PWD/cwd handling ensure subprocess invocations execute in the correct directory context.
  • Topological sort deduplication (converting generator to set in build_dependency_graph) prevents false cycles from duplicate dependency edges.,,
⏰ 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 (8)
tests/unit/test_e2e_workspace_builder.py (2)

14-44: Comprehensive validation of workspace structure.

The focused assertions on README fenced blocks, lading.toml configuration keys, and per-crate file existence ensure the E2E fixture produces the expected layout. This guards against accidental changes that could silently break downstream scenarios.


64-74: Dependency graph validation covers the expected structure.

The signature checks for utils and app dependencies confirm that the metadata payload correctly encodes inter-crate relationships (including dependency kinds: normal, dev, build), addressing the previous review feedback on metadata wiring.

docs/lading-design.md (1)

576-581: Documented E2E layout matches the new tests.

Keep this paragraph; it accurately describes the new tests/e2e/ layout and the use of real Git plus cmd-mox stubs for cargo, matching the fixtures and helpers in this PR.

tests/e2e/helpers/git_helpers.py (1)

1-86: Git helper wrappers and error reporting are sound.

Retain this structure; GitCommandError surfaces rich context for failed Git commands, _run_git_checked centralises exit-code handling, and the public helpers (git_init, git_config_user, git_add_all, git_commit, git_status_porcelain, git_is_clean, rmtree) give the E2E layer a clear, minimal API. rmtree now ignores only missing paths, which matches the docstring and keeps genuine errors visible.

tests/e2e/helpers/e2e_steps_helpers.py (1)

20-121: E2E helper extraction keeps step definitions focused and reusable.

Keep this module as the shared home for E2E utilities: E2EExpectationError gives precise failure messages, run_cli drives the CLI in a controlled environment, extract_dependency_requirement uses structural pattern matching to handle TOML variants, and stub_cargo_metadata / find_staging_root / filter_records encapsulate cmd-mox and output parsing details. This cleanly removes helper noise from the step file and aligns with the earlier review feedback about separation.

tests/e2e/steps/test_e2e_steps.py (2)

29-131: Workspace + Git setup and CLI invocation steps are well structured.

Retain this arrangement: given_nontrivial_workspace_in_git_repo now uses the composite e2e_workspace_with_git fixture and stub_cargo_metadata, and when_run_lading_bump / when_run_lading_publish delegate to run_cli with repo_root and workspace.root, which keeps command execution and environment handling centralised. The _has_valid_target_dir helper and _recording_handler in given_cargo_commands_stubbed remove the previous complex conditional and enforce clear expectations on preflight cargo::check / cargo::test invocations.


139-255: End-to-end assertions comprehensively cover bump, publish, and staging behaviour.

Keep this suite of then_… steps; they jointly assert manifest versions, dependency requirements, README contents, Git dirty state, presence of preflight cargo::check/cargo::test calls, publish order via PWD, one cargo package / cargo publish --dry-run per crate, and correct staging + reporting of README copies. Using git_status_porcelain, extract_dependency_requirement, filter_records, and find_staging_root gives strong guarantees while keeping the step definitions readable.

tests/e2e/conftest.py (1)

15-58: E2E fixtures isolate workspace and Git state cleanly.

The fixture graph composes logically: e2e_workspace_roote2e_workspacee2e_git_repoe2e_workspace_with_git. Each fixture follows the guidelines: modern type hints (PEP 604 style), TYPE_CHECKING guard for Path to avoid runtime import costs, NumPy-format docstrings, snake_case naming, and no mutable defaults. The staging_cleanup closure properly encapsulates deletion logic with correct typing. Keep this as-is.

Run the full test suite locally to confirm integration:

make lint
make check-fmt
make typecheck
pytest -k e2e -q

Comment thread docs/lading-design.md Outdated
Comment thread docs/lading-design.md
Comment thread tests/unit/test_e2e_workspace_builder.py
Comment thread tests/unit/test_e2e_workspace_builder.py Outdated
- Refine markdown formatting in design docs for better readability
- Clarify usage of `publish.strip_patches` configuration and flags
- Replace plaintext directory tree with detailed, indented code block and comments
- Add markdownlint directives to disable/enable spacing rules around listing

These changes enhance clarity and maintainability of the project's design documentation.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Add end-to-end tests for lading; broaden unit tests/docs and cmd-mox coverage Add end-to-end tests for lading; tighten cmd-mox env & workspace graph Dec 15, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
docs/lading-design.md (2)

427-471: Align the “Execute Pre-Publish Checks” step title with sentence case.

Normalise this step heading to sentence case to match the preceding “Prepare workspace manifest” entry and the documentation style guide.

Suggested edit:

-2. **Execute Pre-Publish Checks:** Before publishing, run a series of checks in
+2. **Execute pre-flight checks:** Before publishing, run a series of checks in

As per coding guidelines, use sentence case for headings.


501-516: Align the “Iterate and Publish” step title with sentence case.

Normalise this step heading to sentence case for consistency with the other numbered steps and the documentation style guide.

Suggested edit:

-1. **Iterate and Publish:** For each crate in the determined order:
+1. **Iterate and publish:** For each crate in the determined order:

As per coding guidelines, use sentence case for headings.

♻️ Duplicate comments (1)
docs/lading-design.md (1)

524-549: Restore the directory structure block as a fenced plaintext code block.

Wrap the tree in a fenced plaintext block with explicit language and drop the markdownlint MD046 suppression. The current indented HTML-comment-wrapped block is harder to read and bypasses the documented Markdown conventions.

Apply this diff:

-<!-- markdownlint-disable MD046 -->
-    lading/
-      ├── __init__.py
-      ├── cli.py  # Cyclopts app definition + command wiring
-      ├── commands/
-      │   ├── __init__.py
-      │   ├── _shared.py  # Command-level helper utilities
-      │   ├── bump.py  # Logic for the `bump` subcommand
-      │   └── publish.py  # Logic for the `publish` subcommand
-      ├── config.py  # Frozen dataclasses for `lading.toml`
-      ├── utils/
-      │   ├── __init__.py
-      │   └── path.py  # Filesystem helpers (eg `normalise_workspace_root`)
-      └── workspace/
-          ├── __init__.py
-          ├── metadata.py  # `cargo metadata` invocation and parsing
-          └── models.py  # Workspace graph and manifest helpers
-
-    tests/
-      ├── conftest.py
-      ├── fixtures/
-      │   └── simple_workspace/
-      │       ├── Cargo.toml
-      │       └── lading.toml
-      └── test_*.py
-<!-- markdownlint-enable MD046 -->
+```plaintext
+lading/
+  ├── __init__.py
+  ├── cli.py               # Cyclopts app definition and command wiring
+  ├── commands/
+  │   ├── __init__.py
+  │   ├── _shared.py       # Command-level helper utilities
+  │   ├── bump.py          # Logic for the `bump` subcommand
+  │   └── publish.py       # Logic for the `publish` subcommand
+  ├── config.py            # Frozen dataclasses for `lading.toml`
+  ├── utils/
+  │   ├── __init__.py
+  │   └── path.py          # Filesystem helpers (eg `normalise_workspace_root`)
+  └── workspace/
+      ├── __init__.py
+      ├── metadata.py      # `cargo metadata` invocation and parsing
+      └── models.py        # Workspace graph and manifest helpers
+
+tests/
+  ├── conftest.py
+  ├── fixtures/
+  │   └── simple_workspace/
+  │       ├── Cargo.toml
+  │       └── lading.toml
+  └── test_*.py
+```

As per coding guidelines, use fenced code blocks with an explicit language identifier and keep the tree layout readable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 332ed83 and 4f07e05.

📒 Files selected for processing (2)
  • docs/lading-design.md (4 hunks)
  • tests/unit/test_e2e_workspace_builder.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Use the markdown files within the docs/ directory as a knowledge base and source of truth for project requirements, dependency choices, and architectural decisions.
Proactively update relevant files in the docs/ directory when new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve to keep documentation accurate and current.

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-GB-oxendict) with suffixes: -ize in words like 'realize' and 'organization', -lyse in words like 'analyse' and 'paralyse', -our in words like 'colour' and 'behaviour', -re in words like 'centre' and 'calibre', double 'l' in words like 'cancelled' and 'counsellor', maintain 'e' in words like 'likeable', -ogue in words like 'catalogue'
Use the Oxford comma in documentation: 'ships, planes, and hovercraft' where it aids comprehension
Treat company names as collective nouns in documentation, for example 'Lille Industries are expanding'
Write headings in sentence case
Use Markdown headings (#, ##, ###, and so on) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
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 Markdown
Prefer inline links using text or angle brackets around the URL in Markdown
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown
Ensure tables have a delimiter line below the header row in Markdown
Expand any uncommon acronym on first use, for example, Continuous Integration (CI)
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use footnotes referenced with [^label] in Markdown documentation
Include Mermaid diagrams in documentation where they add clarity
When embedding figures in documentation, use ![alt text](path/to...

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: For Markdown files (.md only), ensure changes pass lint checks via make markdownlint.
For Markdown files (.md only), ensure Mermaid diagrams pass validation using nixie via make nixie.

Files:

  • docs/lading-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/lading-design.md
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: For Python files, ensure changes pass all relevant unit and behavioral tests according to testing guidelines.
For Python files, ensure changes pass lint checks via make lint.
For Python files, ensure changes adhere to formatting standards via make check-fmt.
For Python files, ensure changes pass type checking via make typecheck.
For Python development, refer to detailed guidelines in the .rules/ directory including Python Code Style Guidelines, Context Managers, Exception Design/Raising/Handling/Logging, Generators, Project Configuration, Return Patterns, and Typing best practices.

**/*.py: Use snake_case.py for Python file names, naming them for their contents
Use PascalCase for class names
Use snake_case for variable and function names
Use UPPER_SNAKE_CASE for module-level constants
Prefix private or internal helpers with a single underscore (_)
Enable and maintain full static type coverage using Pyright; use typing everywhere
Use TypedDict or @DataClass(slots=True) for structured data
Avoid Any; use precise types (TypeVar, Protocol, Literal, Union) and typing.cast only when necessary with justification
Be explicit with return type annotations using -> None, -> str, etc., for all public functions and class methods
Prefer immutability: use tuples over lists and types.MappingProxyType for read-only mappings
Enforce strict mode in Pyright; treat all Pyright warnings as CI errors and use # pyright: ignore sparingly with explanation
Avoid side effects at import time; modules should not modify global state or perform actions on import
Document public functions, classes, and modules using NumPy-format docstrings
Use inline comments to explain tricky code and non-obvious logic

**/*.py: Use context managers (via contextlib.contextmanager or __enter__/__exit__ methods) to encapsulate setup and teardown logic for resource management (files, locks, connections, etc.)
Use @contextlib.contextmanager decorator for straightforward procedural setup...

Files:

  • tests/unit/test_e2e_workspace_builder.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep C90 / mccabe complexity ≤ 9

  • Follow single responsibility and CQRS (command/query segregation)
  • Prefer structural pattern matching to
  • Prefer structural pattern matching over isinstance() or imperative decomposition.
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename ele...

Files:

  • tests/unit/test_e2e_workspace_builder.py
**/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

**/test_*.py: Use pytest idioms: prefer fixtures over setup/teardown, parametrize broadly, avoid unnecessary mocks
Group related tests using class with method names prefixed by test_
Write tests from a user's perspective; test public behavior, not internals
Avoid mocking too much; prefer test doubles only for external services or non-deterministic behaviors

Files:

  • tests/unit/test_e2e_workspace_builder.py
**/*test*.py

📄 CodeRabbit inference engine (.rules/python-exception-design-raising-handling-and-logging.md)

In tests, use narrow exception assertions with pytest.raises() specifying the expected type and optionally constraining the message via regex (B017)

Files:

  • tests/unit/test_e2e_workspace_builder.py
🧬 Code graph analysis (1)
tests/unit/test_e2e_workspace_builder.py (2)
crate_tools/unittests/test_publish_workspace_dependencies.py (1)
  • workspace_root (16-21)
tests/e2e/helpers/workspace_builder.py (1)
  • create_nontrivial_workspace (26-91)
⏰ 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 (3)
docs/lading-design.md (2)

420-422: Accept the updated publish.strip_patches wording and inline code usage.

Retain this phrasing and formatting; it now reflects sentence case, uses backticks for configuration keys and flags, and mentions the configuration value explicitly as requested.


587-592: Accept the expanded description of end-to-end behavioural coverage.

Retain this bullet as written; it clearly explains the tests/e2e layout, the use of a temporary Git repository, and the cmd-mox stubbing strategy while following en-GB spelling and line-wrapping rules.

tests/unit/test_e2e_workspace_builder.py (1)

46-77: Keep dependency graph and JSON serialisation assertions as written

The dependency set comparisons via _dependency_signature and the final json.dumps(payload) call with the explanatory comment accurately lock in the cargo metadata stub shape and ensure it remains JSON-serialisable without redundant assertions. This gives strong protection against accidental fixture drift that would break the E2E scenarios.

Comment thread tests/unit/test_e2e_workspace_builder.py
…ion check

Corrected inconsistent capitalization of 'pre-flight checks' and 'Iterate and publish' in lading-design.md for style consistency.

In tests/unit/test_e2e_workspace_builder.py, updated the version string assertion to use workspace.version instead of hardcoded "0.1.0" to reflect dynamic versioning in the test.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
tests/unit/test_e2e_workspace_builder.py (1)

10-11: Simplify the Path import by removing the TYPE_CHECKING guard.

With from __future__ import annotations active, type annotations are stringified at runtime, so importing Path unconditionally incurs no runtime cost. Remove the guard for clarity.

Apply this diff:

+from pathlib import Path
+
 if typ.TYPE_CHECKING:  # pragma: no cover
-    from pathlib import Path
+    pass  # Reserved for imports that prevent circular dependencies

Alternatively, remove the block entirely:

-if typ.TYPE_CHECKING:  # pragma: no cover
-    from pathlib import Path
+from pathlib import Path
In tests/unit/test_e2e_workspace_builder.py at lines 10 to 11, remove the TYPE_CHECKING guard around the Path import and import Path unconditionally from pathlib (e.g., from pathlib import Path) since __future__.annotations defers annotation evaluation, making the guard redundant.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f07e05 and 8ebc294.

📒 Files selected for processing (2)
  • docs/lading-design.md (4 hunks)
  • tests/unit/test_e2e_workspace_builder.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Use the markdown files within the docs/ directory as a knowledge base and source of truth for project requirements, dependency choices, and architectural decisions.
Proactively update relevant files in the docs/ directory when new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve to keep documentation accurate and current.

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-GB-oxendict) with suffixes: -ize in words like 'realize' and 'organization', -lyse in words like 'analyse' and 'paralyse', -our in words like 'colour' and 'behaviour', -re in words like 'centre' and 'calibre', double 'l' in words like 'cancelled' and 'counsellor', maintain 'e' in words like 'likeable', -ogue in words like 'catalogue'
Use the Oxford comma in documentation: 'ships, planes, and hovercraft' where it aids comprehension
Treat company names as collective nouns in documentation, for example 'Lille Industries are expanding'
Write headings in sentence case
Use Markdown headings (#, ##, ###, and so on) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
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 Markdown
Prefer inline links using text or angle brackets around the URL in Markdown
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown
Ensure tables have a delimiter line below the header row in Markdown
Expand any uncommon acronym on first use, for example, Continuous Integration (CI)
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use footnotes referenced with [^label] in Markdown documentation
Include Mermaid diagrams in documentation where they add clarity
When embedding figures in documentation, use ![alt text](path/to...

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: For Markdown files (.md only), ensure changes pass lint checks via make markdownlint.
For Markdown files (.md only), ensure Mermaid diagrams pass validation using nixie via make nixie.

Files:

  • docs/lading-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/lading-design.md
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: For Python files, ensure changes pass all relevant unit and behavioral tests according to testing guidelines.
For Python files, ensure changes pass lint checks via make lint.
For Python files, ensure changes adhere to formatting standards via make check-fmt.
For Python files, ensure changes pass type checking via make typecheck.
For Python development, refer to detailed guidelines in the .rules/ directory including Python Code Style Guidelines, Context Managers, Exception Design/Raising/Handling/Logging, Generators, Project Configuration, Return Patterns, and Typing best practices.

**/*.py: Use snake_case.py for Python file names, naming them for their contents
Use PascalCase for class names
Use snake_case for variable and function names
Use UPPER_SNAKE_CASE for module-level constants
Prefix private or internal helpers with a single underscore (_)
Enable and maintain full static type coverage using Pyright; use typing everywhere
Use TypedDict or @DataClass(slots=True) for structured data
Avoid Any; use precise types (TypeVar, Protocol, Literal, Union) and typing.cast only when necessary with justification
Be explicit with return type annotations using -> None, -> str, etc., for all public functions and class methods
Prefer immutability: use tuples over lists and types.MappingProxyType for read-only mappings
Enforce strict mode in Pyright; treat all Pyright warnings as CI errors and use # pyright: ignore sparingly with explanation
Avoid side effects at import time; modules should not modify global state or perform actions on import
Document public functions, classes, and modules using NumPy-format docstrings
Use inline comments to explain tricky code and non-obvious logic

**/*.py: Use context managers (via contextlib.contextmanager or __enter__/__exit__ methods) to encapsulate setup and teardown logic for resource management (files, locks, connections, etc.)
Use @contextlib.contextmanager decorator for straightforward procedural setup...

Files:

  • tests/unit/test_e2e_workspace_builder.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep C90 / mccabe complexity ≤ 9

  • Follow single responsibility and CQRS (command/query segregation)
  • Prefer structural pattern matching to
  • Prefer structural pattern matching over isinstance() or imperative decomposition.
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename ele...

Files:

  • tests/unit/test_e2e_workspace_builder.py
**/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

**/test_*.py: Use pytest idioms: prefer fixtures over setup/teardown, parametrize broadly, avoid unnecessary mocks
Group related tests using class with method names prefixed by test_
Write tests from a user's perspective; test public behavior, not internals
Avoid mocking too much; prefer test doubles only for external services or non-deterministic behaviors

Files:

  • tests/unit/test_e2e_workspace_builder.py
**/*test*.py

📄 CodeRabbit inference engine (.rules/python-exception-design-raising-handling-and-logging.md)

In tests, use narrow exception assertions with pytest.raises() specifying the expected type and optionally constraining the message via regex (B017)

Files:

  • tests/unit/test_e2e_workspace_builder.py
🧬 Code graph analysis (1)
tests/unit/test_e2e_workspace_builder.py (2)
crate_tools/unittests/test_publish_workspace_dependencies.py (1)
  • workspace_root (16-21)
tests/e2e/helpers/workspace_builder.py (1)
  • create_nontrivial_workspace (26-91)
🔍 Remote MCP

Let me try searching the web for additional context on the technologies mentioned:Based on the detailed AI-generated summaries and PR comments provided in your context, I can deliver a focused review summary without additional tool searches. Here's the synthesized information most relevant for your PR review:

Key Technical Review Points

1. Critical Unresolved Issues

Documentation formatting (docs/lading-design.md):

  • The "Proposed Directory Structure" section was converted to a wrapped single-line format but should remain as a fenced code block with proper indentation and newlines for readability and code reference.

Test code organization (tests/e2e/steps/test_e2e_steps.py):

  • Helper utilities (E2EExpectationError, _extract_dependency_requirement, _run_cli, _stub_cargo_metadata) remain mixed with step definitions. These should be extracted to tests/e2e/helpers/e2e_steps_helpers.py to maintain separation of concerns and improve maintainability.

2. Code Quality Issues Flagged

Issue File Recommended Fix
Complex nested conditional tests/e2e/steps/test_e2e_steps.py Extract _has_valid_target_dir(args: tuple[str, ...]) -> bool helper
Function argument count (5 args, threshold 4) tests/e2e/conftest.py Create composite fixture e2e_workspace_with_git returning tuple of (workspace, repo_root)
Mock classes defined inside test tests/unit/publish/test_publish_execution_helpers.py Move _Env, _IPC, _CommandRunner to module-level as _MockCmdMoxEnv, etc.

3. Resolved Changes

  • publish_execution.py: PWD-to-CWD mapping now correctly derives subprocess working directory from passthrough_env.get("PWD") instead of always using None
  • Preflight assertions added: New Then step validates cargo::check and cargo::test invocations during publish scenario
  • Unit test coverage expanded: E2E workspace builder tests now include focused assertions for README content, lading.toml settings, and dependency graph validation

4. Test Infrastructure Summary

New E2E testing framework:

  • Pytest fixtures create non-trivial multi-crate Rust workspaces (core, utils, app) with real Git operations
  • Cargo interactions stubbed via cmd-mox for determinism
  • Two BDD scenarios cover: (1) version bumping with dirty repo detection, (2) dry-run publish with order/invocation validation
  • Workspace builder generates complete Cargo.toml, lading.toml, and README with version placeholders

Workspace graph deduplication:

  • build_dependency_graph now uses set comprehension + sorting to eliminate duplicate dependency edges and ensure consistent topological ordering

5. Testing Recommendations

From PR objectives:

  • Run E2E tests: pytest -k e2e
  • Run unit tests: pytest tests/unit -q
⏰ 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

Comment thread docs/lading-design.md Outdated
@coderabbitai

coderabbitai Bot commented Dec 16, 2025

Copy link
Copy Markdown

Tip

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

🧩 Analysis chain


🏁 Script executed:

#!/bin/bash

echo "=== 1. Checking docs/lading-design.md directory structure formatting ==="
if [ -f docs/lading-design.md ]; then
    # Look for the directory structure section
    grep -n -A 30 -i "proposed directory structure\|directory structure" docs/lading-design.md | head -50
else
    echo "File not found: docs/lading-design.md"
fi

echo ""
echo "=== 2. Checking if helpers were extracted from test_e2e_steps.py ==="
echo "--- Looking for E2EExpectationError in test_e2e_steps.py ---"
grep -n "class E2EExpectationError\|E2EExpectationError =" tests/e2e/steps/test_e2e_steps.py 2>/dev/null || echo "Not found in test_e2e_steps.py"

echo ""
echo "--- Looking for _extract_dependency_requirement in test_e2e_steps.py ---"
grep -n "def _extract_dependency_requirement" tests/e2e/steps/test_e2e_steps.py 2>/dev/null || echo "Not found in test_e2e_steps.py"

echo ""
echo "--- Looking for _run_cli in test_e2e_steps.py ---"
grep -n "def _run_cli" tests/e2e/steps/test_e2e_steps.py 2>/dev/null || echo "Not found in test_e2e_steps.py"

echo ""
echo "--- Checking tests/e2e/helpers/ for extracted helpers ---"
ls -la tests/e2e/helpers/ 2>/dev/null || echo "Directory not found"

echo ""
echo "--- Looking for helpers in tests/e2e/helpers/*.py files ---"
if [ -d tests/e2e/helpers ]; then
    for file in tests/e2e/helpers/*.py; do
        if [ -f "$file" ]; then
            echo "File: $file"
            grep -n "class E2EExpectationError\|def _extract_dependency_requirement\|def _run_cli\|def run_cli\|def extract_dependency" "$file" 2>/dev/null | head -5
        fi
    done
fi

Length of output: 2472


🏁 Script executed:

#!/bin/bash

echo "=== 3. Checking cwd derivation in publish_execution.py ==="
sed -n '290,305p' lading/commands/publish_execution.py

echo ""
echo "=== 4. Checking for preflight assertion step in test_e2e_steps.py ==="
grep -n -A 10 "def then.*preflight\|@then.*preflight" tests/e2e/steps/test_e2e_steps.py 2>/dev/null || echo "Preflight step not found"

echo ""
echo "=== 5. Checking workspace builder test assertions ==="
sed -n '1,80p' tests/unit/test_e2e_workspace_builder.py

Length of output: 4466


🏁 Script executed:

#!/bin/bash

echo "=== Additional check: test_e2e_steps.py imports and structure ==="
head -50 tests/e2e/steps/test_e2e_steps.py

echo ""
echo "=== File line count for test_e2e_steps.py ==="
wc -l tests/e2e/steps/test_e2e_steps.py

Length of output: 1681


@leynos: Yes! All 5 items are now fully resolved. The previous response was incorrect about the first two overall comments. Here's the corrected status:

✅ All Issues Resolved (5 of 5)

Overall Comment 1: Directory structure formatting in docs

Status: ✅ RESOLVED

Lines 524-549 of docs/lading-design.md show the directory structure is properly formatted with newlines and indentation:

    lading/
      ├── __init__.py
      ├── cli.py  # Cyclopts app definition + command wiring
      ├── commands/
      │   ├── __init__.py
      ...

The structure is readable and correctly uses a markdownlint-disable block to allow the indented format.

Overall Comment 2: Helper extraction from test_e2e_steps.py

Status: ✅ RESOLVED

All helpers have been successfully extracted to tests/e2e/helpers/e2e_steps_helpers.py:

  • E2EExpectationError → extracted (line 25)
  • _extract_dependency_requirement → extracted as extract_dependency_requirement (line 85)
  • _run_cli → extracted as run_cli (line 61)
  • Additional helpers: stub_cargo_metadata, find_staging_root, filter_records

The step definitions file now:

  • Imports these helpers (lines 12-20)
  • Is reduced to 255 lines (from 361)
  • Focuses purely on step definitions

Comment 1: cwd derivation from passthrough_env

Status: ✅ RESOLVED

Line 295 correctly uses:

cwd_value = passthrough_env.get("PWD")

Comment 2: Cargo preflight assertion step

Status: ✅ RESOLVED

Lines 190-196 implement the step:

@then("cargo preflight was run for the workspace")
def then_cargo_preflight_ran(publish_spies: dict[str, typ.Any]) -> None:
    check_calls = filter_records(publish_spies, "cargo::check")
    test_calls = filter_records(publish_spies, "cargo::test")
    assert check_calls, "expected at least one cargo::check preflight invocation"
    assert test_calls, "expected at least one cargo::test preflight invocation"

Comment 3: Enhanced workspace builder assertions

Status: ✅ RESOLVED

The test includes comprehensive assertions for:

  • README fenced TOML blocks and per-crate version lines
  • lading.toml containing [bump.documentation], globs, [publish], and strip_patches
  • Cargo metadata dependency graph validation with correct kind values

All review comments have been successfully addressed! 🎉

  /\_/\
 ( o.o )
  > ^ <
(thought you'd caught me out!)

…esign doc

Updated the formatting of the `lading` package directory structure in the lading-design.md documentation. Changed from HTML markdownlint disables and commented lines to a clean plaintext code block with consistent indentation and comments, improving readability and clarity of the project structure proposal.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Add end-to-end tests for lading; tighten cmd-mox env & workspace graph Add end-to-end tests for lading; broaden test coverage and fixes Dec 16, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

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

187-209: Add prose descriptions before Mermaid diagrams for accessibility. The coding guidelines require "a short description before each Mermaid diagram so screen readers can understand it." Currently, only headings (#### Publish data flow and ### Publish Preflight Sequence) precede the diagrams; prose descriptions are needed.

Apply these diffs to add prose descriptions:

At line 186 (before the first diagram):

 #### Publish data flow
+
+The publish data flow shows how the publish command orchestrates manifest
+preparation, crate planning, and command execution. The workflow splits
+configuration-driven patch stripping logic (all vs. per-crate) based on dry-run
+and live modes, and feeds the resulting plan to execution helpers.
+
 ```mermaid

At line 472 (before the second diagram):

 ### Publish Preflight Sequence
+
+The preflight sequence diagram illustrates the pre-flight checks that run
+before crate publication. Auxiliary build commands (if configured) execute
+first, followed by cargo check and cargo test with environment overrides
+applied. Preflight failures abort the publish workflow; success advances to
+crate-by-crate publishing.
+
 ```mermaid

Also applies to: 474-499

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ebc294 and 80adeb4.

📒 Files selected for processing (1)
  • docs/lading-design.md (4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Use the markdown files within the docs/ directory as a knowledge base and source of truth for project requirements, dependency choices, and architectural decisions.
Proactively update relevant files in the docs/ directory when new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve to keep documentation accurate and current.

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-GB-oxendict) with suffixes: -ize in words like 'realize' and 'organization', -lyse in words like 'analyse' and 'paralyse', -our in words like 'colour' and 'behaviour', -re in words like 'centre' and 'calibre', double 'l' in words like 'cancelled' and 'counsellor', maintain 'e' in words like 'likeable', -ogue in words like 'catalogue'
Use the Oxford comma in documentation: 'ships, planes, and hovercraft' where it aids comprehension
Treat company names as collective nouns in documentation, for example 'Lille Industries are expanding'
Write headings in sentence case
Use Markdown headings (#, ##, ###, and so on) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
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 Markdown
Prefer inline links using text or angle brackets around the URL in Markdown
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown
Ensure tables have a delimiter line below the header row in Markdown
Expand any uncommon acronym on first use, for example, Continuous Integration (CI)
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use footnotes referenced with [^label] in Markdown documentation
Include Mermaid diagrams in documentation where they add clarity
When embedding figures in documentation, use ![alt text](path/to...

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: For Markdown files (.md only), ensure changes pass lint checks via make markdownlint.
For Markdown files (.md only), ensure Mermaid diagrams pass validation using nixie via make nixie.

Files:

  • docs/lading-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/lading-design.md
🔍 Remote MCP

Based on the extensive context already provided in your PR materials, I can deliver a comprehensive review summary without additional tool searches, as the AI-generated summaries and PR objectives contain sufficient technical detail.

Consolidated PR Review Summary

Overview

This PR (PR #46) introduces a production-grade end-to-end testing framework for the lading CLI tool—a Rust workspace publishing and versioning utility. The implementation adds ~1,500+ lines of test infrastructure while fixing critical cmd-mox integration issues and workspace dependency-graph handling.


Core Changes

1. End-to-End Test Framework (tests/e2e/)

New test infrastructure:

  • Fixtures (tests/e2e/conftest.py): Provides e2e_workspace_root, e2e_workspace, e2e_git_repo, and e2e_workspace_with_git to create realistic test environments
  • Workspace Builder (tests/e2e/helpers/workspace_builder.py): Generates non-trivial multi-crate Rust workspaces (core, utils, app) with complete Cargo.toml, lading.toml, and README scaffolding
  • Git Helpers (tests/e2e/helpers/git_helpers.py): Provides real git operations (init, commit, status) and custom GitCommandError exception for test diagnostics
  • BDD Scenarios (tests/e2e/features/e2e.feature): Two scenarios validate:
    • Version bumping marks repo dirty after updating manifests and internal dependencies
    • Publishing in dry-run mode with cargo interactions stubbed, verifying publish order and per-crate staging

2. Critical Bug Fixes

PWD/CWD propagation (lading/commands/publish_execution.py):

  • Fixed _handle_cmd_mox_passthrough() to derive subprocess working directory from passthrough_env["PWD"] instead of always using None
  • _build_cmd_mox_invocation_env() now correctly omits PWD when no explicit cwd is provided, preventing environment pollution

Workspace dependency deduplication (lading/workspace/models.py):

  • Changed build_dependency_graph() from generator expression to set comprehension + sorting in dependency_names calculation
  • Eliminates duplicate edges and ensures deterministic topological ordering

3. Documentation Updates

File Changes
docs/lading-design.md Restructured design steps (4,5,6→1,2,etc.), expanded preflight/publish flow narrative with environment controls and staging behavior documentation
docs/roadmap.md Marked "Create End-to-End Test Suite" (Phase 4.1) as complete
docs/usage-guide.md Added clarification on e2e approach: real git + stubbed cargo (cmd-mox passthrough)

Quality Assurance & Test Coverage

New unit tests addressing PR feedback:

  • tests/unit/test_e2e_workspace_builder.py: Validates workspace structure, README content formatting, lading.toml settings, and cargo metadata JSON serializability
  • tests/unit/test_workspace_models_validation.py: Added test_topological_sort_dedupes_duplicate_dependencies to verify deduplication logic
  • tests/unit/publish/test_publish_execution_helpers.py: Extended mocks to validate cwd derivation from PWD in passthrough environment

Test discovery integration:

  • tests/conftest.py now includes "tests.e2e.steps.test_e2e_steps" in pytest_plugins tuple for seamless E2E step discovery

Known Review Items (Per Comments)

Issue Status Notes
Complex conditional for --target-dir validation ✅ Resolved Helper _has_valid_target_dir() extraction suggested and implemented
Function argument count (5 params) ✅ Resolved Composite fixture e2e_workspace_with_git created in conftest.py
Inline mock classes in test ✅ Resolved _Env, _IPC, _CommandRunner moved to module-level in test file
Cargo preflight assertions missing ✅ Resolved Then step added to validate cargo::check and cargo::test invocations
E2E workspace builder tests insufficiently specific ✅ Resolved Enhanced with README formatting, lading.toml, and metadata assertions
Helper code mixed in test_e2e_steps.py ✅ Resolved Extracted to tests/e2e/helpers/e2e_steps_helpers.py (new module)

Verification Recommendations

Test execution:

pytest -k e2e              # Run E2E scenarios (2 scenarios covering bump + publish flows)
pytest tests/unit -q       # Run unit tests for workspace builder and dependency graph

Expected outcomes:

  • E2E tests should demonstrate deterministic version propagation, README updates, and Git state tracking
  • Stubbed cargo operations ensure no network/build side effects
  • Unit tests validate workspace structure assumptions (lading.toml bump patterns, README TOML fences, dependency JSON serializability)

⏰ 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 (2)
docs/lading-design.md (2)

420-422: Approved: past feedback on sentence case and backtick formatting resolved. The step title now uses sentence case, and configuration keys and flags are properly marked as code. The prose explicitly refers to the "configuration value", improving clarity per the previous review guidance.


524-549: Approved: directory structure now uses proper plaintext fenced block. The change resolves the previous issue of HTML-comment bypass, replacing it with a readable ASCII tree formatted one path per line. The two-space indentation and inline comments are consistent and align with documentation guidelines.

Comment thread docs/lading-design.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Confirmed resolved: directory structure now uses proper plaintext fencing.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Add end-to-end tests for lading; broaden test coverage and fixes Add end-to-end tests for lading; extend test suite and docs Dec 16, 2025
- Added detailed explanations on publish data flow and preflight sequence.
- Reformatted proposed directory structure for better readability.
- Improved clarity and consistency in design document sections.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
Comment thread tests/e2e/helpers/workspace_builder.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

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

432-436: Rewrap line 432 to respect 80-character paragraph limit.

Line 432 exceeds 80 characters. Rewrap the list item:

-2. **Execute pre-flight checks:** Before publishing, run a series of checks in
-   the workspace itself to ensure integrity:
+2. **Execute pre-flight checks:** Before publishing, run a series of checks
+   in the workspace itself to ensure integrity:
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6fd5a14 and 6349394.

📒 Files selected for processing (1)
  • docs/lading-design.md (6 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Use the markdown files within the docs/ directory as a knowledge base and source of truth for project requirements, dependency choices, and architectural decisions.
Proactively update relevant files in the docs/ directory when new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve to keep documentation accurate and current.

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-GB-oxendict) with suffixes: -ize in words like 'realize' and 'organization', -lyse in words like 'analyse' and 'paralyse', -our in words like 'colour' and 'behaviour', -re in words like 'centre' and 'calibre', double 'l' in words like 'cancelled' and 'counsellor', maintain 'e' in words like 'likeable', -ogue in words like 'catalogue'
Use the Oxford comma in documentation: 'ships, planes, and hovercraft' where it aids comprehension
Treat company names as collective nouns in documentation, for example 'Lille Industries are expanding'
Write headings in sentence case
Use Markdown headings (#, ##, ###, and so on) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
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 Markdown
Prefer inline links using text or angle brackets around the URL in Markdown
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown
Ensure tables have a delimiter line below the header row in Markdown
Expand any uncommon acronym on first use, for example, Continuous Integration (CI)
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use footnotes referenced with [^label] in Markdown documentation
Include Mermaid diagrams in documentation where they add clarity
When embedding figures in documentation, use ![alt text](path/to...

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: For Markdown files (.md only), ensure changes pass lint checks via make markdownlint.
For Markdown files (.md only), ensure Mermaid diagrams pass validation using nixie via make nixie.

Files:

  • docs/lading-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/lading-design.md
🪛 LanguageTool
docs/lading-design.md

[grammar] ~482-~482: Did you mean the noun “publishing”?
Context: ...s applied. Preflight failures abort the publish workflow; success advances to crate-by-...

(PREPOSITION_VERB)

⏰ 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). (2)
  • GitHub Check: Sourcery review
  • GitHub Check: Review for correctness
🔇 Additional comments (2)
docs/lading-design.md (2)

479-483: LGTM!

The paragraph correctly wraps within limits and the grammar is sound.


512-514: LGTM!

The new subsection heading correctly uses sentence case, and the step numbering properly restarts at 1 under the new "Publishing iteration" section, providing clear structural separation.

Comment thread docs/lading-design.md
Comment thread docs/lading-design.md
Comment thread docs/lading-design.md Outdated
Comment thread docs/lading-design.md
…ucture

Refactor the directory structure section in the documentation for better readability by adding proper indentation and line breaks. This enhances clarity for developers reviewing the lading package layout.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos
leynos merged commit c1dc67f into main Dec 19, 2025
4 checks passed
@leynos
leynos deleted the terragon/e2e-tests-bump-publish-l8k03f branch December 19, 2025 22:23
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