Skip to content

Fix review app delete project checkout#307

Merged
justin808 merged 1 commit into
mainfrom
jg-codex/delete-review-app-project-checkout
May 23, 2026
Merged

Fix review app delete project checkout#307
justin808 merged 1 commit into
mainfrom
jg-codex/delete-review-app-project-checkout

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented May 23, 2026

Summary

  • checkout the downstream repository into app/ before running review-app delete
  • run cpflow setup/delete from that downstream working directory so .controlplane/controlplane.yml is present
  • add workflow/action specs for the required checkout and working_directory wiring

Validation

  • CPLN_ORG=test bundle exec rspec spec/github_workflows_spec.rb
  • RUBOCOP_CACHE_ROOT=/private/tmp/rubocop-cache CPLN_ORG=test bundle exec rubocop --no-server spec/github_workflows_spec.rb
  • actionlint .github/workflows/cpflow-delete-review-app.yml
  • git diff --check

This fixes the failure observed when closing shakacode/react-webpack-rails-tutorial#734: cpflow delete could not find project_folder/.controlplane/controlplane.yml.


Note

Low Risk
Low risk: workflow wiring change to ensure cpflow delete runs in the correct repo directory, plus test coverage for the new checkout/working-directory behavior.

Overview
Fixes review-app deletion by checking out the downstream/caller repo into app/ before running delete, and then running cpflow setup + delete from that app working directory so .controlplane/controlplane.yml is present.

Updates the cpflow-delete-control-plane-app composite action to accept a working_directory input (default .) and applies it via working-directory, and adds/updates RSpec assertions to lock in the workflow/action wiring.

Reviewed by Cursor Bugbot for commit c374ce2. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Tests

    • Added validation for GitHub workflow and action configurations to ensure proper setup and execution.
  • Chores

    • Enhanced working directory handling for deletion operations to improve reliability and configurability.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

Walkthrough

This PR introduces configurable working directory support to the deletion workflow and action. The control plane app action gains an optional working_directory input, the review app workflow checks out into an explicit app directory and passes it through, and new tests validate both the action contract and workflow integration.

Changes

Working Directory Configuration

Layer / File(s) Summary
Delete control plane action input contract
.github/actions/cpflow-delete-control-plane-app/action.yml
The composite action declares an optional working_directory input (default ".") and wires it to the delete step's working-directory field.
Delete review app workflow integration
.github/workflows/cpflow-delete-review-app.yml
The workflow adds an explicit checkout step into an app directory and updates both the environment setup and delete-control-plane-app action invocation to use working_directory: app.
GitHub Actions YAML validation tests
spec/github_workflows_spec.rb
New RSpec suite validates the workflow's checkout configuration and working directory usage across steps, plus the action's input default and step wiring.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A workflow takes flight with a path all so bright,
app directory clear, working directories right,
One input to rule them, from action to flow,
With specs that stand guard where the deletions all go! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix review app delete project checkout' directly aligns with the main objective of fixing the checkout process for the delete review app workflow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg-codex/delete-review-app-project-checkout

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 23, 2026

Greptile Summary

This PR fixes a missing .controlplane/controlplane.yml error that occurred when cpflow delete ran without the downstream project present on disk. It checks out the consumer repo into app/ before deletion and passes working_directory: app through the setup and delete action chain.

  • .github/workflows/cpflow-delete-review-app.yml: adds a "Checkout repository" step (guarded by steps.config.outputs.ready) that clones the downstream repo into app/, and updates working_directory for both "Setup environment" and "Delete review app" to point at app/.
  • .github/actions/cpflow-delete-control-plane-app/action.yml: exposes an optional working_directory input (default .) and applies it as working-directory on the shell step so cpflow resolves controlplane.yml from the right location.
  • spec/github_workflows_spec.rb: new spec that parses the workflow YAML and asserts the checkout path/credentials, setup working directory, and delete action working directory are all wired to app.

Confidence Score: 4/5

Safe to merge; the workflow, action, and spec changes are focused and correct.

The three-file change is narrowly scoped: it adds a checkout step, threads working_directory: app through the action chain, and verifies the wiring with a YAML-parsing spec. The only gap is that the spec doesn't assert the if: steps.config.outputs.ready == 'true' guard on the new checkout step, so that condition could silently regress. No correctness bugs were found in the workflow or action logic itself.

spec/github_workflows_spec.rb — missing assertion for the if guard on the "Checkout repository" step.

Important Files Changed

Filename Overview
.github/actions/cpflow-delete-control-plane-app/action.yml Adds optional working_directory input (default .) and wires it to working-directory on the Delete application step so cpflow finds .controlplane/controlplane.yml in the correct directory.
.github/workflows/cpflow-delete-review-app.yml Inserts a downstream repo checkout into app/ (guarded by steps.config.outputs.ready) and routes working_directory: app to both Setup environment and Delete review app steps, fixing the missing controlplane.yml at delete time.
spec/github_workflows_spec.rb New spec verifying checkout path/credentials, setup working_directory, and delete action working_directory wiring; doesn't assert the if guard on the checkout step so that condition could regress silently.

Sequence Diagram

sequenceDiagram
    participant GH as GitHub Event
    participant CV as Validate Config
    participant CO as Checkout (app/)
    participant SE as Setup Environment
    participant DA as Delete App (cpflow)
    participant FN as Finalize Status

    GH->>CV: PR closed / issue_comment / workflow_dispatch
    CV-->>CO: "ready == 'true'"
    CO->>CO: checkout consumer repo → app/
    CO-->>SE: "working_directory=app"
    SE->>SE: detect Ruby version in app/
    SE->>SE: install cpln + cpflow
    SE-->>DA: "working_directory=app"
    DA->>DA: cd app/ → cpflow delete -a APP_NAME
    DA-->>FN: success/failure
    FN->>GH: update PR comment
Loading

Reviews (1): Last reviewed commit: "Fix review app delete project checkout" | Re-trigger Greptile

Comment on lines +21 to +36
it "runs cpflow delete from a downstream app checkout" do
expect(step_named("Checkout repository")).to include(
"uses" => "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd",
"with" => include(
"path" => "app",
"persist-credentials" => false
)
)

expect(step_named("Setup environment").fetch("with")).to include(
"working_directory" => "app"
)
expect(step_named("Delete review app").fetch("with")).to include(
"working_directory" => "app"
)
end
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Spec doesn't assert the if guard on the checkout step

The "Checkout repository" step carries if: steps.config.outputs.ready == 'true' in the workflow, which keeps it from running when config validation fails. The current spec uses include(...) so the if key is silently ignored. If that guard were accidentally dropped, the test would still pass while the step would check out into app/ even on invalid configs — causing a misleading empty working directory for subsequent steps.

Consider asserting "if" => "steps.config.outputs.ready == 'true'" alongside the other fields so the condition is pinned by the spec.


def step_named(name)
steps.find { |step| step["name"] == name }
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If a step is renamed or removed, step_named returns nil and the downstream .include(...) or .fetch("with") failure says expected nil to include ... — it doesn't tell you which step went missing. A small guard makes regressions easier to diagnose:

Suggested change
end
steps.find { |step| step["name"] == name } ||
raise("No workflow step named #{name.inspect}. Available: #{steps.filter_map { |s| s['name'] }.inspect}")

Comment on lines +21 to +36
it "runs cpflow delete from a downstream app checkout" do
expect(step_named("Checkout repository")).to include(
"uses" => "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd",
"with" => include(
"path" => "app",
"persist-credentials" => false
)
)

expect(step_named("Setup environment").fetch("with")).to include(
"working_directory" => "app"
)
expect(step_named("Delete review app").fetch("with")).to include(
"working_directory" => "app"
)
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The test validates the checkout step's uses and with values but not its if: guard. If someone removed the if: steps.config.outputs.ready == 'true' condition, this test would still pass — but the checkout would now run even when config validation failed. Consider adding:

expect(step_named("Checkout repository")).to include(
  "if" => "steps.config.outputs.ready == 'true'"
)

@justin808 justin808 force-pushed the jg-codex/delete-review-app-project-checkout branch from de1c2e6 to c374ce2 Compare May 23, 2026 08:41
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 23, 2026

Code Review — PR #307: Fix review app delete project checkout

Overview

This PR fixes a real bug: cpflow delete was failing when closing review apps because it could not find .controlplane/controlplane.yml — that file lives in the downstream (caller) repo, not in the cpflow checkout. The fix is correct: check out the downstream repo into app/ before running setup/delete, and pass working_directory: app to both actions.

The composite action change is backwards-compatible (default is "."), and the new spec/github_workflows_spec.rb provides good structural coverage of the YAML wiring.


Issues

1. Changelog not updated

The [Unreleased] ### Fixed section in CHANGELOG.md is missing an entry for this fix. The project's conventions (see the header in CHANGELOG.md) expect bug fixes to be documented there.

2. step_named returns nil silently — opaque test failures

When a step name does not match (e.g. due to a rename), steps.find returns nil. The subsequent expect(nil).to include(...) produces a confusing failure message. Consider raising a descriptive error instead (see inline comment).

3. if: guard on the new checkout step is not asserted

The spec verifies the checkout is wired correctly (path, persist-credentials, working_directory) but does not assert that the new step has if: steps.config.outputs.ready == 'true'. Without that guard the step would run even when config validation fails. The condition is present in the workflow file today, but adding an assertion prevents future regressions.

4. Ruby version detection now reads the downstream app, not cpflow (intentional, worth a comment)

Switching working_directory from .cpflow to app in cpflow-setup-environment changes which directory is scanned for .ruby-version / .tool-versions / Gemfile. This is the right behaviour (cpflow should run under the app's Ruby environment), but it is a subtle shift. A one-line comment in the workflow would help future readers understand why app is used here rather than .cpflow.


Summary

The fix itself is correct and the new test file is a good addition. The items above are all minor (changelog entry, test robustness, one clarifying comment). Happy to approve once the changelog is updated.

let(:steps) { workflow.fetch("jobs").fetch("delete-review-app").fetch("steps") }

def step_named(name)
steps.find { |step| step["name"] == name }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When a step name is not found, find returns nil and the downstream expect(nil).to include(...) / nil.fetch("with") failure messages are opaque ("expected nil to include…"). Consider raising a step-not-found error immediately so the name mismatch is surfaced clearly:

Suggested change
steps.find { |step| step["name"] == name }
steps.find { |step| step["name"] == name } ||
raise("Step #{name.inspect} not found in workflow. Available: #{steps.filter_map { |s| s["name"] }.inspect}")

"persist-credentials" => false
)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The spec does not assert the if: guard on the checkout step. If the condition is accidentally removed or changed, the step would run even when config validation fails. Consider adding:

      expect(step_named("Checkout repository")).to include(
        "if" => "steps.config.outputs.ready == 'true'"
      )

uses: ./.cpflow/.github/actions/cpflow-setup-environment
with:
token: ${{ secrets.CPLN_TOKEN_STAGING }}
org: ${{ vars.CPLN_ORG_STAGING }}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The working_directory was previously .cpflow (the cpflow repo checkout). Changing it to app (the downstream caller repo) means Ruby version detection now reads the downstream project's .ruby-version / .tool-versions / Gemfile — which is the correct behaviour since cpflow needs to run in the app's Ruby environment. A short comment here would make this non-obvious choice self-documenting for future maintainers.

Suggested change
org: ${{ vars.CPLN_ORG_STAGING }}
working_directory: app # app's Ruby version files, not cpflow's

@justin808 justin808 merged commit 3e0e7e1 into main May 23, 2026
14 checks passed
@justin808 justin808 deleted the jg-codex/delete-review-app-project-checkout branch May 23, 2026 08:46
justin808 added a commit that referenced this pull request May 24, 2026
* origin/main:
  Fix deploy-image showing container names instead of workload names (#255) (#294)
  Re-enable RuboCop NewCops and fix violations (#300)
  [codex] Fix stale app cleanup for image-less GVCs (#310)
  Handle non-zero exit from cpln workload exec gracefully (#301)
  Document Thruster HTTP/2 proxy configuration for Rails apps (#292)
  Friendly error in cpflow-detect-release-phase when controlplane.yml missing (#299)
  Document downstream cpflow testing (#308)
  Fix review app delete project checkout (#307)
  Fallback Ruby setup when no version file exists
  Move generated GitHub Actions logic upstream
  Animate review app command feedback (#304)
  Use Node 24 GitHub action versions (#303)
  Relax thor dependency to ~> 1.3 for Rails 8 solid_queue compatibility (#264) (#291)
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