Skip to content

Commit a5bb67e

Browse files
committed
Merge remote-tracking branch 'origin/main' into jg-conductor/victoria-v6
* origin/main: Fix deploy-image showing container names instead of workload names (#255) (#294) Re-enable RuboCop NewCops and fix violations (#300) [codex] Fix stale app cleanup for image-less GVCs (#310) Handle non-zero exit from cpln workload exec gracefully (#301) Document Thruster HTTP/2 proxy configuration for Rails apps (#292) Friendly error in cpflow-detect-release-phase when controlplane.yml missing (#299) Document downstream cpflow testing (#308) Fix review app delete project checkout (#307) Fallback Ruby setup when no version file exists Move generated GitHub Actions logic upstream Animate review app command feedback (#304) Use Node 24 GitHub action versions (#303) Relax thor dependency to ~> 1.3 for Rails 8 solid_queue compatibility (#264) (#291)
2 parents 8d83dfd + 21c0310 commit a5bb67e

74 files changed

Lines changed: 3355 additions & 1565 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ inputs:
1111
review_app_prefix:
1212
description: Prefix used for review app names
1313
required: true
14+
working_directory:
15+
description: Directory containing the downstream project's .controlplane/controlplane.yml
16+
required: false
17+
default: "."
1418

1519
runs:
1620
using: composite
1721
steps:
1822
- name: Delete application
1923
shell: bash
24+
working-directory: ${{ inputs.working_directory }}
2025
run: ${{ github.action_path }}/delete-app.sh
2126
env:
2227
APP_NAME: ${{ inputs.app_name }}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ runs:
3434
require "yaml"
3535
3636
app_name = ARGV.fetch(0)
37+
38+
unless File.file?(".controlplane/controlplane.yml")
39+
warn "Error: `.controlplane/controlplane.yml` is missing. " \
40+
"cpflow-detect-release-phase must be invoked from a cpflow-configured project."
41+
exit 1
42+
end
43+
3744
data = YAML.safe_load(File.read(".controlplane/controlplane.yml"), aliases: true)
3845
apps = data["apps"] || {}
3946
app_config = apps[app_name]
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
name: Setup Control Plane Environment
2+
description: Sets up Ruby, installs the Control Plane CLI and cpflow, and configures a default profile
3+
4+
inputs:
5+
token:
6+
description: Control Plane token
7+
required: true
8+
org:
9+
description: Control Plane organization
10+
required: true
11+
ruby_version:
12+
description: >-
13+
Ruby version used for cpflow. When empty (the default), ruby/setup-ruby
14+
auto-detects from .ruby-version, .tool-versions, mise.toml, or a Gemfile
15+
ruby directive, then falls back to the action's pinned default.
16+
required: false
17+
default: ""
18+
working_directory:
19+
description: Directory where ruby/setup-ruby should detect Ruby version files.
20+
required: false
21+
default: "."
22+
# GitHub parses double-brace expression snippets inside action metadata (including
23+
# `description:`) while loading the composite action, and the `vars` context is not
24+
# available in that phase. Keep these descriptions in plain prose - reference repo
25+
# variables by NAME only, never with literal GitHub Actions expression syntax.
26+
cpln_cli_version:
27+
description: >-
28+
@controlplane/cli version. Empty string falls back to the action's pinned default,
29+
so callers can wire this input to the CPLN_CLI_VERSION repository variable
30+
unconditionally.
31+
required: false
32+
default: ""
33+
cpflow_version:
34+
description: >-
35+
cpflow gem version to install from RubyGems. Empty string installs cpflow from
36+
the checked-out control-plane-flow repository, so callers can test a GitHub ref
37+
without publishing a release.
38+
required: false
39+
default: ""
40+
41+
runs:
42+
using: composite
43+
# ruby/setup-ruby tracks Ruby/toolcache updates on a major tag. The privileged
44+
# reusable workflows pin GitHub-owned actions to immutable SHAs.
45+
steps:
46+
- name: Resolve Ruby setup version
47+
id: ruby-version
48+
shell: bash
49+
env:
50+
INPUT_RUBY_VERSION: ${{ inputs.ruby_version }}
51+
INPUT_WORKING_DIRECTORY: ${{ inputs.working_directory }}
52+
run: |
53+
set -euo pipefail
54+
55+
ruby_version="${INPUT_RUBY_VERSION}"
56+
working_directory="${INPUT_WORKING_DIRECTORY:-.}"
57+
# Bump when the project's minimum-supported Ruby advances.
58+
default_ruby_version="3.2"
59+
60+
if [[ -z "${ruby_version}" ]]; then
61+
if [[ -f "${working_directory}/.ruby-version" ]] ||
62+
{ [[ -f "${working_directory}/.tool-versions" ]] && grep -Eq "^[[:space:]]*ruby[[:space:]]+" "${working_directory}/.tool-versions"; } ||
63+
{ [[ -f "${working_directory}/mise.toml" ]] && grep -Eq "^[[:space:]]*ruby[[:space:]]*=" "${working_directory}/mise.toml"; } ||
64+
{ [[ -f "${working_directory}/.mise.toml" ]] && grep -Eq "^[[:space:]]*ruby[[:space:]]*=" "${working_directory}/.mise.toml"; }; then
65+
: # keep empty; ruby/setup-ruby will auto-detect
66+
elif [[ -f "${working_directory}/Gemfile" ]] && grep -Eq "^[[:space:]]*ruby[[:space:]]*(\(|file:|['\"])" "${working_directory}/Gemfile"; then
67+
: # keep empty; ruby/setup-ruby will read Gemfile
68+
else
69+
ruby_version="${default_ruby_version}"
70+
fi
71+
fi
72+
73+
echo "ruby_version=${ruby_version}" >> "$GITHUB_OUTPUT"
74+
75+
- name: Set up Ruby
76+
# ruby/setup-ruby intentionally tracks the v1 tag so Ruby/toolcache updates
77+
# roll out automatically; Dependabot/Renovate can manage this non-GitHub action.
78+
uses: ruby/setup-ruby@v1
79+
with:
80+
ruby-version: ${{ steps.ruby-version.outputs.ruby_version }}
81+
working-directory: ${{ inputs.working_directory }}
82+
83+
- name: Install Control Plane CLI and cpflow gem
84+
shell: bash
85+
env:
86+
CPLN_CLI_VERSION: ${{ inputs.cpln_cli_version }}
87+
CPFLOW_VERSION: ${{ inputs.cpflow_version }}
88+
CPFLOW_SOURCE_DIR: ${{ github.action_path }}/../../..
89+
run: |
90+
set -euo pipefail
91+
92+
# Bump this default when a new Control Plane CLI release should roll out by default.
93+
# Override per-repo by setting the `CPLN_CLI_VERSION` repo variable.
94+
default_cpln_cli_version="3.10.2"
95+
96+
CPLN_CLI_VERSION="${CPLN_CLI_VERSION:-${default_cpln_cli_version}}"
97+
98+
npm_global_prefix="${HOME}/.npm-global"
99+
mkdir -p "${npm_global_prefix}"
100+
echo "${npm_global_prefix}/bin" >> "$GITHUB_PATH"
101+
export PATH="${npm_global_prefix}/bin:${PATH}"
102+
103+
npm install --global --prefix "${npm_global_prefix}" "@controlplane/cli@${CPLN_CLI_VERSION}"
104+
cpln --version
105+
106+
if [[ -n "${CPFLOW_VERSION}" ]]; then
107+
gem install cpflow -v "${CPFLOW_VERSION}" --no-document
108+
else
109+
cpflow_source_dir="$(cd "${CPFLOW_SOURCE_DIR}" && pwd)"
110+
if [[ ! -f "${cpflow_source_dir}/cpflow.gemspec" ]]; then
111+
echo "::error::CPFLOW_SOURCE_DIR (${cpflow_source_dir}) does not contain cpflow.gemspec" >&2
112+
exit 1
113+
fi
114+
115+
cpflow_gem="$(mktemp -t cpflow-XXXXXX.gem)"
116+
trap 'rm -f "${cpflow_gem}"' EXIT
117+
(
118+
cd "${cpflow_source_dir}"
119+
gem build cpflow.gemspec --output "${cpflow_gem}"
120+
)
121+
gem install "${cpflow_gem}" --no-document
122+
fi
123+
124+
cpflow --version
125+
126+
- name: Setup Control Plane profile and registry login
127+
shell: bash
128+
env:
129+
# Pass the token via CPLN_TOKEN so cpln picks it up from the environment
130+
# rather than `--token`, which would leak it into /proc/<pid>/cmdline and ps output.
131+
CPLN_TOKEN: ${{ inputs.token }}
132+
ORG: ${{ inputs.org }}
133+
run: |
134+
set -euo pipefail
135+
136+
if [[ -z "$CPLN_TOKEN" ]]; then
137+
echo "Error: Control Plane token not provided" >&2
138+
exit 1
139+
fi
140+
141+
if [[ -z "$ORG" ]]; then
142+
echo "Error: Control Plane organization not provided" >&2
143+
exit 1
144+
fi
145+
146+
# `cpln profile update` lists `create` as an alias (cpln profile --help) and is
147+
# idempotent: it creates the profile if missing and updates it otherwise. Calling
148+
# update directly avoids parsing the CLI's "already exists" English error text,
149+
# which would silently swallow a real failure if the wording ever changed.
150+
cpln profile update default --org "$ORG"
151+
cpln image docker-login --org "$ORG"
152+
153+
# Keep the token available to later cpflow/cpln steps without passing it
154+
# on the command line. GitHub masks secret values in logs, and the env file
155+
# itself is not echoed.
156+
delim="CPLN_TOKEN_DELIM_$(openssl rand -hex 8)"
157+
{
158+
echo "CPLN_TOKEN<<${delim}"
159+
echo "${CPLN_TOKEN}"
160+
echo "${delim}"
161+
} >> "$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: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd
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+
working_directory: .cpflow
54+
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
55+
cpflow_version: ${{ vars.CPFLOW_VERSION }}
56+
57+
- name: Checkout caller repository
58+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
59+
with:
60+
persist-credentials: false
61+
62+
- name: Remove stale review apps
63+
env:
64+
REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
65+
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
66+
shell: bash
67+
run: |
68+
set -euo pipefail
69+
cpflow cleanup-stale-apps -a "${REVIEW_APP_PREFIX}" --org "${CPLN_ORG_STAGING}" --yes

0 commit comments

Comments
 (0)