From c5a82793194480d146a8288e875f63fc4a9de579 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 9 May 2026 14:45:23 -1000 Subject: [PATCH 1/6] Polish review app command UX before 5.0.0 stable Rename the generated PR commands to a single namespaced family: /deploy-review-app -> +review-app-deploy /delete-review-app -> +review-app-delete /help -> +review-app-help Updates the trigger workflows, the PR-open quick reference, the long-form help (.github/cpflow-help.md), the AI rollout prompt, and the CI automation docs to use the new names consistently. Existing repos that have already generated this flow will need to regenerate the workflows or update the old command names by hand; this is acceptable now because the flow has not yet shipped in a stable release (currently 5.0.0.rc.0). Help message changes (.github/cpflow-help.md): - Self-identify the message ("You asked for review app help. These commands are generated by cpflow.") so PR readers know what they are looking at. - Rename "Repository secrets / variables" to "GitHub Actions secrets / variables" to match where they are configured. - Clarify Control Plane wording: tokens are scoped to a Control Plane org on controlplane.com; orgs are named accordingly. - Wrap the secrets/variables tables in a collapsed
block so casual readers see the commands without scrolling past a wall of config. - Add an "Advanced: testing changes to generated workflows" section that documents the gh workflow run pattern for testing PR-branch workflow edits before merge. PR-open message (cpflow-review-app-help.yml): - Drop the long quick reference; list the three commands and tell readers to comment +review-app-help for setup details. Contributing docs: - Add a "Developing the GitHub flow generator" section explaining where the templates live, which surface area to keep consistent on a command rename, how to run the generator spec, where actionlint applies, and how to dispatch comment-trigger workflows on a PR branch with gh workflow run before merge. Co-Authored-By: Claude Opus 4.7 (1M context) --- CONTRIBUTING.md | 16 +++++ docs/ai-github-flow-prompt.md | 2 +- docs/ci-automation.md | 14 ++--- lib/command/ai_github_flow_prompt.rb | 2 +- .../.github/cpflow-help.md | 59 +++++++++++++------ .../workflows/cpflow-delete-review-app.yml | 2 +- .../workflows/cpflow-deploy-review-app.yml | 6 +- .../.github/workflows/cpflow-help-command.yml | 2 +- .../workflows/cpflow-review-app-help.yml | 13 ++-- 9 files changed, 77 insertions(+), 39 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e1272361..e28412d9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -72,6 +72,22 @@ CPLN_ORG=your-org-for-tests bundle exec rspec --tag slow cpflow test ``` +## Developing the GitHub flow generator + +`cpflow generate-github-actions` copies templates from `lib/github_flow_templates/` into a target repo's `.github/` directory. To work on this feature: + +- **Edit the templates in place.** The generator does no string-mangling beyond a small set of substitutions handled in `lib/command/generate_github_actions.rb`; what you put in `lib/github_flow_templates/.github/` is (almost) exactly what ships into a generated repo. Make changes there, not in a generated copy. +- **Surface area to keep consistent.** A change to a PR command (e.g. `+review-app-deploy`) usually touches three places: the trigger workflow (`lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml`), the PR-open quick reference (`cpflow-review-app-help.yml`), and the long-form help (`lib/github_flow_templates/.github/cpflow-help.md`). The AI flow prompt (`lib/command/ai_github_flow_prompt.rb`) also names commands and should be kept in sync. +- **Run the generator spec on every change:** + + ```sh + bundle exec rspec spec/command/generate_github_actions_spec.rb + ``` + + It generates the templates into a tmp playground and asserts on their contents — most regressions in the templates will fail there. +- **Lint the templates.** Generated workflows are checked with `actionlint` in CI. Install it locally and run `actionlint lib/github_flow_templates/.github/workflows/*.yml` to catch issues before pushing. +- **Test PR-branch workflow edits in a real repo.** Comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute base-branch code, so they will not exercise your PR-branch changes. Generate the workflows into a downstream test repo, push to a feature branch, then dispatch with `gh workflow run cpflow-deploy-review-app.yml --ref -f pr_number=` to run the workflow code from your branch. Repeat for the delete/help workflows as needed. + ## Releasing See [Releasing the Gem](./docs/releasing.md) for the changelog-first Ruby gem release process. In short: run diff --git a/docs/ai-github-flow-prompt.md b/docs/ai-github-flow-prompt.md index ba9a09f8..9f1dd3da 100644 --- a/docs/ai-github-flow-prompt.md +++ b/docs/ai-github-flow-prompt.md @@ -20,7 +20,7 @@ prompt tells the agent to stop on. ```text Set up Control Plane GitHub Flow for this repo. Start with `cpflow github-flow-readiness` and stop on any reported blockers. The repo must be deployable from a clean clone: published package versions, complete runtime scaffold, and a production Dockerfile that can build the app. If any package version is unpublished, inaccessible from CI, or requires credentials that are not already modeled in the repo or GitHub settings, stop and report the blocker instead of generating workflow files. If the repo is a legacy sample pinned to an obsolete Ruby or Bundler toolchain, if it does not even have a production Dockerfile yet, or if it is a monorepo without an already-decided single app boundary for this flow, stop and report that as a prerequisite instead of forcing the rollout. -If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `/deploy-review-app`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. +If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Keep Node available in the final image if asset compilation or SSR depends on ExecJS, Yarn, `pnpm`, or npm after the main install layer. Make sure the generated Dockerfile uses a Ruby base image compatible with the app's declared Ruby requirement. Preserve repo-defined frontend build hooks: if `config/shakapacker.yml` defines a `precompile_hook`, or React on Rails enables `config.auto_load_bundle = true`, confirm the generated Dockerfile runs that codegen step before `rails assets:precompile`. If `config/database.yml` shows SQLite in production, confirm that the generated scaffold uses persistent `db` and `storage` volumes plus a release script that runs `rails db:prepare`; otherwise keep the default Postgres workload. If the public workload is not named `rails`, set `PRIMARY_WORKLOAD` or adjust the generated workflows. Inspect the Dockerfile and package sources for private GitHub dependencies or `RUN --mount=type=ssh`; if present, wire `DOCKER_BUILD_SSH_KEY`, optionally set `DOCKER_BUILD_SSH_KNOWN_HOSTS` for non-GitHub SSH hosts, and keep `DOCKER_BUILD_EXTRA_ARGS` to newline-delimited single tokens such as `--build-arg=FOO=bar`. diff --git a/docs/ci-automation.md b/docs/ci-automation.md index 5b3736a1..51e693ba 100644 --- a/docs/ci-automation.md +++ b/docs/ci-automation.md @@ -4,7 +4,7 @@ This document describes the reusable GitHub Actions scaffolding generated by `cp The goal is to bring the Heroku Flow model into any `cpflow` project: -1. Comment `/deploy-review-app` on a pull request to create or update a review app. +1. Comment `+review-app-deploy` on a pull request to create or update a review app. 2. Push more commits to the PR to auto-redeploy that review app. 3. Push to the staging branch to auto-deploy staging. 4. Promote the already-built staging artifact to production from the Actions tab. @@ -18,7 +18,7 @@ End-to-end rollout in one view: 2. `cpflow generate` — creates `.controlplane/` if missing. 3. `cpflow generate-github-actions` — adds the `cpflow-*` composite actions and workflows. 4. Configure the GitHub [repository secrets and variables](#required-github-repository-settings) the workflows expect. -5. Push the branch, then comment `/deploy-review-app` on a PR to spin up a review environment. +5. Push the branch, then comment `+review-app-deploy` on a PR to spin up a review environment. See [Bootstrap a Project](#bootstrap-a-project) for command details, [Repo Readiness Checklist](#repo-readiness-checklist) for what "ready" means, and [AI Playbook](#ai-playbook) to run the rollout through an agent. @@ -216,22 +216,22 @@ The action will start an SSH agent, add the key, write `known_hosts`, and pass ` `cpflow-help-command.yml` -- Replies to `/help` on a pull request with the commands and required repo settings. +- Replies to `+review-app-help` on a pull request with the commands and required repo settings. `cpflow-deploy-review-app.yml` -- Creates a review app when someone comments `/deploy-review-app`. +- Creates a review app when someone comments `+review-app-deploy`. - Redeploys an existing review app automatically on later PR pushes. - Creates a GitHub deployment and comments with the review URL and logs. - Leaves PR pushes alone until the first review app is explicitly requested, which keeps demo-app costs down. -- Accepts `/deploy-review-app` only from trusted commenters (`OWNER`, `MEMBER`, or `COLLABORATOR`). +- Accepts `+review-app-deploy` only from trusted commenters (`OWNER`, `MEMBER`, or `COLLABORATOR`). - Skips fork-based PR deploys because the workflow builds Docker images with repository secrets. `cpflow-delete-review-app.yml` -- Deletes the review app on `/delete-review-app`. +- Deletes the review app on `+review-app-delete`. - Also deletes it automatically when the pull request closes. -- Accepts `/delete-review-app` only from trusted commenters (`OWNER`, `MEMBER`, or `COLLABORATOR`). +- Accepts `+review-app-delete` only from trusted commenters (`OWNER`, `MEMBER`, or `COLLABORATOR`). `cpflow-deploy-staging.yml` diff --git a/lib/command/ai_github_flow_prompt.rb b/lib/command/ai_github_flow_prompt.rb index c7c5473e..8ceda7b6 100644 --- a/lib/command/ai_github_flow_prompt.rb +++ b/lib/command/ai_github_flow_prompt.rb @@ -32,7 +32,7 @@ def prompt <<~PROMPT Set up Control Plane GitHub Flow for this repo. Start with `cpflow github-flow-readiness` and stop on any reported blockers. The repo must be deployable from a clean clone: published package versions, complete runtime scaffold, and a production Dockerfile that can build the app. If any package version is unpublished, inaccessible from CI, or requires credentials that are not already modeled in the repo or GitHub settings, stop and report the blocker instead of generating workflow files. If the repo is a legacy sample pinned to an obsolete Ruby or Bundler toolchain, if it does not even have a production Dockerfile yet, or if it is a monorepo without an already-decided single app boundary for this flow, stop and report that as a prerequisite instead of forcing the rollout. - If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default (`#{inferred_app_prefix}`) and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `/deploy-review-app`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. + If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default (`#{inferred_app_prefix}`) and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Keep Node available in the final image if asset compilation or SSR depends on ExecJS, Yarn, `pnpm`, or npm after the main install layer. Make sure the generated Dockerfile uses a Ruby base image compatible with the app's declared Ruby requirement. Preserve repo-defined frontend build hooks: if `config/shakapacker.yml` defines a `precompile_hook`, or React on Rails enables `config.auto_load_bundle = true`, confirm the generated Dockerfile runs that codegen step before `rails assets:precompile`. If `config/database.yml` shows SQLite in production, confirm that the generated scaffold uses persistent `db` and `storage` volumes plus a release script that runs `rails db:prepare`; otherwise keep the default Postgres workload. If the public workload is not named `rails`, set `PRIMARY_WORKLOAD` or adjust the generated workflows. Inspect the Dockerfile and package sources for private GitHub dependencies or `RUN --mount=type=ssh`; if present, wire `DOCKER_BUILD_SSH_KEY`, optionally set `DOCKER_BUILD_SSH_KNOWN_HOSTS` for non-GitHub SSH hosts, and keep `DOCKER_BUILD_EXTRA_ARGS` to newline-delimited single tokens such as `--build-arg=FOO=bar`. diff --git a/lib/github_flow_templates/.github/cpflow-help.md b/lib/github_flow_templates/.github/cpflow-help.md index 3cc41dc1..9a80ffe6 100644 --- a/lib/github_flow_templates/.github/cpflow-help.md +++ b/lib/github_flow_templates/.github/cpflow-help.md @@ -1,32 +1,48 @@ -# Control Plane GitHub Flow +# Review app help + +You asked for review app help. These commands are generated by [cpflow](https://github.com/shakacode/control-plane-flow). ## PR commands -`/deploy-review-app` +`+review-app-deploy` - Creates the review app if it does not exist - Builds the PR commit image - Deploys the image and comments with the review URL -- Comment body must be exactly `/deploy-review-app` — no surrounding text, trailing whitespace, or trailing newline. The trigger uses an exact-equality match, so a comment like `please /deploy-review-app now` or `/deploy-review-app ` (with a trailing space) silently no-ops. +- Comment body must be exactly `+review-app-deploy` — no surrounding text, trailing whitespace, or trailing newline. The trigger uses an exact-equality match, so a comment like `please +review-app-deploy now` or `+review-app-deploy ` (with a trailing space) silently no-ops. -`/delete-review-app` +`+review-app-delete` - Deletes the review app when the PR is done - This also runs automatically when the PR closes -- Same exact-match rule as `/deploy-review-app`: the comment body must be exactly `/delete-review-app`. +- Same exact-match rule as `+review-app-deploy`: the comment body must be exactly `+review-app-delete`. + +`+review-app-help` +- Posts this message on the PR. + +## Workflow behavior + +- Review apps are opt-in and created with `+review-app-deploy` +- New commits redeploy existing review apps automatically +- Pushes to the staging branch deploy staging automatically +- Promotion to production is manual via the Actions tab +- A nightly workflow removes stale review apps + +
+Advanced: GitHub Actions secrets and variables -## Repository secrets +### GitHub Actions secrets | Name | Required | Notes | | --- | --- | --- | -| `CPLN_TOKEN_STAGING` | yes | Service-account token scoped to the staging org. | -| `CPLN_TOKEN_PRODUCTION` | yes (for promote) | Service-account token scoped to the production org. | +| `CPLN_TOKEN_STAGING` | yes | Service-account token scoped to the staging Control Plane org on controlplane.com. | +| `CPLN_TOKEN_PRODUCTION` | yes (for promote) | Service-account token scoped to the production Control Plane org on controlplane.com. | | `DOCKER_BUILD_SSH_KEY` | optional | Private SSH key used when Docker builds fetch private deps via `RUN --mount=type=ssh`. | -## Repository variables +### GitHub Actions variables | Name | Required | Notes | | --- | --- | --- | -| `CPLN_ORG_STAGING` | yes | Control Plane org for staging and review apps. | -| `CPLN_ORG_PRODUCTION` | yes (for promote) | Control Plane org for production. | +| `CPLN_ORG_STAGING` | yes | Control Plane org on controlplane.com for staging and review apps. | +| `CPLN_ORG_PRODUCTION` | yes (for promote) | Control Plane org on controlplane.com for production. | | `STAGING_APP_NAME` | yes | App name in `controlplane.yml` used as the staging deploy target. | | `PRODUCTION_APP_NAME` | yes (for promote) | App name in `controlplane.yml` used as the production deploy target. | | `REVIEW_APP_PREFIX` | yes | Prefix for per-PR review app names (e.g. `review-app`). | @@ -38,10 +54,19 @@ | `CPLN_CLI_VERSION` | optional | Pin a specific `@controlplane/cli` version; falls back to the action default when unset. | | `CPFLOW_VERSION` | optional | Pin a specific cpflow gem version; falls back to the generated default when unset. | -## Workflow behavior +
-- Review apps are opt-in and created with `/deploy-review-app` -- New commits redeploy existing review apps automatically -- Pushes to the staging branch deploy staging automatically -- Promotion to production is manual via the Actions tab -- A nightly workflow removes stale review apps +
+Advanced: testing changes to generated workflows + +When iterating on the generated workflow YAML on a PR branch, comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute the workflow code from the base branch — not your PR branch. To exercise the PR-branch workflow code before merging, dispatch the workflow manually with `gh`: + +```sh +gh workflow run cpflow-deploy-review-app.yml --ref -f pr_number= +gh workflow run cpflow-delete-review-app.yml --ref -f pr_number= +gh workflow run cpflow-help-command.yml --ref -f pr_number= +``` + +`workflow_dispatch` runs use the workflow file from the `--ref` you pass, so this is the supported way to test PR-branch workflow edits before merge. After merge, comment triggers go back to running base-branch code as usual. + +
diff --git a/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml b/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml index d4543e28..34c07d44 100644 --- a/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml +++ b/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml @@ -33,7 +33,7 @@ jobs: if: | (github.event_name == 'issue_comment' && github.event.issue.pull_request && - github.event.comment.body == '/delete-review-app' && + github.event.comment.body == '+review-app-delete' && contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) || (github.event_name == 'pull_request_target' && github.event.action == 'closed') || github.event_name == 'workflow_dispatch' diff --git a/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml b/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml index d8bf4aa8..ac216133 100644 --- a/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +++ b/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml @@ -37,7 +37,7 @@ jobs: deploy: # Skip synchronize/opened events from fork PRs at the job level — they cannot access # repository secrets anyway, so running any steps just burns billable minutes. Users - # can still manually deploy a fork PR via `/deploy-review-app` (gated below by + # can still manually deploy a fork PR via `+review-app-deploy` (gated below by # author_association) or workflow_dispatch. if: | (github.event_name == 'pull_request' && @@ -45,7 +45,7 @@ jobs: github.event_name == 'workflow_dispatch' || (github.event_name == 'issue_comment' && github.event.issue.pull_request && - github.event.comment.body == '/deploy-review-app' && + github.event.comment.body == '+review-app-deploy' && contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) runs-on: ubuntu-latest timeout-minutes: 45 @@ -236,7 +236,7 @@ jobs: run: | { echo "Review app ${APP_NAME} does not exist yet." - echo "Create it with a PR comment that is exactly /deploy-review-app." + echo "Create it with a PR comment that is exactly +review-app-deploy." } >> "$GITHUB_STEP_SUMMARY" - name: Setup review app if it does not exist yet diff --git a/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml b/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml index 65fc3de6..8ed50ff2 100644 --- a/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml +++ b/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml @@ -20,7 +20,7 @@ jobs: if: | (github.event_name == 'issue_comment' && github.event.issue.pull_request && - github.event.comment.body == '/help' && + github.event.comment.body == '+review-app-help' && contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest diff --git a/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml b/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml index 1b35b65e..f590ea60 100644 --- a/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml +++ b/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml @@ -26,16 +26,13 @@ jobs: with: script: | const body = [ - "# Control Plane review app commands", + "# Review app commands", "", - "`/deploy-review-app`", - "Create the review app or redeploy the PR branch to it.", + "- `+review-app-deploy` - create or redeploy this PR's review app.", + "- `+review-app-delete` - delete this PR's review app and temporary resources.", + "- `+review-app-help` - show setup details and workflow behavior.", "", - "`/delete-review-app`", - "Delete the review app and its temporary resources.", - "", - "`/help`", - "Show the required GitHub variables, secrets, and workflow behavior." + "For setup details, comment `+review-app-help`." ].join("\n"); await github.rest.issues.createComment({ From 8f6bbeb449eac6655f631ab6ac41d8197b3b5ff0 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 9 May 2026 16:34:57 -1000 Subject: [PATCH 2/6] Address review feedback on review-app command rename - CHANGELOG: add Unreleased Changed entry for the +review-app-* rename - Spec: pin the public +review-app-deploy/-delete/-help trigger strings so a future template edit cannot silently rename them - cpflow-help.md: spell out the exact-match rule on the +review-app-delete bullet so it is self-contained for first-time readers - cpflow-help-command.yml: comment why workflow_dispatch intentionally skips the author_association gate (GitHub already restricts manual dispatches to actions:write users) Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 4 +++- lib/github_flow_templates/.github/cpflow-help.md | 2 +- .../.github/workflows/cpflow-help-command.yml | 5 +++++ spec/command/generate_github_actions_spec.rb | 6 ++++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf3fd5e2..cd2edda2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,9 @@ In addition to the standard keepachangelog.com categories, this project uses a l ## [Unreleased] -_Please add entries here for your pull requests that have not yet been released._ +### Changed + +- Renamed the generated review-app PR comment commands to a namespaced `+review-app-*` family: `/deploy-review-app` → `+review-app-deploy`, `/delete-review-app` → `+review-app-delete`, and `/help` → `+review-app-help`. Repos that ran `cpflow generate-github-actions` against 5.0.0.rc.0 must regenerate the workflow templates and update saved instructions or runbooks. [PR 285](https://github.com/shakacode/control-plane-flow/pull/285) by [Justin Gordon](https://github.com/justin808). ## [5.0.0.rc.0] - 2026-05-05 diff --git a/lib/github_flow_templates/.github/cpflow-help.md b/lib/github_flow_templates/.github/cpflow-help.md index 9a80ffe6..a229e13c 100644 --- a/lib/github_flow_templates/.github/cpflow-help.md +++ b/lib/github_flow_templates/.github/cpflow-help.md @@ -13,7 +13,7 @@ You asked for review app help. These commands are generated by [cpflow](https:// `+review-app-delete` - Deletes the review app when the PR is done - This also runs automatically when the PR closes -- Same exact-match rule as `+review-app-deploy`: the comment body must be exactly `+review-app-delete`. +- Comment body must be exactly `+review-app-delete` — no surrounding text, trailing whitespace, or trailing newline. Same exact-equality rule as `+review-app-deploy`. `+review-app-help` - Posts this message on the PR. diff --git a/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml b/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml index 8ed50ff2..6fbab0b8 100644 --- a/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml +++ b/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml @@ -17,6 +17,11 @@ permissions: jobs: help: + # Comment-triggered runs are gated on author_association so only repo + # owners/members/collaborators can invoke them. workflow_dispatch is + # intentionally not gated here: GitHub already restricts manual dispatches + # to users with `actions: write` (write access to the repo), which is a + # stricter bar than COLLABORATOR. if: | (github.event_name == 'issue_comment' && github.event.issue.pull_request && diff --git a/spec/command/generate_github_actions_spec.rb b/spec/command/generate_github_actions_spec.rb index 45adb85b..65c9ea8e 100644 --- a/spec/command/generate_github_actions_spec.rb +++ b/spec/command/generate_github_actions_spec.rb @@ -224,6 +224,12 @@ def generated_yaml_paths expect(contents).to include('fs.readFileSync(".github/cpflow-help.md"') end + it "pins the public +review-app-* PR comment trigger strings" do + expect(review_app_workflow_path.read).to include("github.event.comment.body == '+review-app-deploy'") + expect(delete_review_workflow_path.read).to include("github.event.comment.body == '+review-app-delete'") + expect(help_workflow_path.read).to include("github.event.comment.body == '+review-app-help'") + end + it "documents Docker build vars in the help markdown" do help_md_path = playground.join(".github/cpflow-help.md") contents = help_md_path.read From 08ac574c47d7e65e0dbf6eb4ded4661d7cf83826 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 9 May 2026 20:36:13 -1000 Subject: [PATCH 3/6] Address second review-app command rename pass - Extend the trigger-string spec so it also pins the +review-app-* command names in the PR-open quick-reference workflow (cpflow-review-app-help.yml). A future edit to that bullet list cannot now silently drift away from the real triggers. - Add the same exact-equality caveat to the +review-app-help bullet in cpflow-help.md that the +review-app-deploy and +review-app-delete bullets already carry. - Spell out cpflow-delete-review-app.yml and cpflow-help-command.yml explicitly in the CONTRIBUTING.md gh workflow run example so a developer reading that section does not have to cross-reference cpflow-help.md. Co-Authored-By: Claude Opus 4.7 (1M context) --- CONTRIBUTING.md | 8 +++++++- lib/github_flow_templates/.github/cpflow-help.md | 1 + spec/command/generate_github_actions_spec.rb | 9 +++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e28412d9..f22154b0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -86,7 +86,13 @@ cpflow test It generates the templates into a tmp playground and asserts on their contents — most regressions in the templates will fail there. - **Lint the templates.** Generated workflows are checked with `actionlint` in CI. Install it locally and run `actionlint lib/github_flow_templates/.github/workflows/*.yml` to catch issues before pushing. -- **Test PR-branch workflow edits in a real repo.** Comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute base-branch code, so they will not exercise your PR-branch changes. Generate the workflows into a downstream test repo, push to a feature branch, then dispatch with `gh workflow run cpflow-deploy-review-app.yml --ref -f pr_number=` to run the workflow code from your branch. Repeat for the delete/help workflows as needed. +- **Test PR-branch workflow edits in a real repo.** Comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute base-branch code, so they will not exercise your PR-branch changes. Generate the workflows into a downstream test repo, push to a feature branch, then dispatch each affected workflow with `gh`: + + ```sh + gh workflow run cpflow-deploy-review-app.yml --ref -f pr_number= + gh workflow run cpflow-delete-review-app.yml --ref -f pr_number= + gh workflow run cpflow-help-command.yml --ref -f pr_number= + ``` ## Releasing diff --git a/lib/github_flow_templates/.github/cpflow-help.md b/lib/github_flow_templates/.github/cpflow-help.md index a229e13c..6f7c4f47 100644 --- a/lib/github_flow_templates/.github/cpflow-help.md +++ b/lib/github_flow_templates/.github/cpflow-help.md @@ -17,6 +17,7 @@ You asked for review app help. These commands are generated by [cpflow](https:// `+review-app-help` - Posts this message on the PR. +- Comment body must be exactly `+review-app-help` — no surrounding text, trailing whitespace, or trailing newline. Same exact-equality rule as `+review-app-deploy`. ## Workflow behavior diff --git a/spec/command/generate_github_actions_spec.rb b/spec/command/generate_github_actions_spec.rb index 65c9ea8e..5e43f91f 100644 --- a/spec/command/generate_github_actions_spec.rb +++ b/spec/command/generate_github_actions_spec.rb @@ -30,6 +30,10 @@ def help_workflow_path playground.join(".github/workflows/cpflow-help-command.yml") end + def pr_open_help_workflow_path + playground.join(".github/workflows/cpflow-review-app-help.yml") + end + def promote_workflow_path playground.join(".github/workflows/cpflow-promote-staging-to-production.yml") end @@ -228,6 +232,11 @@ def generated_yaml_paths expect(review_app_workflow_path.read).to include("github.event.comment.body == '+review-app-deploy'") expect(delete_review_workflow_path.read).to include("github.event.comment.body == '+review-app-delete'") expect(help_workflow_path.read).to include("github.event.comment.body == '+review-app-help'") + + pr_open_help = pr_open_help_workflow_path.read + expect(pr_open_help).to include("+review-app-deploy") + expect(pr_open_help).to include("+review-app-delete") + expect(pr_open_help).to include("+review-app-help") end it "documents Docker build vars in the help markdown" do From 9a5ecbfbd1f659eadd05349c02d5c8606ab0b409 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sun, 10 May 2026 21:52:42 -1000 Subject: [PATCH 4/6] Address third review-app command rename pass Polishing nits from the latest reviewer round: - cpflow-help.md and CONTRIBUTING.md now say comment-triggered runs use the workflow code from the repository's default branch, not the base branch. GitHub resolves issue_comment workflows from the default branch, which is technically distinct from the PR's base branch and matters for repos that target non-default branches. - The pr_open_help block in the generator spec now pins each command string to its actual bullet form (`"- \`+review-app-deploy\``), so a silent rename in the trigger-relevant text fails the spec even if the bare command name still appears elsewhere in the file. - CHANGELOG entry now explains why `+` was picked over `/` (avoid collision with GitHub's reserved slash-command surface and other bots that listen on `/help`, and to make the three commands obviously part of one namespaced family). --- CHANGELOG.md | 2 +- CONTRIBUTING.md | 2 +- lib/github_flow_templates/.github/cpflow-help.md | 4 ++-- spec/command/generate_github_actions_spec.rb | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd2edda2..b8461e2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ In addition to the standard keepachangelog.com categories, this project uses a l ### Changed -- Renamed the generated review-app PR comment commands to a namespaced `+review-app-*` family: `/deploy-review-app` → `+review-app-deploy`, `/delete-review-app` → `+review-app-delete`, and `/help` → `+review-app-help`. Repos that ran `cpflow generate-github-actions` against 5.0.0.rc.0 must regenerate the workflow templates and update saved instructions or runbooks. [PR 285](https://github.com/shakacode/control-plane-flow/pull/285) by [Justin Gordon](https://github.com/justin808). +- Renamed the generated review-app PR comment commands to a namespaced `+review-app-*` family: `/deploy-review-app` → `+review-app-deploy`, `/delete-review-app` → `+review-app-delete`, and `/help` → `+review-app-help`. The `+` prefix is used instead of `/` to avoid collision with GitHub's reserved slash-command surface and with other bots that listen on `/help`, and to make the three commands obviously part of one namespaced family. Repos that ran `cpflow generate-github-actions` against 5.0.0.rc.0 must regenerate the workflow templates and update saved instructions or runbooks. [PR 285](https://github.com/shakacode/control-plane-flow/pull/285) by [Justin Gordon](https://github.com/justin808). ## [5.0.0.rc.0] - 2026-05-05 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f22154b0..ee8d5e33 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -86,7 +86,7 @@ cpflow test It generates the templates into a tmp playground and asserts on their contents — most regressions in the templates will fail there. - **Lint the templates.** Generated workflows are checked with `actionlint` in CI. Install it locally and run `actionlint lib/github_flow_templates/.github/workflows/*.yml` to catch issues before pushing. -- **Test PR-branch workflow edits in a real repo.** Comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute base-branch code, so they will not exercise your PR-branch changes. Generate the workflows into a downstream test repo, push to a feature branch, then dispatch each affected workflow with `gh`: +- **Test PR-branch workflow edits in a real repo.** Comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute the workflow code from the repository's default branch, so they will not exercise your PR-branch changes. Generate the workflows into a downstream test repo, push to a feature branch, then dispatch each affected workflow with `gh`: ```sh gh workflow run cpflow-deploy-review-app.yml --ref -f pr_number= diff --git a/lib/github_flow_templates/.github/cpflow-help.md b/lib/github_flow_templates/.github/cpflow-help.md index 6f7c4f47..a53eeaae 100644 --- a/lib/github_flow_templates/.github/cpflow-help.md +++ b/lib/github_flow_templates/.github/cpflow-help.md @@ -60,7 +60,7 @@ You asked for review app help. These commands are generated by [cpflow](https://
Advanced: testing changes to generated workflows -When iterating on the generated workflow YAML on a PR branch, comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute the workflow code from the base branch — not your PR branch. To exercise the PR-branch workflow code before merging, dispatch the workflow manually with `gh`: +When iterating on the generated workflow YAML on a PR branch, comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute the workflow code from the repository's default branch — not your PR branch. To exercise the PR-branch workflow code before merging, dispatch the workflow manually with `gh`: ```sh gh workflow run cpflow-deploy-review-app.yml --ref -f pr_number= @@ -68,6 +68,6 @@ gh workflow run cpflow-delete-review-app.yml --ref -f pr_number gh workflow run cpflow-help-command.yml --ref -f pr_number= ``` -`workflow_dispatch` runs use the workflow file from the `--ref` you pass, so this is the supported way to test PR-branch workflow edits before merge. After merge, comment triggers go back to running base-branch code as usual. +`workflow_dispatch` runs use the workflow file from the `--ref` you pass, so this is the supported way to test PR-branch workflow edits before merge. After merge, comment triggers go back to running the default-branch workflow code as usual.
diff --git a/spec/command/generate_github_actions_spec.rb b/spec/command/generate_github_actions_spec.rb index 5e43f91f..9704c7ca 100644 --- a/spec/command/generate_github_actions_spec.rb +++ b/spec/command/generate_github_actions_spec.rb @@ -234,9 +234,9 @@ def generated_yaml_paths expect(help_workflow_path.read).to include("github.event.comment.body == '+review-app-help'") pr_open_help = pr_open_help_workflow_path.read - expect(pr_open_help).to include("+review-app-deploy") - expect(pr_open_help).to include("+review-app-delete") - expect(pr_open_help).to include("+review-app-help") + expect(pr_open_help).to include('"- `+review-app-deploy`') + expect(pr_open_help).to include('"- `+review-app-delete`') + expect(pr_open_help).to include('"- `+review-app-help`') end it "documents Docker build vars in the help markdown" do From afcc2c1e2ba6229ad363821328f75881b42d465d Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Mon, 11 May 2026 18:14:45 -1000 Subject: [PATCH 5/6] Address review app command feedback --- CHANGELOG.md | 2 +- .../workflows/cpflow-review-app-help.yml | 4 +++- spec/command/generate_github_actions_spec.rb | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8461e2b..56457f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ In addition to the standard keepachangelog.com categories, this project uses a l ### Changed -- Renamed the generated review-app PR comment commands to a namespaced `+review-app-*` family: `/deploy-review-app` → `+review-app-deploy`, `/delete-review-app` → `+review-app-delete`, and `/help` → `+review-app-help`. The `+` prefix is used instead of `/` to avoid collision with GitHub's reserved slash-command surface and with other bots that listen on `/help`, and to make the three commands obviously part of one namespaced family. Repos that ran `cpflow generate-github-actions` against 5.0.0.rc.0 must regenerate the workflow templates and update saved instructions or runbooks. [PR 285](https://github.com/shakacode/control-plane-flow/pull/285) by [Justin Gordon](https://github.com/justin808). +- Renamed the generated review-app PR comment commands to a namespaced `+review-app-*` family: `/deploy-review-app` → `+review-app-deploy`, `/delete-review-app` → `+review-app-delete`, and `/help` → `+review-app-help`. The `+` prefix is used instead of `/` to avoid collision with GitHub's reserved slash-command surface and with other bots that listen on `/help`, and to make the three commands obviously part of one namespaced family. Repos that ran `cpflow generate-github-actions` against 5.0.0.rc.0 must regenerate the generated `.github/workflows/cpflow-*.yml` files and `.github/cpflow-help.md`, then update saved instructions or runbooks. [PR 285](https://github.com/shakacode/control-plane-flow/pull/285) by [Justin Gordon](https://github.com/justin808). ## [5.0.0.rc.0] - 2026-05-05 diff --git a/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml b/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml index f590ea60..74626217 100644 --- a/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml +++ b/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml @@ -28,11 +28,13 @@ jobs: const body = [ "# Review app commands", "", + "Repo owners, members, and collaborators can use these commands:", + "", "- `+review-app-deploy` - create or redeploy this PR's review app.", "- `+review-app-delete` - delete this PR's review app and temporary resources.", "- `+review-app-help` - show setup details and workflow behavior.", "", - "For setup details, comment `+review-app-help`." + "For setup details, repo owners, members, and collaborators can comment `+review-app-help`." ].join("\n"); await github.rest.issues.createComment({ diff --git a/spec/command/generate_github_actions_spec.rb b/spec/command/generate_github_actions_spec.rb index 9704c7ca..11f92ce7 100644 --- a/spec/command/generate_github_actions_spec.rb +++ b/spec/command/generate_github_actions_spec.rb @@ -228,15 +228,31 @@ def generated_yaml_paths expect(contents).to include('fs.readFileSync(".github/cpflow-help.md"') end - it "pins the public +review-app-* PR comment trigger strings" do + it "pins the +review-app-* workflow trigger strings" do expect(review_app_workflow_path.read).to include("github.event.comment.body == '+review-app-deploy'") expect(delete_review_workflow_path.read).to include("github.event.comment.body == '+review-app-delete'") expect(help_workflow_path.read).to include("github.event.comment.body == '+review-app-help'") + end + it "pins the +review-app-* commands in the PR-open message" do pr_open_help = pr_open_help_workflow_path.read + + expect(pr_open_help).to include('"Repo owners, members, and collaborators can use these commands:"') + # The leading " is the opening quote of the JS array string literal in cpflow-review-app-help.yml. expect(pr_open_help).to include('"- `+review-app-deploy`') expect(pr_open_help).to include('"- `+review-app-delete`') expect(pr_open_help).to include('"- `+review-app-help`') + expect(pr_open_help).to include( + '"For setup details, repo owners, members, and collaborators can comment `+review-app-help`."' + ) + end + + it "pins the +review-app-* commands in the long-form help markdown" do + help_md = playground.join(".github/cpflow-help.md").read + + expect(help_md).to include("`+review-app-deploy`") + expect(help_md).to include("`+review-app-delete`") + expect(help_md).to include("`+review-app-help`") end it "documents Docker build vars in the help markdown" do From 13287347b6ee29a2ba0b8b5e5e13389285fbdf27 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Mon, 11 May 2026 18:41:43 -1000 Subject: [PATCH 6/6] Address review app command nits --- CONTRIBUTING.md | 6 +++--- .../.github/cpflow-help.md | 6 +++--- .../workflows/cpflow-delete-review-app.yml | 2 +- .../workflows/cpflow-deploy-review-app.yml | 4 ++-- .../.github/workflows/cpflow-help-command.yml | 2 +- spec/command/generate_github_actions_spec.rb | 18 +++++++++++------- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee8d5e33..bb3f3860 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -89,9 +89,9 @@ cpflow test - **Test PR-branch workflow edits in a real repo.** Comment-triggered runs (`+review-app-deploy`, `+review-app-delete`, `+review-app-help`) execute the workflow code from the repository's default branch, so they will not exercise your PR-branch changes. Generate the workflows into a downstream test repo, push to a feature branch, then dispatch each affected workflow with `gh`: ```sh - gh workflow run cpflow-deploy-review-app.yml --ref -f pr_number= - gh workflow run cpflow-delete-review-app.yml --ref -f pr_number= - gh workflow run cpflow-help-command.yml --ref -f pr_number= + gh workflow run cpflow-deploy-review-app.yml --ref -f pr_number= + gh workflow run cpflow-delete-review-app.yml --ref -f pr_number= + gh workflow run cpflow-help-command.yml --ref -f pr_number= ``` ## Releasing diff --git a/lib/github_flow_templates/.github/cpflow-help.md b/lib/github_flow_templates/.github/cpflow-help.md index a53eeaae..dd82ba08 100644 --- a/lib/github_flow_templates/.github/cpflow-help.md +++ b/lib/github_flow_templates/.github/cpflow-help.md @@ -8,16 +8,16 @@ You asked for review app help. These commands are generated by [cpflow](https:// - Creates the review app if it does not exist - Builds the PR commit image - Deploys the image and comments with the review URL -- Comment body must be exactly `+review-app-deploy` — no surrounding text, trailing whitespace, or trailing newline. The trigger uses an exact-equality match, so a comment like `please +review-app-deploy now` or `+review-app-deploy ` (with a trailing space) silently no-ops. +- Comment body must be exactly `+review-app-deploy`, with no surrounding text or trailing spaces. A single trailing newline from GitHub's comment editor is accepted. Comments like `please +review-app-deploy now` or `+review-app-deploy ` (with a trailing space) silently no-op. `+review-app-delete` - Deletes the review app when the PR is done - This also runs automatically when the PR closes -- Comment body must be exactly `+review-app-delete` — no surrounding text, trailing whitespace, or trailing newline. Same exact-equality rule as `+review-app-deploy`. +- Comment body must be exactly `+review-app-delete`, with no surrounding text or trailing spaces. A single trailing newline from GitHub's comment editor is accepted. Same command-match rule as `+review-app-deploy`. `+review-app-help` - Posts this message on the PR. -- Comment body must be exactly `+review-app-help` — no surrounding text, trailing whitespace, or trailing newline. Same exact-equality rule as `+review-app-deploy`. +- Comment body must be exactly `+review-app-help`, with no surrounding text or trailing spaces. A single trailing newline from GitHub's comment editor is accepted. Same command-match rule as `+review-app-deploy`. ## Workflow behavior diff --git a/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml b/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml index 34c07d44..a4006f8b 100644 --- a/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml +++ b/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml @@ -33,7 +33,7 @@ jobs: if: | (github.event_name == 'issue_comment' && github.event.issue.pull_request && - github.event.comment.body == '+review-app-delete' && + contains(fromJson('["+review-app-delete","+review-app-delete\n","+review-app-delete\r\n"]'), github.event.comment.body) && contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) || (github.event_name == 'pull_request_target' && github.event.action == 'closed') || github.event_name == 'workflow_dispatch' diff --git a/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml b/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml index ac216133..27f90484 100644 --- a/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +++ b/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml @@ -45,7 +45,7 @@ jobs: github.event_name == 'workflow_dispatch' || (github.event_name == 'issue_comment' && github.event.issue.pull_request && - github.event.comment.body == '+review-app-deploy' && + contains(fromJson('["+review-app-deploy","+review-app-deploy\n","+review-app-deploy\r\n"]'), github.event.comment.body) && contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) runs-on: ubuntu-latest timeout-minutes: 45 @@ -236,7 +236,7 @@ jobs: run: | { echo "Review app ${APP_NAME} does not exist yet." - echo "Create it with a PR comment that is exactly +review-app-deploy." + echo "Create it with +review-app-deploy as the PR comment body." } >> "$GITHUB_STEP_SUMMARY" - name: Setup review app if it does not exist yet diff --git a/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml b/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml index 6fbab0b8..0818dfb2 100644 --- a/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml +++ b/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml @@ -25,7 +25,7 @@ jobs: if: | (github.event_name == 'issue_comment' && github.event.issue.pull_request && - github.event.comment.body == '+review-app-help' && + contains(fromJson('["+review-app-help","+review-app-help\n","+review-app-help\r\n"]'), github.event.comment.body) && contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest diff --git a/spec/command/generate_github_actions_spec.rb b/spec/command/generate_github_actions_spec.rb index 11f92ce7..d37b2b96 100644 --- a/spec/command/generate_github_actions_spec.rb +++ b/spec/command/generate_github_actions_spec.rb @@ -34,6 +34,10 @@ def pr_open_help_workflow_path playground.join(".github/workflows/cpflow-review-app-help.yml") end + def command_body_match_expression(command) + %(contains(fromJson('["#{command}","#{command}\\n","#{command}\\r\\n"]'), github.event.comment.body)) + end + def promote_workflow_path playground.join(".github/workflows/cpflow-promote-staging-to-production.yml") end @@ -229,19 +233,18 @@ def generated_yaml_paths end it "pins the +review-app-* workflow trigger strings" do - expect(review_app_workflow_path.read).to include("github.event.comment.body == '+review-app-deploy'") - expect(delete_review_workflow_path.read).to include("github.event.comment.body == '+review-app-delete'") - expect(help_workflow_path.read).to include("github.event.comment.body == '+review-app-help'") + expect(review_app_workflow_path.read).to include(command_body_match_expression("+review-app-deploy")) + expect(delete_review_workflow_path.read).to include(command_body_match_expression("+review-app-delete")) + expect(help_workflow_path.read).to include(command_body_match_expression("+review-app-help")) end it "pins the +review-app-* commands in the PR-open message" do pr_open_help = pr_open_help_workflow_path.read expect(pr_open_help).to include('"Repo owners, members, and collaborators can use these commands:"') - # The leading " is the opening quote of the JS array string literal in cpflow-review-app-help.yml. - expect(pr_open_help).to include('"- `+review-app-deploy`') - expect(pr_open_help).to include('"- `+review-app-delete`') - expect(pr_open_help).to include('"- `+review-app-help`') + expect(pr_open_help).to include("- `+review-app-deploy` - create or redeploy this PR's review app.") + expect(pr_open_help).to include("- `+review-app-delete` - delete this PR's review app and temporary resources.") + expect(pr_open_help).to include("- `+review-app-help` - show setup details and workflow behavior.") expect(pr_open_help).to include( '"For setup details, repo owners, members, and collaborators can comment `+review-app-help`."' ) @@ -253,6 +256,7 @@ def generated_yaml_paths expect(help_md).to include("`+review-app-deploy`") expect(help_md).to include("`+review-app-delete`") expect(help_md).to include("`+review-app-help`") + expect(help_md).to include("A single trailing newline from GitHub's comment editor is accepted.") end it "documents Docker build vars in the help markdown" do