|
1 | 1 | # Testing cpflow GitHub Actions Changes |
2 | 2 |
|
3 | | -Use this guide when changing generated `cpflow-*` GitHub Actions, updating the |
4 | | -`cpflow` generator version, or debugging review-app automation. |
5 | | - |
6 | | -## What To Test |
7 | | - |
8 | | -Test the flow in three layers: |
9 | | - |
10 | | -1. Local generated-file checks catch YAML, metadata, and lint problems before a PR. |
11 | | -2. GitHub workflow checks prove GitHub can load the workflow and run CI. |
12 | | -3. A real review-app deploy proves the default-branch trusted actions, GitHub |
13 | | - secrets, Docker build, and Control Plane deploy all work together. |
14 | | - |
15 | | -The third layer matters because the review-app workflow intentionally checks out |
16 | | -trusted workflow sources from the repository default branch before passing |
17 | | -Control Plane secrets to local composite actions. A PR branch can contain fixed |
18 | | -`.github/actions/*` files, but the deploy job still loads those local actions |
19 | | -from `master` until the fix is merged there. |
20 | | - |
21 | | -## How Upstream Code Is Pinned |
22 | | - |
23 | | -Generated `cpflow-*` workflows are thin wrappers around reusable workflows in |
24 | | -`shakacode/control-plane-flow`. GitHub reusable workflows cannot be loaded from |
25 | | -a Ruby gem; GitHub resolves them from a repository ref. Each wrapper therefore |
26 | | -has two upstream pins that must stay in sync: |
27 | | - |
28 | | -```yaml |
29 | | -uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@<ref> |
30 | | -with: |
31 | | - control_plane_flow_ref: <ref> |
32 | | -``` |
33 | | -
|
34 | | -`uses: ...@<ref>` chooses the reusable workflow file. `control_plane_flow_ref` |
35 | | -chooses the same upstream checkout for shared composite actions and, when |
36 | | -`CPFLOW_VERSION` is unset, the source used to build and install the `cpflow` gem |
37 | | -inside the workflow. |
38 | | - |
39 | | -The stable release path is still gem-driven: |
40 | | - |
41 | | -1. Install or update to a released `cpflow` gem. |
42 | | -2. Run `cpflow generate-github-actions --staging-branch master`. |
43 | | -3. The generated wrappers use `v<cpflow gem version>` as the upstream ref. |
44 | | - |
45 | | -That tag should point to the same source that produced the RubyGems release, so |
46 | | -the workflow code is locked to a release tag rather than a moving branch. Do not |
47 | | -pin production workflows to `main` or a feature branch. For unreleased testing, |
48 | | -pin to an immutable commit SHA, not a branch name, then regenerate or repin to |
49 | | -the release tag after the upstream release is published. |
50 | | - |
51 | | -`CPFLOW_VERSION` is separate from the GitHub workflow ref. If the repository |
52 | | -variable is set, the setup action runs `gem install cpflow -v <version>`. If it |
53 | | -is unset, the setup action builds `cpflow` from the checked-out upstream ref. |
54 | | -For normal releases, either leave `CPFLOW_VERSION` unset while using the matching |
55 | | -`v<version>` upstream tag, or set `CPFLOW_VERSION` to the same released gem |
56 | | -version without the leading `v`. |
57 | | - |
58 | | -This repo is currently pinned to an upstream commit SHA because the reusable |
59 | | -workflow change was tested before a new `cpflow` gem release existed. That is |
60 | | -safer than pinning a branch, but it should be treated as a temporary test pin |
61 | | -until the next upstream release tag is available. |
62 | | - |
63 | | -What is tied to the upstream repo: |
64 | | - |
65 | | -- The downstream workflow wrapper hardcodes `shakacode/control-plane-flow` in |
66 | | - `uses:`. |
67 | | -- The reusable workflow file comes from the ref after `@`. |
68 | | -- The reusable workflow checks out `control-plane-flow` at |
69 | | - `control_plane_flow_ref` to load shared composite actions. |
70 | | -- When `CPFLOW_VERSION` is empty, the setup action builds and installs the |
71 | | - `cpflow` gem from that checked-out repository ref. |
72 | | - |
73 | | -What is tied to RubyGems: |
74 | | - |
75 | | -- A released `cpflow` gem is the normal source used to generate downstream |
76 | | - workflow wrappers. |
77 | | -- The `CPFLOW_VERSION` repository variable is a runtime override that runs |
78 | | - `gem install cpflow -v <version>` inside workflows. |
79 | | - |
80 | | -For stable downstream automation, prefer the release path: generate from a |
81 | | -released gem and pin wrappers to the matching upstream release tag. For |
82 | | -pre-release validation, pin to a full commit SHA from the upstream PR, never a |
83 | | -moving branch. |
84 | | - |
85 | | -## Testing An Unmerged Upstream PR Downstream |
86 | | - |
87 | | -You can test an upstream `control-plane-flow` PR in this downstream app before |
88 | | -merging upstream, without publishing a gem. Use an immutable commit SHA from the |
89 | | -upstream PR branch: |
90 | | - |
91 | | -1. Push the upstream PR branch and copy its head commit SHA. |
92 | | -2. In a downstream test branch, pin every generated wrapper ref: |
93 | | - |
94 | | - ```sh |
95 | | - bin/pin-cpflow-github-ref <upstream-pr-sha> |
96 | | - ``` |
97 | | - |
98 | | - The helper accepts release tags and full 40-character commit SHAs by default. |
99 | | - It rejects branch names such as `main` or `feature/foo`; use |
100 | | - `--allow-moving-ref` only for short-lived local experiments that will not be |
101 | | - committed. The resulting diff should replace both pins in each reusable |
102 | | - workflow call: |
103 | | - |
104 | | - ```yaml |
105 | | - uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@<upstream-pr-sha> |
106 | | - with: |
107 | | - control_plane_flow_ref: <upstream-pr-sha> |
108 | | - ``` |
109 | | - |
110 | | -3. Keep `CPFLOW_VERSION` unset unless you intentionally want to test a released |
111 | | - RubyGems version instead of building `cpflow` from the upstream PR SHA. |
112 | | -4. Run `bin/test-cpflow-github-flow`. |
113 | | -5. Open a downstream PR and trigger a real review app with a comment whose body |
114 | | - is exactly: |
115 | | - |
116 | | - ```text |
117 | | - +review-app-deploy |
118 | | - ``` |
119 | | - |
120 | | -6. Verify the deploy logs show the expected upstream commit SHA, the setup step |
121 | | - prints the expected `cpflow` version/source, and the review app URL returns |
122 | | - HTTP 200. |
123 | | -7. After the upstream PR merges and releases, regenerate or repin downstream to |
124 | | - the release tag instead of leaving the temporary commit SHA forever. |
125 | | - |
126 | | -This tests the real reusable workflow and shared composite actions from the |
127 | | -upstream PR. It avoids merging upstream blind while also avoiding a mutable |
128 | | -branch ref in downstream automation. |
| 3 | +Generic reusable-workflow behavior belongs upstream in the |
| 4 | +[`control-plane-flow` CI automation guide](https://github.com/shakacode/control-plane-flow/blob/main/docs/ci-automation.md). |
| 5 | +Use this repo note only as the canary checklist for |
| 6 | +`react-webpack-rails-tutorial`. |
129 | 7 |
|
130 | 8 | ## Local Checks |
131 | 9 |
|
132 | | -After regenerating the flow, run these checks from the repository root. If |
133 | | -`cpflow` is installed as a gem, use `cpflow` directly: |
| 10 | +After regenerating the generated `cpflow-*` wrappers, run: |
134 | 11 |
|
135 | 12 | ```sh |
136 | | -bin/conductor-exec cpflow generate-github-actions --staging-branch master |
137 | | -bin/test-cpflow-github-flow |
| 13 | +bin/conductor-exec bin/test-cpflow-github-flow |
138 | 14 | ``` |
139 | 15 |
|
140 | | -When testing an unreleased upstream `control-plane-flow` checkout, replace |
141 | | -`cpflow` with that checkout's `bin/cpflow`: |
| 16 | +When testing an unreleased upstream `control-plane-flow` checkout, pass that |
| 17 | +checkout's `bin/cpflow`: |
142 | 18 |
|
143 | 19 | ```sh |
144 | | -bin/conductor-exec ruby /path/to/control-plane-flow/bin/cpflow generate-github-actions --staging-branch master |
145 | | -bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow |
| 20 | +bin/conductor-exec bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow |
146 | 21 | ``` |
147 | 22 |
|
148 | | -Why the explicit description check exists: GitHub parses expression-like snippets |
149 | | -inside composite action metadata, including `description:` fields. Literal |
150 | | -examples such as `${{ vars.SOME_VALUE }}` can fail action loading before any |
151 | | -shell step starts. The wrapper runs `cpflow github-flow-readiness`, parses the |
152 | | -generated YAML, checks action input descriptions for literal GitHub expressions, |
153 | | -checks that every generated wrapper keeps `uses:` and `control_plane_flow_ref` |
154 | | -on the same upstream ref across all `cpflow-*` wrappers, checks that any |
155 | | -secret-inheriting reusable workflow passes `control_plane_flow_ref`, and runs |
156 | | -`actionlint -ignore 'SC2129' .github/workflows/cpflow-*.yml`. |
157 | | - |
158 | | -## PR Checks |
| 23 | +## Testing An Upstream PR Downstream |
159 | 24 |
|
160 | | -Open a normal PR for the generated-file diff and wait for CI. The workflow PR |
161 | | -itself is useful for syntax and CI validation, but it does not fully prove |
162 | | -review-app deployment changes that live under `.github/actions/`. |
163 | | - |
164 | | -For top-level workflow edits, you can manually dispatch the PR branch workflow: |
| 25 | +Use an immutable upstream commit SHA, not a branch: |
165 | 26 |
|
166 | 27 | ```sh |
167 | | -gh workflow run cpflow-deploy-review-app.yml --ref <branch> -f pr_number=<pr-number> |
| 28 | +bin/pin-cpflow-github-ref <40-character-control-plane-flow-commit-sha> |
| 29 | +bin/conductor-exec bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow |
168 | 30 | ``` |
169 | 31 |
|
170 | | -This loads the workflow file from `<branch>`, but the deploy workflow's |
171 | | -`Checkout trusted workflow sources` step still checks out `master` before using |
172 | | -local composite actions with secrets. Treat this as a partial smoke test, not as |
173 | | -proof that PR-branch composite action changes work. |
174 | | - |
175 | | -## Post-Merge Review-App Test |
| 32 | +Leave `CPFLOW_VERSION` unset while testing a commit SHA. After the upstream gem |
| 33 | +and tag ship, repin wrappers to the release tag, such as `v5.0.1`. |
176 | 34 |
|
177 | | -After the workflow PR merges to `master`, test a real review-app deployment: |
| 35 | +## Review App Canary |
178 | 36 |
|
179 | | -1. Pick a same-repository PR to use as the canary. |
180 | | -2. If the review app does not exist yet, comment exactly `+review-app-deploy` on |
181 | | - that PR. |
182 | | -3. If a previous deploy run failed, rerun the failed deploy run after the |
183 | | - workflow PR is merged. |
184 | | -4. Confirm the deploy run checks out `master` at the merge commit in |
185 | | - `Checkout trusted workflow sources`. |
186 | | -5. Confirm `Setup environment` succeeds and prints the expected `cpflow` version. |
187 | | -6. Confirm `Check if review app exists`, `Build Docker image`, and |
188 | | - `Deploy to Control Plane` all run as expected. |
189 | | -7. Open the review-app URL from the PR comment or deployment status and verify |
190 | | - it returns HTTP 200. |
| 37 | +1. Open or reuse a same-repository PR. |
| 38 | +2. Comment exactly `+review-app-deploy`. |
| 39 | +3. Confirm the deploy job checks out the expected upstream Control Plane Flow |
| 40 | + source selected by the generated wrapper's `uses:` ref. |
| 41 | +4. Confirm `Setup environment`, `Check if review app exists`, |
| 42 | + `Build Docker image`, and `Deploy to Control Plane` all pass. |
| 43 | +5. Open the review-app URL from the PR comment and verify it returns HTTP 200. |
191 | 44 |
|
192 | | -Use the generated app name from the workflow log: |
| 45 | +Comment-triggered workflows run from the repository default branch. If you are |
| 46 | +testing edits to a workflow file before merging, manually dispatch the PR branch |
| 47 | +workflow: |
193 | 48 |
|
194 | | -```text |
195 | | -APP_NAME: ${REVIEW_APP_PREFIX}-${PR_NUMBER} |
| 49 | +```sh |
| 50 | +gh workflow run cpflow-deploy-review-app.yml --ref <branch> -f pr_number=<pr-number> |
196 | 51 | ``` |
197 | 52 |
|
198 | | -This is a template from the workflow output, not a literal command to evaluate |
199 | | -unless those environment variables are already set. For this repo, verify the |
200 | | -actual `REVIEW_APP_PREFIX` repository variable before assuming the final app |
201 | | -name. |
202 | | - |
203 | 53 | ## Troubleshooting Signals |
204 | 54 |
|
205 | | -### Composite action metadata fails before setup |
206 | | - |
207 | | -Error shape: |
208 | | - |
209 | | -```text |
210 | | -Unrecognized named-value: 'vars' |
211 | | -Failed to load ./.github/actions/cpflow-setup-environment/action.yml |
212 | | -``` |
213 | | - |
214 | | -Cause: GitHub parsed a literal expression inside composite action metadata, |
215 | | -usually an input description. Because trusted local actions come from `master`, |
216 | | -fix and merge the generated action metadata on `master`, then rerun the deploy. |
217 | | - |
218 | | -### Setup succeeds, then `cpflow exists` reports token format |
219 | | - |
220 | | -Error shape: |
| 55 | +### Token Format Error |
221 | 56 |
|
222 | 57 | ```text |
223 | 58 | ERROR: Unknown API token format. Please re-run 'cpln profile login' or set the correct CPLN_TOKEN env variable. |
224 | 59 | ``` |
225 | 60 |
|
226 | | -Cause: the workflow can read `CPLN_TOKEN_STAGING`, but the value is not a valid |
227 | | -Control Plane service-account token for the installed Control Plane CLI. Rotate |
228 | | -the GitHub secret, then rerun the failed deploy job. |
229 | | - |
230 | | -### PR pushes do not create a new review app |
| 61 | +The workflow can read `CPLN_TOKEN_STAGING`, but the secret value is not a valid |
| 62 | +Control Plane service-account token. Rotate the GitHub secret and rerun the |
| 63 | +deploy. |
231 | 64 |
|
232 | | -This is expected. Pushes redeploy only after the review app already exists. |
233 | | -Create the first review app by commenting exactly: |
| 65 | +### No Deploy After Push |
234 | 66 |
|
235 | | -```text |
236 | | -+review-app-deploy |
237 | | -``` |
| 67 | +Pushes redeploy only after the review app already exists. Create the first one |
| 68 | +with an exact `+review-app-deploy` PR comment. |
238 | 69 |
|
239 | | -## Ways To Make This Easier |
| 70 | +### No Visible Workflow Changes |
240 | 71 |
|
241 | | -- Extend `bin/pin-cpflow-github-ref` so it can also run |
242 | | - `bin/test-cpflow-github-flow`, open a downstream PR, and print or post the |
243 | | - exact `+review-app-deploy` command needed to start the canary deploy. |
244 | | -- Add CI coverage that runs `bin/test-cpflow-github-flow` on generated workflow |
245 | | - changes, so ref mismatches and action metadata parsing issues are caught |
246 | | - before review. |
247 | | -- Add a no-secret GitHub Actions smoke workflow that loads generated local |
248 | | - composite actions from the PR branch and fails fast on action metadata parsing. |
249 | | -- Extend `bin/test-cpflow-github-flow` as more local cpflow GitHub Actions |
250 | | - checks become worth standardizing. |
251 | | -- Add an early token sanity step after `Setup environment` so invalid |
252 | | - `CPLN_TOKEN_STAGING` and `CPLN_TOKEN_PRODUCTION` values fail with a named |
253 | | - "validate Control Plane token" step instead of surfacing later during |
254 | | - `cpflow exists`. |
255 | | -- Keep a tiny canary PR open for review-app workflow testing so post-merge |
256 | | - deploy verification does not depend on whichever feature PR happens to exist. |
257 | | -- Upstream the metadata-description check to `cpflow github-flow-readiness` so |
258 | | - downstream repos get the guard automatically. |
| 72 | +Comment-triggered runs use workflow files from `master`. For PR-branch workflow |
| 73 | +edits, use `workflow_dispatch` as shown above or merge first and test with a |
| 74 | +real review-app deploy. |
0 commit comments