Skip to content

Commit 99e7155

Browse files
committed
Refresh cpflow flow from latest PR 278
1 parent adf6902 commit 99e7155

16 files changed

Lines changed: 233 additions & 153 deletions

File tree

.controlplane/shakacode-team.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ Optional repository settings:
5353
- `CPLN_CLI_VERSION`: pin a specific `@controlplane/cli` version; defaults to the generated action pin.
5454
- `CPFLOW_VERSION`: pin a specific cpflow gem version; defaults to the generated action pin.
5555
- `HEALTH_CHECK_ACCEPTED_STATUSES`: production promotion health statuses; defaults to `200 301 302`.
56+
- `HEALTH_CHECK_RETRIES` / `HEALTH_CHECK_INTERVAL`: production health polling controls; defaults to `24` retries and `15` seconds.
57+
- `ROLLBACK_READINESS_RETRIES` / `ROLLBACK_READINESS_INTERVAL`: post-rollback health polling controls; defaults to `24` retries and `15` seconds.
5658

5759
If staging moves off `master`, update both `STAGING_APP_BRANCH` and the branch
5860
filter in `.github/workflows/cpflow-deploy-staging.yml`.

.github/actions/cpflow-build-docker-image/action.yml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ runs:
7474
7575
PR_INFO=""
7676
docker_build_args=()
77+
ssh_agent_started=false
78+
79+
cleanup_build_ssh() {
80+
if [[ "${ssh_agent_started}" == "true" ]]; then
81+
ssh-agent -k >/dev/null || true
82+
fi
83+
rm -f "${HOME}/.ssh/cpflow_build_key"
84+
}
85+
trap cleanup_build_ssh EXIT
7786
7887
if [[ -n "${PR_NUMBER}" ]]; then
7988
PR_INFO=" for PR #${PR_NUMBER}"
@@ -96,7 +105,7 @@ runs:
96105
97106
if [[ -f "${HOME}/.ssh/cpflow_build_key" ]]; then
98107
eval "$(ssh-agent -s)"
99-
trap 'ssh-agent -k >/dev/null; rm -f "${HOME}/.ssh/cpflow_build_key"' EXIT
108+
ssh_agent_started=true
100109
ssh-add "${HOME}/.ssh/cpflow_build_key"
101110
docker_build_args+=("--ssh=default")
102111
fi
@@ -105,10 +114,9 @@ runs:
105114
cpflow build-image -a "${APP_NAME}" --commit="${COMMIT_SHA}" --org="${CONTROL_PLANE_ORG}" "${docker_build_args[@]}"
106115
echo "✅ Docker image build successful${PR_INFO} (commit ${COMMIT_SHA})"
107116
108-
- name: Cleanup Docker build SSH key
117+
- name: Remove SSH key
109118
if: ${{ always() }}
110119
shell: bash
111120
run: |
112-
# Defence in depth: the build step also traps EXIT, but this still runs
113-
# if a future refactor exits before that trap is installed.
121+
# Defence in depth for cancellations or future refactors around the build trap.
114122
rm -f "${HOME}/.ssh/cpflow_build_key"

.github/actions/cpflow-delete-control-plane-app/check-app-exists.sh

Lines changed: 0 additions & 41 deletions
This file was deleted.

.github/actions/cpflow-delete-control-plane-app/delete-app.sh

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,42 @@ if [[ "$APP_NAME" != "${expected_prefix}"* ]]; then
1414
exit 1
1515
fi
1616

17+
# Guard against a misconfigured REVIEW_APP_PREFIX that would otherwise match
18+
# a well-known shared environment.
19+
if echo "$APP_NAME" | grep -iqE '(^|-)(production|staging)(-|$)'; then
20+
echo "❌ ERROR: refusing to delete an app whose name contains 'production' or 'staging'" >&2
21+
echo "App name: $APP_NAME" >&2
22+
exit 1
23+
fi
24+
1725
echo "🔍 Checking if application exists: $APP_NAME"
18-
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19-
if bash "${script_dir}/check-app-exists.sh"; then
20-
:
21-
else
22-
exists_status=$?
23-
if [[ "$exists_status" -ne 1 ]]; then
26+
exists_output=""
27+
set +e
28+
exists_output="$(cpflow exists -a "$APP_NAME" --org "$CPLN_ORG" 2>&1)"
29+
exists_status=$?
30+
set -e
31+
32+
case "$exists_status" in
33+
0)
34+
;;
35+
2)
36+
if [[ -n "$exists_output" ]]; then
37+
printf '%s\n' "$exists_output"
38+
fi
39+
echo "⚠️ Application does not exist: $APP_NAME"
40+
exit 0
41+
;;
42+
*)
43+
echo "❌ ERROR: failed to determine whether application exists: $APP_NAME" >&2
44+
if [[ -n "$exists_output" ]]; then
45+
printf '%s\n' "$exists_output" >&2
46+
fi
2447
exit "$exists_status"
25-
fi
26-
echo "⚠️ Application does not exist: $APP_NAME"
27-
exit 0
48+
;;
49+
esac
50+
51+
if [[ -n "$exists_output" ]]; then
52+
printf '%s\n' "$exists_output"
2853
fi
2954

3055
echo "🗑️ Deleting application: $APP_NAME"

.github/actions/cpflow-detect-release-phase/action.yml

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Detect release phase support
22
description: >-
3-
Inspects the cpflow config for an app and emits `flag=--run-release-phase`
3+
Inspects .controlplane/controlplane.yml for an app and emits `flag=--run-release-phase`
44
when a `release_script:` is configured. Outputs an empty `flag` otherwise.
55
66
inputs:
@@ -24,15 +24,32 @@ runs:
2424
run: |
2525
set -euo pipefail
2626
27-
config_output=""
28-
if ! config_output="$(cpflow config -a "${APP_NAME}" 2>&1)"; then
29-
echo "Failed to read cpflow config for app '${APP_NAME}'" >&2
30-
printf '%s\n' "${config_output}" >&2
27+
release_script="$(ruby - "${APP_NAME}" <<'RUBY'
28+
require "yaml"
29+
30+
app_name = ARGV.fetch(0)
31+
data = YAML.load_file(".controlplane/controlplane.yml", aliases: true)
32+
apps = data["apps"] || {}
33+
app_config = apps[app_name]
34+
35+
unless app_config
36+
app_config = apps.find do |name, config|
37+
config.is_a?(Hash) &&
38+
config["match_if_app_name_starts_with"] &&
39+
app_name.start_with?(name)
40+
end&.last
41+
end
42+
43+
unless app_config.is_a?(Hash)
44+
warn "Error: app '#{app_name}' is not defined under `apps:` in `.controlplane/controlplane.yml`."
3145
exit 1
32-
fi
46+
end
47+
48+
puts app_config["release_script"].to_s
49+
RUBY
50+
)"
3351
34-
# Anchor to start-of-line so commented-out release_script: entries don't enable --run-release-phase.
35-
if grep -qE '^[[:space:]]*release_script:' <<< "${config_output}"; then
52+
if [[ -n "${release_script}" ]]; then
3653
echo "flag=--run-release-phase" >> "$GITHUB_OUTPUT"
3754
else
3855
echo "flag=" >> "$GITHUB_OUTPUT"

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

Lines changed: 8 additions & 12 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 a repository-variable-backed input 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 a repository-variable-backed input unconditionally.
26+
so callers can pass `${{ vars.CPFLOW_VERSION }}` unconditionally.
2727
required: false
2828
default: ""
2929

@@ -52,7 +52,12 @@ runs:
5252
CPLN_CLI_VERSION="${CPLN_CLI_VERSION:-${default_cpln_cli_version}}"
5353
CPFLOW_VERSION="${CPFLOW_VERSION:-${default_cpflow_version}}"
5454
55-
sudo npm install -g "@controlplane/cli@${CPLN_CLI_VERSION}"
55+
npm_global_prefix="${HOME}/.npm-global"
56+
mkdir -p "${npm_global_prefix}"
57+
echo "${npm_global_prefix}/bin" >> "$GITHUB_PATH"
58+
export PATH="${npm_global_prefix}/bin:${PATH}"
59+
60+
npm install --global --prefix "${npm_global_prefix}" "@controlplane/cli@${CPLN_CLI_VERSION}"
5661
cpln --version
5762
5863
gem install cpflow -v "${CPFLOW_VERSION}" --no-document
@@ -78,15 +83,6 @@ runs:
7883
exit 1
7984
fi
8085
81-
# Later workflow steps call cpflow/cpln, so persist the token without putting it on argv.
82-
# This intentionally gives subsequent trusted steps in the same job a CPLN_TOKEN env var.
83-
token_delimiter="CPLN_TOKEN_$(openssl rand -hex 8)"
84-
{
85-
echo "CPLN_TOKEN<<${token_delimiter}"
86-
printf '%s\n' "$CPLN_TOKEN"
87-
echo "${token_delimiter}"
88-
} >> "$GITHUB_ENV"
89-
9086
create_output=""
9187
if ! create_output="$(cpln profile create default --org "$ORG" 2>&1)"; then
9288
if ! echo "$create_output" | grep -qi "already exists"; then

.github/actions/cpflow-validate-config/action.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ runs:
3939
missing=()
4040
while IFS= read -r entry; do
4141
entry="${entry%$'\r'}"
42-
entry="$(printf '%s' "${entry}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
42+
entry="${entry#"${entry%%[![:space:]]*}"}"
43+
entry="${entry%"${entry##*[![:space:]]}"}"
4344
[[ -z "${entry}" ]] && continue
4445
4546
type="${entry%%:*}"
@@ -70,6 +71,5 @@ runs:
7071
exit 0
7172
fi
7273
73-
echo "Missing required GitHub configuration:" >&2
74-
printf -- '- %s\n' "${missing[@]}" >&2
74+
printf 'Missing required GitHub configuration:\n- %s\n' "${missing[@]}" >&2
7575
exit 1

.github/actions/cpflow-wait-for-health/action.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,14 @@ runs:
6161
for attempt in $(seq 1 "${CPFLOW_MAX_RETRIES}"); do
6262
echo "Health check attempt ${attempt}/${CPFLOW_MAX_RETRIES}"
6363
64-
if ! endpoint="$(cpln workload get "${CPFLOW_WORKLOAD_NAME}" --gvc "${CPFLOW_APP_NAME}" --org "${CPFLOW_ORG}" -o json | jq -r '.status.endpoint // empty')"; then
65-
echo "Unable to fetch workload endpoint; will retry if attempts remain."
66-
endpoint=""
64+
if ! workload_json="$(cpln workload get "${CPFLOW_WORKLOAD_NAME}" --gvc "${CPFLOW_APP_NAME}" --org "${CPFLOW_ORG}" -o json 2>&1)"; then
65+
echo "::error::Workload '${CPFLOW_WORKLOAD_NAME}' not found in GVC '${CPFLOW_APP_NAME}'. Set PRIMARY_WORKLOAD to the correct workload name." >&2
66+
printf '%s\n' "${workload_json}" >&2
67+
echo "healthy=false" >> "$GITHUB_OUTPUT"
68+
exit 1
6769
fi
70+
71+
endpoint="$(echo "${workload_json}" | jq -r '.status.endpoint // empty')"
6872
if [[ -n "${endpoint}" ]]; then
6973
http_status="$(curl -s -o /dev/null -w '%{http_code}' --max-time "${CPFLOW_CURL_MAX_TIME}" "${endpoint}" 2>/dev/null || echo 000)"
7074
echo "Endpoint: ${endpoint}, HTTP status: ${http_status}"
@@ -75,6 +79,8 @@ runs:
7579
exit 0
7680
fi
7781
done
82+
else
83+
echo "Workload '${CPFLOW_WORKLOAD_NAME}' has no endpoint yet; waiting for one to be assigned."
7884
fi
7985
8086
if [[ "${attempt}" -lt "${CPFLOW_MAX_RETRIES}" ]]; then

.github/cpflow-help.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
- Creates the review app if it does not exist
77
- Builds the PR commit image
88
- Deploys the image and comments with the review URL
9-
- The command must be the only text in the comment
9+
- The comment must contain exactly `/deploy-review-app` and no other text
1010

1111
`/delete-review-app`
1212
- Deletes the review app when the PR is done
1313
- This also runs automatically when the PR closes
14+
- The comment must contain exactly `/delete-review-app` and no other text
1415

1516
## Repository secrets
1617

@@ -34,6 +35,8 @@
3435
| `DOCKER_BUILD_EXTRA_ARGS` | optional | Newline-delimited extra docker build tokens (e.g. `--build-arg=FOO=bar`). |
3536
| `DOCKER_BUILD_SSH_KNOWN_HOSTS` | optional | SSH known_hosts entries when SSH build hosts are not GitHub.com. |
3637
| `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. |
3740
| `CPLN_CLI_VERSION` | optional | Pin a specific `@controlplane/cli` version; falls back to the action default when unset. |
3841
| `CPFLOW_VERSION` | optional | Pin a specific cpflow gem version; falls back to the generated default when unset. |
3942

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ jobs:
4646

4747
- name: Remove stale review apps
4848
env:
49-
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
5049
REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
50+
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
5151
shell: bash
5252
run: |
5353
set -euo pipefail

0 commit comments

Comments
 (0)