Skip to content

Commit 7575e7b

Browse files
committed
Move generated GitHub Actions logic upstream
1 parent 02d92ad commit 7575e7b

30 files changed

Lines changed: 1897 additions & 1458 deletions

lib/github_flow_templates/.github/actions/cpflow-build-docker-image/action.yml renamed to .github/actions/cpflow-build-docker-image/action.yml

File renamed without changes.

lib/github_flow_templates/.github/actions/cpflow-delete-control-plane-app/action.yml renamed to .github/actions/cpflow-delete-control-plane-app/action.yml

File renamed without changes.

lib/github_flow_templates/.github/actions/cpflow-delete-control-plane-app/delete-app.sh renamed to .github/actions/cpflow-delete-control-plane-app/delete-app.sh

File renamed without changes.

lib/github_flow_templates/.github/actions/cpflow-detect-release-phase/action.yml renamed to .github/actions/cpflow-detect-release-phase/action.yml

File renamed without changes.

lib/github_flow_templates/.github/actions/cpflow-setup-environment/action.yml renamed to .github/actions/cpflow-setup-environment/action.yml

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: Setup Control Plane Environment
2-
description: Sets up Ruby, installs the Control Plane CLI and cpflow gem, and configures a default profile
2+
description: Sets up Ruby, installs the Control Plane CLI and cpflow, and configures a default profile
33

44
inputs:
55
token:
@@ -14,16 +14,26 @@ inputs:
1414
from .ruby-version, .tool-versions, or the Gemfile.
1515
required: false
1616
default: ""
17+
working_directory:
18+
description: Directory where ruby/setup-ruby should detect .ruby-version, .tool-versions, or the Gemfile.
19+
required: false
20+
default: "."
21+
# GitHub parses double-brace expression snippets inside action metadata (including
22+
# `description:`) while loading the composite action, and the `vars` context is not
23+
# available in that phase. Keep these descriptions in plain prose - reference repo
24+
# variables by NAME only, never with literal GitHub Actions expression syntax.
1725
cpln_cli_version:
1826
description: >-
19-
@controlplane/cli version. Empty string falls back to the action's pinned default
20-
so callers can pass `${{ vars.CPLN_CLI_VERSION }}` unconditionally.
27+
@controlplane/cli version. Empty string falls back to the action's pinned default,
28+
so callers can wire this input to the CPLN_CLI_VERSION repository variable
29+
unconditionally.
2130
required: false
2231
default: ""
2332
cpflow_version:
2433
description: >-
25-
cpflow gem version. Empty string falls back to the action's pinned default
26-
so callers can pass `${{ vars.CPFLOW_VERSION }}` unconditionally.
34+
cpflow gem version to install from RubyGems. Empty string installs cpflow from
35+
the checked-out control-plane-flow repository, so callers can test a GitHub ref
36+
without publishing a release.
2737
required: false
2838
default: ""
2939

@@ -41,23 +51,22 @@ runs:
4151
uses: ruby/setup-ruby@v1
4252
with:
4353
ruby-version: ${{ inputs.ruby_version }}
54+
working-directory: ${{ inputs.working_directory }}
4455

4556
- name: Install Control Plane CLI and cpflow gem
4657
shell: bash
4758
env:
4859
CPLN_CLI_VERSION: ${{ inputs.cpln_cli_version }}
4960
CPFLOW_VERSION: ${{ inputs.cpflow_version }}
61+
CPFLOW_SOURCE_DIR: ${{ github.action_path }}/../../..
5062
run: |
5163
set -euo pipefail
5264
53-
# Bump these defaults when a new release lands that you want to roll out by default.
54-
# Override per-repo by setting `CPLN_CLI_VERSION` / `CPFLOW_VERSION` repo variables;
55-
# an empty input falls back to the action's pinned default below.
56-
default_cpln_cli_version="3.3.1"
57-
default_cpflow_version="__CPFLOW_VERSION__"
65+
# Bump this default when a new Control Plane CLI release should roll out by default.
66+
# Override per-repo by setting the `CPLN_CLI_VERSION` repo variable.
67+
default_cpln_cli_version="3.10.2"
5868
5969
CPLN_CLI_VERSION="${CPLN_CLI_VERSION:-${default_cpln_cli_version}}"
60-
CPFLOW_VERSION="${CPFLOW_VERSION:-${default_cpflow_version}}"
6170
6271
npm_global_prefix="${HOME}/.npm-global"
6372
mkdir -p "${npm_global_prefix}"
@@ -67,7 +76,18 @@ runs:
6776
npm install --global --prefix "${npm_global_prefix}" "@controlplane/cli@${CPLN_CLI_VERSION}"
6877
cpln --version
6978
70-
gem install cpflow -v "${CPFLOW_VERSION}" --no-document
79+
if [[ -n "${CPFLOW_VERSION}" ]]; then
80+
gem install cpflow -v "${CPFLOW_VERSION}" --no-document
81+
else
82+
cpflow_source_dir="$(cd "${CPFLOW_SOURCE_DIR}" && pwd)"
83+
cpflow_gem="$(mktemp -t cpflow-XXXXXX.gem)"
84+
(
85+
cd "${cpflow_source_dir}"
86+
gem build cpflow.gemspec --output "${cpflow_gem}"
87+
)
88+
gem install "${cpflow_gem}" --no-document
89+
fi
90+
7191
cpflow --version
7292
7393
- name: Setup Control Plane profile and registry login
@@ -96,3 +116,12 @@ runs:
96116
# which would silently swallow a real failure if the wording ever changed.
97117
cpln profile update default --org "$ORG"
98118
cpln image docker-login --org "$ORG"
119+
120+
# Keep the token available to later cpflow/cpln steps without passing it
121+
# on the command line. GitHub masks secret values in logs, and the env file
122+
# itself is not echoed.
123+
{
124+
echo "CPLN_TOKEN<<__CPFLOW_CPLN_TOKEN__"
125+
echo "${CPLN_TOKEN}"
126+
echo "__CPFLOW_CPLN_TOKEN__"
127+
} >> "$GITHUB_ENV"

lib/github_flow_templates/.github/actions/cpflow-validate-config/action.yml renamed to .github/actions/cpflow-validate-config/action.yml

File renamed without changes.

lib/github_flow_templates/.github/actions/cpflow-wait-for-health/action.yml renamed to .github/actions/cpflow-wait-for-health/action.yml

File renamed without changes.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: Cleanup Stale Review Apps
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
control_plane_flow_ref:
7+
description: Git ref used to load shared cpflow composite actions.
8+
required: false
9+
type: string
10+
default: main
11+
12+
permissions:
13+
contents: read
14+
15+
concurrency:
16+
# Single global group: only one cleanup sweep at a time. Independent of review-app
17+
# deploy/delete groups (different keys), so cleanup will not block per-PR work.
18+
group: cpflow-cleanup-stale-review-apps
19+
# A cancelled `cpflow cleanup-stale-apps` can leave half-deleted review apps; let
20+
# the in-flight run finish before the next scheduled tick begins.
21+
cancel-in-progress: false
22+
23+
jobs:
24+
cleanup:
25+
runs-on: ubuntu-latest
26+
timeout-minutes: 30
27+
steps:
28+
- name: Checkout control-plane-flow actions
29+
uses: actions/checkout@v6
30+
with:
31+
repository: shakacode/control-plane-flow
32+
ref: ${{ inputs.control_plane_flow_ref }}
33+
path: .cpflow
34+
persist-credentials: false
35+
36+
- name: Validate required secrets and variables
37+
uses: ./.cpflow/.github/actions/cpflow-validate-config
38+
env:
39+
CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
40+
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
41+
REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
42+
with:
43+
required: |
44+
secret:CPLN_TOKEN_STAGING
45+
variable:CPLN_ORG_STAGING
46+
variable:REVIEW_APP_PREFIX
47+
48+
- name: Setup environment
49+
uses: ./.cpflow/.github/actions/cpflow-setup-environment
50+
with:
51+
token: ${{ secrets.CPLN_TOKEN_STAGING }}
52+
org: ${{ vars.CPLN_ORG_STAGING }}
53+
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
54+
cpflow_version: ${{ vars.CPFLOW_VERSION }}
55+
56+
- name: Remove stale review apps
57+
env:
58+
REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
59+
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
60+
shell: bash
61+
run: |
62+
set -euo pipefail
63+
cpflow cleanup-stale-apps -a "${REVIEW_APP_PREFIX}" --org "${CPLN_ORG_STAGING}" --yes
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
name: Delete Review App
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
control_plane_flow_ref:
7+
description: Git ref used to load shared cpflow composite actions.
8+
required: false
9+
type: string
10+
default: main
11+
12+
permissions:
13+
contents: read
14+
issues: write
15+
pull-requests: write
16+
17+
concurrency:
18+
group: cpflow-delete-review-app-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
19+
# Deletions must not cancel each other mid-flight — a cancelled `cpln` delete can leave
20+
# partial state behind. Let the in-progress deletion finish before the next run starts.
21+
cancel-in-progress: false
22+
23+
env:
24+
APP_NAME: ${{ vars.REVIEW_APP_PREFIX }}-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
25+
CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }}
26+
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
27+
28+
jobs:
29+
delete-review-app:
30+
if: |
31+
(github.event_name == 'issue_comment' &&
32+
github.event.issue.pull_request &&
33+
contains(fromJson('["+review-app-delete","+review-app-delete\n","+review-app-delete\r\n"]'), github.event.comment.body) &&
34+
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
35+
(github.event_name == 'pull_request_target' && github.event.action == 'closed') ||
36+
github.event_name == 'workflow_dispatch'
37+
runs-on: ubuntu-latest
38+
timeout-minutes: 15
39+
40+
steps:
41+
- name: React to delete command
42+
if: github.event_name == 'issue_comment'
43+
continue-on-error: true
44+
uses: actions/github-script@v8
45+
with:
46+
script: |
47+
try {
48+
await github.rest.reactions.createForIssueComment({
49+
owner: context.repo.owner,
50+
repo: context.repo.repo,
51+
comment_id: context.payload.comment.id,
52+
content: "eyes"
53+
});
54+
} catch (error) {
55+
if (error.status === 422) {
56+
core.info("Delete command reaction already exists.");
57+
} else {
58+
throw error;
59+
}
60+
}
61+
62+
- name: Checkout control-plane-flow actions
63+
uses: actions/checkout@v6
64+
with:
65+
repository: shakacode/control-plane-flow
66+
ref: ${{ inputs.control_plane_flow_ref }}
67+
path: .cpflow
68+
persist-credentials: false
69+
70+
- name: Validate required secrets and variables
71+
id: config
72+
uses: ./.cpflow/.github/actions/cpflow-validate-config
73+
env:
74+
CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
75+
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
76+
REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
77+
with:
78+
required: |
79+
secret:CPLN_TOKEN_STAGING
80+
variable:CPLN_ORG_STAGING
81+
variable:REVIEW_APP_PREFIX
82+
pull_request_friendly: "true"
83+
84+
- name: Setup environment
85+
if: steps.config.outputs.ready == 'true'
86+
uses: ./.cpflow/.github/actions/cpflow-setup-environment
87+
with:
88+
token: ${{ secrets.CPLN_TOKEN_STAGING }}
89+
org: ${{ vars.CPLN_ORG_STAGING }}
90+
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
91+
cpflow_version: ${{ vars.CPFLOW_VERSION }}
92+
93+
- name: Set workflow links
94+
if: steps.config.outputs.ready == 'true'
95+
uses: actions/github-script@v8
96+
with:
97+
script: |
98+
const workflowUrl = `${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
99+
core.exportVariable("WORKFLOW_URL", workflowUrl);
100+
core.exportVariable(
101+
"CONSOLE_URL",
102+
`https://console.cpln.io/console/org/${process.env.CPLN_ORG}/-info`
103+
);
104+
105+
- name: Create initial PR comment
106+
if: steps.config.outputs.ready == 'true'
107+
id: create-comment
108+
uses: actions/github-script@v8
109+
with:
110+
script: |
111+
const body = [
112+
"## 🗑️ Deleting review app...",
113+
"",
114+
`_Removing the review app for PR #${process.env.PR_NUMBER}_`
115+
].join("\n");
116+
117+
const comment = await github.rest.issues.createComment({
118+
owner: context.repo.owner,
119+
repo: context.repo.repo,
120+
issue_number: Number(process.env.PR_NUMBER),
121+
body
122+
});
123+
core.setOutput("comment-id", comment.data.id);
124+
125+
- name: Delete review app
126+
if: steps.config.outputs.ready == 'true'
127+
uses: ./.cpflow/.github/actions/cpflow-delete-control-plane-app
128+
with:
129+
app_name: ${{ env.APP_NAME }}
130+
cpln_org: ${{ vars.CPLN_ORG_STAGING }}
131+
review_app_prefix: ${{ vars.REVIEW_APP_PREFIX }}
132+
133+
# Finalizer still runs after delete failures, but only after config validation
134+
# created the initial PR comment and workflow link env vars it updates.
135+
- name: Finalize delete status
136+
if: always() && steps.config.outputs.ready == 'true'
137+
uses: actions/github-script@v8
138+
env:
139+
COMMENT_ID: ${{ steps.create-comment.outputs.comment-id }}
140+
JOB_STATUS: ${{ job.status }}
141+
with:
142+
script: |
143+
const commentId = Number(process.env.COMMENT_ID);
144+
const success = process.env.JOB_STATUS === "success";
145+
const body = success
146+
? [
147+
"## ✅ Review App Deleted",
148+
"",
149+
`_Review app for PR #${process.env.PR_NUMBER} is deleted_`,
150+
"",
151+
`🎮 [Control Plane Console](${process.env.CONSOLE_URL})`,
152+
`📋 [View Workflow Logs](${process.env.WORKFLOW_URL})`
153+
].join("\n")
154+
: [
155+
"## ❌ Failed to Delete Review App",
156+
"",
157+
`_Failed to delete review app for PR #${process.env.PR_NUMBER}_`,
158+
"",
159+
`🎮 [Control Plane Console](${process.env.CONSOLE_URL})`,
160+
`📋 [View Workflow Logs](${process.env.WORKFLOW_URL})`
161+
].join("\n");
162+
163+
if (!Number.isFinite(commentId) || commentId <= 0) {
164+
core.warning("Skipping delete status comment update because no comment id was created.");
165+
return;
166+
}
167+
168+
await github.rest.issues.updateComment({
169+
owner: context.repo.owner,
170+
repo: context.repo.repo,
171+
comment_id: commentId,
172+
body
173+
});

0 commit comments

Comments
 (0)