Skip to content

Commit bb9d579

Browse files
authored
Regenerate cpflow review app flow (#735)
1 parent 5c94c36 commit bb9d579

14 files changed

Lines changed: 89 additions & 131 deletions

.controlplane/readme.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -369,17 +369,18 @@ Review Apps (deployment of apps based on a PR) are done via the generated
369369

370370
The review apps work by creating isolated deployments for pull requests through
371371
this automated process. When an approved collaborator comments exactly
372-
`/deploy-review-app` on a PR, the action:
372+
`+review-app-deploy` on a PR, the action:
373373

374374
1. Sets up the necessary environment and tools
375375
2. Creates a unique review app if it doesn't exist
376376
3. Builds a Docker image tagged with the PR commit SHA
377377
4. Deploys this image to Control Plane with its own isolated environment
378378

379379
After the review app exists, new pushes to the PR redeploy it automatically.
380-
Use `/delete-review-app` to delete it manually; closing the PR deletes it
381-
automatically. Pushes to the staging branch deploy staging, and production
382-
promotion is manual from the `cpflow-promote-staging-to-production` workflow.
380+
Use `+review-app-delete` to delete it manually; closing the PR deletes it
381+
automatically. Use `+review-app-help` for the review-app command reference.
382+
Pushes to the staging branch deploy staging, and production promotion is manual
383+
from the `cpflow-promote-staging-to-production` workflow.
383384
If staging moves off `master`, update both the `STAGING_APP_BRANCH` repository
384385
variable and the `branches:` filter in `.github/workflows/cpflow-deploy-staging.yml`;
385386
GitHub does not allow repository variables in trigger branch filters.
@@ -432,9 +433,9 @@ bundle exec rubocop
432433
Then open a normal PR and let GitHub Actions prove the generated review-app,
433434
staging, lint, JS, and RSpec workflows before merging. For review-app workflow
434435
changes, test both the local workflow syntax and a real deployment. GitHub runs
435-
`issue_comment` workflows from the default branch, so a `/deploy-review-app`
436-
comment on the PR does not fully exercise slash-command changes that are only on
437-
the PR branch. Before merge, run the PR branch workflow explicitly:
436+
`issue_comment` workflows from the default branch, so a `+review-app-deploy`
437+
comment on the PR does not fully exercise command changes that are only on the
438+
PR branch. Before merge, run the PR branch workflow explicitly:
438439

439440
```bash
440441
gh workflow run cpflow-deploy-review-app.yml --ref <branch> -f pr_number=<pr-number>

.controlplane/shakacode-team.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
Deployments are handled by Control Plane configuration in this repo and GitHub Actions.
66

77
### Review Apps
8-
- Add a comment `/deploy-review-app` to any PR to deploy a review app
8+
- Add a comment `+review-app-deploy` to any PR to deploy a review app
99
- The generated app name is `${REVIEW_APP_PREFIX}-${PR_NUMBER}`. Keep
1010
`REVIEW_APP_PREFIX` set to `qa-react-webpack-rails-tutorial-pr` so review
1111
apps use names like `qa-react-webpack-rails-tutorial-pr-1234`, matching the
1212
prefix-backed config in `.controlplane/controlplane.yml`.
1313
- New pushes to a PR redeploy only after the review app already exists.
14-
- Add `/delete-review-app` to delete a review app manually; closing the PR also
15-
deletes it automatically.
14+
- Add `+review-app-delete` to delete a review app manually; closing the PR also
15+
deletes it automatically. Use `+review-app-help` for the command reference.
1616

1717
### Staging Environment
1818
- **Automatic**: Any merge to the `master` branch automatically deploys to staging

.github/actions/cpflow-setup-environment/action.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ inputs:
1717
cpln_cli_version:
1818
description: >-
1919
@controlplane/cli version. Empty string falls back to the action's pinned default
20-
so callers can pass the repository variable value unconditionally.
20+
so callers can pass `${{ vars.CPLN_CLI_VERSION }}` unconditionally.
2121
required: false
2222
default: ""
2323
cpflow_version:
2424
description: >-
2525
cpflow gem version. Empty string falls back to the action's pinned default
26-
so callers can pass the repository variable value unconditionally.
26+
so callers can pass `${{ vars.CPFLOW_VERSION }}` unconditionally.
2727
required: false
2828
default: ""
2929

@@ -54,7 +54,7 @@ runs:
5454
# Override per-repo by setting `CPLN_CLI_VERSION` / `CPFLOW_VERSION` repo variables;
5555
# an empty input falls back to the action's pinned default below.
5656
default_cpln_cli_version="3.3.1"
57-
default_cpflow_version="5.0.0.rc.0"
57+
default_cpflow_version="5.0.0.rc.1"
5858
5959
CPLN_CLI_VERSION="${CPLN_CLI_VERSION:-${default_cpln_cli_version}}"
6060
CPFLOW_VERSION="${CPFLOW_VERSION:-${default_cpflow_version}}"

.github/cpflow-help.md

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,49 @@
1-
# Control Plane GitHub Flow
1+
# Review app help
2+
3+
You asked for review app help. These commands are generated by [cpflow](https://github.com/shakacode/control-plane-flow).
24

35
## PR commands
46

5-
`/deploy-review-app`
7+
`+review-app-deploy`
68
- Creates the review app if it does not exist
79
- Builds the PR commit image
810
- Deploys the image and comments with the review URL
9-
- 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.
11+
- 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.
1012

11-
`/delete-review-app`
13+
`+review-app-delete`
1214
- Deletes the review app when the PR is done
1315
- This also runs automatically when the PR closes
14-
- Same exact-match rule as `/deploy-review-app`: the comment body must be exactly `/delete-review-app`.
16+
- 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`.
17+
18+
`+review-app-help`
19+
- Posts this message on the PR.
20+
- 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`.
21+
22+
## Workflow behavior
23+
24+
- Review apps are opt-in and created with `+review-app-deploy`
25+
- New commits redeploy existing review apps automatically
26+
- Pushes to the staging branch deploy staging automatically
27+
- Promotion to production is manual via the Actions tab
28+
- A nightly workflow removes stale review apps
29+
30+
<details>
31+
<summary>Advanced: GitHub Actions secrets and variables</summary>
1532

16-
## Repository secrets
33+
### GitHub Actions secrets
1734

1835
| Name | Required | Notes |
1936
| --- | --- | --- |
20-
| `CPLN_TOKEN_STAGING` | yes | Service-account token scoped to the staging org. |
21-
| `CPLN_TOKEN_PRODUCTION` | yes (for promote) | Service-account token scoped to the production org. |
37+
| `CPLN_TOKEN_STAGING` | yes | Service-account token scoped to the staging Control Plane org on controlplane.com. |
38+
| `CPLN_TOKEN_PRODUCTION` | yes (for promote) | Service-account token scoped to the production Control Plane org on controlplane.com. |
2239
| `DOCKER_BUILD_SSH_KEY` | optional | Private SSH key used when Docker builds fetch private deps via `RUN --mount=type=ssh`. |
2340

24-
## Repository variables
41+
### GitHub Actions variables
2542

2643
| Name | Required | Notes |
2744
| --- | --- | --- |
28-
| `CPLN_ORG_STAGING` | yes | Control Plane org for staging and review apps. |
29-
| `CPLN_ORG_PRODUCTION` | yes (for promote) | Control Plane org for production. |
45+
| `CPLN_ORG_STAGING` | yes | Control Plane org on controlplane.com for staging and review apps. |
46+
| `CPLN_ORG_PRODUCTION` | yes (for promote) | Control Plane org on controlplane.com for production. |
3047
| `STAGING_APP_NAME` | yes | App name in `controlplane.yml` used as the staging deploy target. |
3148
| `PRODUCTION_APP_NAME` | yes (for promote) | App name in `controlplane.yml` used as the production deploy target. |
3249
| `REVIEW_APP_PREFIX` | yes | Prefix for per-PR review app names (e.g. `review-app`). |
@@ -35,16 +52,22 @@
3552
| `DOCKER_BUILD_EXTRA_ARGS` | optional | Newline-delimited extra docker build tokens (e.g. `--build-arg=FOO=bar`). |
3653
| `DOCKER_BUILD_SSH_KNOWN_HOSTS` | optional | SSH known_hosts entries when SSH build hosts are not GitHub.com. |
3754
| `HEALTH_CHECK_ACCEPTED_STATUSES` | optional | Space-separated HTTP statuses considered healthy on promote (default `200 301 302`). |
38-
| `HEALTH_CHECK_RETRIES` / `HEALTH_CHECK_INTERVAL` | optional | Production health polling controls; defaults to `24` retries and `15` seconds. |
39-
| `ROLLBACK_READINESS_RETRIES` / `ROLLBACK_READINESS_INTERVAL` | optional | Post-rollback health polling controls; defaults to `24` retries and `15` seconds. |
4055
| `CPLN_CLI_VERSION` | optional | Pin a specific `@controlplane/cli` version; falls back to the action default when unset. |
4156
| `CPFLOW_VERSION` | optional | Pin a specific cpflow gem version; falls back to the generated default when unset. |
4257

43-
## Workflow behavior
58+
</details>
4459

45-
- Review apps are opt-in and created with `/deploy-review-app`
46-
- New commits redeploy existing review apps automatically
47-
- Slash command workflows run from the default branch until merged. Test PR-branch edits with `gh workflow run cpflow-deploy-review-app.yml --ref <branch> -f pr_number=<pr-number>`.
48-
- Pushes to the staging branch deploy staging automatically
49-
- Promotion to production is manual via the Actions tab
50-
- A nightly workflow removes stale review apps
60+
<details>
61+
<summary>Advanced: testing changes to generated workflows</summary>
62+
63+
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`:
64+
65+
```sh
66+
gh workflow run cpflow-deploy-review-app.yml --ref <your-pr-branch> -f pr_number=<pr-number>
67+
gh workflow run cpflow-delete-review-app.yml --ref <your-pr-branch> -f pr_number=<pr-number>
68+
gh workflow run cpflow-help-command.yml --ref <your-pr-branch> -f pr_number=<pr-number>
69+
```
70+
71+
`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.
72+
73+
</details>

.github/workflows/cpflow-cleanup-stale-review-apps.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ jobs:
4848

4949
- name: Remove stale review apps
5050
env:
51-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
5251
REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
5352
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
5453
shell: bash

.github/workflows/cpflow-delete-review-app.yml

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ on:
1414

1515
permissions:
1616
contents: read
17-
deployments: write
1817
issues: write
1918
pull-requests: write
2019

@@ -34,7 +33,7 @@ jobs:
3433
if: |
3534
(github.event_name == 'issue_comment' &&
3635
github.event.issue.pull_request &&
37-
github.event.comment.body == '/delete-review-app' &&
36+
contains(fromJson('["+review-app-delete","+review-app-delete\n","+review-app-delete\r\n"]'), github.event.comment.body) &&
3837
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
3938
(github.event_name == 'pull_request_target' && github.event.action == 'closed') ||
4039
github.event_name == 'workflow_dispatch'
@@ -109,43 +108,11 @@ jobs:
109108
- name: Delete review app
110109
if: steps.config.outputs.ready == 'true'
111110
uses: ./.github/actions/cpflow-delete-control-plane-app
112-
env:
113-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
114111
with:
115112
app_name: ${{ env.APP_NAME }}
116113
cpln_org: ${{ vars.CPLN_ORG_STAGING }}
117114
review_app_prefix: ${{ vars.REVIEW_APP_PREFIX }}
118115

119-
- name: Mark GitHub deployment inactive
120-
if: steps.config.outputs.ready == 'true'
121-
uses: actions/github-script@v7
122-
with:
123-
script: |
124-
const environment = `review/${process.env.APP_NAME}`;
125-
const deployments = await github.paginate(github.rest.repos.listDeployments, {
126-
owner: context.repo.owner,
127-
repo: context.repo.repo,
128-
environment,
129-
per_page: 100
130-
});
131-
132-
if (deployments.length === 0) {
133-
core.info(`No GitHub deployments found for ${environment}.`);
134-
return;
135-
}
136-
137-
for (const deployment of deployments) {
138-
await github.rest.repos.createDeploymentStatus({
139-
owner: context.repo.owner,
140-
repo: context.repo.repo,
141-
deployment_id: deployment.id,
142-
state: "inactive",
143-
environment,
144-
log_url: process.env.WORKFLOW_URL,
145-
description: "Review app deleted"
146-
});
147-
}
148-
149116
- name: Finalize delete status
150117
if: always() && steps.config.outputs.ready == 'true'
151118
uses: actions/github-script@v7

.github/workflows/cpflow-deploy-review-app.yml

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ jobs:
3737
deploy:
3838
# Skip synchronize/opened events from fork PRs at the job level — they cannot access
3939
# repository secrets anyway, so running any steps just burns billable minutes. Users
40-
# can still manually deploy a fork PR via `/deploy-review-app` (gated below by
40+
# can still manually deploy a fork PR via `+review-app-deploy` (gated below by
4141
# author_association) or workflow_dispatch.
4242
if: |
4343
(github.event_name == 'pull_request' &&
4444
github.event.pull_request.head.repo.full_name == github.repository) ||
4545
github.event_name == 'workflow_dispatch' ||
4646
(github.event_name == 'issue_comment' &&
4747
github.event.issue.pull_request &&
48-
github.event.comment.body == '/deploy-review-app' &&
48+
contains(fromJson('["+review-app-deploy","+review-app-deploy\n","+review-app-deploy\r\n"]'), github.event.comment.body) &&
4949
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association))
5050
runs-on: ubuntu-latest
5151
timeout-minutes: 45
@@ -61,26 +61,6 @@ jobs:
6161
ref: ${{ github.event.repository.default_branch }}
6262
persist-credentials: false
6363

64-
- name: Set up Ruby for cpflow bootstrap
65-
if: ${{ hashFiles('.github/actions/cpflow-validate-config/action.yml') == '' }}
66-
uses: ruby/setup-ruby@v1
67-
with:
68-
ruby-version: "3.4"
69-
70-
- name: Bootstrap generated cpflow actions
71-
if: ${{ hashFiles('.github/actions/cpflow-validate-config/action.yml') == '' }}
72-
shell: bash
73-
run: |
74-
set -euo pipefail
75-
gem install cpflow -v "5.0.0.rc.0" --no-document
76-
ruby -S cpflow generate-github-actions --staging-branch master
77-
# shellcheck disable=SC2016
78-
ruby -0pi -e '$_.gsub!(/so callers can pass `\$\{\{ vars\.CPLN_CLI_VERSION \}\}` unconditionally\./, "so callers can pass the repository variable value unconditionally."); $_.gsub!(/so callers can pass `\$\{\{ vars\.CPFLOW_VERSION \}\}` unconditionally\./, "so callers can pass the repository variable value unconditionally.")' .github/actions/cpflow-setup-environment/action.yml
79-
if grep -n '\$''{{ vars\.\(CPLN_CLI_VERSION\|CPFLOW_VERSION\) }}' .github/actions/cpflow-setup-environment/action.yml; then
80-
echo "::error::Bootstrapped cpflow setup action still contains GitHub metadata expressions in input descriptions."
81-
exit 1
82-
fi
83-
8464
- name: Validate required secrets and variables
8565
id: config
8666
uses: ./.github/actions/cpflow-validate-config
@@ -220,8 +200,6 @@ jobs:
220200
if: steps.config.outputs.ready == 'true' && steps.source.outputs.allowed == 'true'
221201
id: check-app
222202
working-directory: app
223-
env:
224-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
225203
shell: bash
226204
run: |
227205
set -euo pipefail
@@ -260,15 +238,13 @@ jobs:
260238
run: |
261239
{
262240
echo "Review app ${APP_NAME} does not exist yet."
263-
echo "Create it with a PR comment that is exactly /deploy-review-app."
241+
echo "Create it with +review-app-deploy as the PR comment body."
264242
} >> "$GITHUB_STEP_SUMMARY"
265243
266244
- name: Setup review app if it does not exist yet
267245
id: setup-review-app
268246
if: steps.config.outputs.ready == 'true' && steps.source.outputs.allowed == 'true' && steps.check-app.outputs.exists != 'true' && github.event_name != 'pull_request'
269247
working-directory: app
270-
env:
271-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
272248
shell: bash
273249
run: |
274250
set -euo pipefail
@@ -355,8 +331,6 @@ jobs:
355331
- name: Build Docker image
356332
if: steps.config.outputs.ready == 'true' && steps.source.outputs.allowed == 'true' && (steps.check-app.outputs.exists == 'true' || steps.setup-review-app.outcome == 'success')
357333
uses: ./.github/actions/cpflow-build-docker-image
358-
env:
359-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
360334
with:
361335
app_name: ${{ env.APP_NAME }}
362336
org: ${{ vars.CPLN_ORG_STAGING }}
@@ -397,7 +371,6 @@ jobs:
397371
if: steps.config.outputs.ready == 'true' && steps.source.outputs.allowed == 'true' && (steps.check-app.outputs.exists == 'true' || steps.setup-review-app.outcome == 'success')
398372
working-directory: app
399373
env:
400-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
401374
RELEASE_PHASE_FLAG: ${{ steps.release-phase.outputs.flag }}
402375
shell: bash
403376
run: |
@@ -415,8 +388,6 @@ jobs:
415388
if: steps.config.outputs.ready == 'true' && steps.source.outputs.allowed == 'true' && (steps.check-app.outputs.exists == 'true' || steps.setup-review-app.outcome == 'success')
416389
id: workload
417390
working-directory: app
418-
env:
419-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
420391
shell: bash
421392
run: |
422393
set -euo pipefail

.github/workflows/cpflow-deploy-staging.yml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
# deploy branches unless `cpflow generate-github-actions --staging-branch BRANCH`
99
# was used. If STAGING_APP_BRANCH is later changed in repository variables, keep
1010
# this list in sync so pushes to that branch actually trigger the workflow.
11-
branches: ["master"]
11+
branches: ["main", "master"]
1212
workflow_dispatch:
1313

1414
permissions:
@@ -17,7 +17,7 @@ permissions:
1717
env:
1818
APP_NAME: ${{ vars.STAGING_APP_NAME }}
1919
CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }}
20-
STAGING_APP_BRANCH: ${{ vars.STAGING_APP_BRANCH || 'master' }}
20+
STAGING_APP_BRANCH: ${{ vars.STAGING_APP_BRANCH }}
2121

2222
concurrency:
2323
group: cpflow-deploy-staging-${{ github.ref_name }}
@@ -56,8 +56,6 @@ jobs:
5656
- name: Checkout repository
5757
if: steps.check-branch.outputs.is_deployable == 'true'
5858
uses: actions/checkout@v4
59-
with:
60-
persist-credentials: false
6159

6260
- name: Validate required secrets and variables
6361
if: steps.check-branch.outputs.is_deployable == 'true'
@@ -93,8 +91,6 @@ jobs:
9391

9492
- name: Build Docker image
9593
uses: ./.github/actions/cpflow-build-docker-image
96-
env:
97-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
9894
with:
9995
app_name: ${{ env.APP_NAME }}
10096
org: ${{ vars.CPLN_ORG_STAGING }}
@@ -105,7 +101,7 @@ jobs:
105101

106102
deploy:
107103
needs: [validate-branch, build]
108-
if: needs.validate-branch.outputs.is_deployable == 'true' && needs.build.result == 'success'
104+
if: needs.validate-branch.outputs.is_deployable == 'true'
109105
runs-on: ubuntu-latest
110106
timeout-minutes: 30
111107
steps:
@@ -130,7 +126,6 @@ jobs:
130126

131127
- name: Deploy staging image
132128
env:
133-
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN_STAGING }}
134129
RELEASE_PHASE_FLAG: ${{ steps.release-phase.outputs.flag }}
135130
shell: bash
136131
run: |

0 commit comments

Comments
 (0)