Skip to content

Commit 15cd558

Browse files
committed
Works with deployment
1 parent 005eab7 commit 15cd558

20 files changed

+742
-138
lines changed

.controlplane/Dockerfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
ARG RUBY_VERSION=3.3.4
33
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
44

5+
# Current commit hash environment variable
6+
ARG GIT_COMMIT
7+
ENV GIT_COMMIT_SHA=${GIT_COMMIT}
8+
59
# Install packages needed to build gems and node modules
610
RUN apt-get update -qq && \
711
apt-get install --no-install-recommends -y build-essential curl git libpq-dev libvips node-gyp pkg-config python-is-python3
@@ -76,7 +80,3 @@ ENTRYPOINT ["./.controlplane/entrypoint.sh"]
7680
# Default args to pass to the entry point that can be overridden
7781
# For Kubernetes and ControlPlane, these are the "workload args"
7882
CMD ["./bin/rails", "server"]
79-
80-
# Current commit hash environment variable
81-
ARG GIT_COMMIT_SHA
82-
ENV GIT_COMMIT_SHA=${GIT_COMMIT_SHA}

.controlplane/readme.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,32 @@ cpflow build-image -a $APP_NAME --commit ABCD
123123
### `entrypoint.sh`
124124
- waits for Postgres and Redis to be available
125125
- runs `rails db:prepare` to create/seed or migrate the database
126+
127+
## CI Automation, Review Apps and Staging
128+
129+
_Note, some of the URL references are internal for the ShakaCode team._
130+
131+
Review Apps (deployment of apps based on a PR) are done via Github Actions.
132+
133+
The review apps work by creating isolated deployments for each branch through this automated process. When a branch is pushed, the action:
134+
135+
1. Sets up the necessary environment and tools
136+
2. Creates a unique deployment for that branch if it doesn't exist
137+
3. Builds a Docker image tagged with the branch's commit SHA
138+
4. Deploys this image to Control Plane with its own isolated environment
139+
140+
This allows teams to:
141+
- Preview changes in a production-like environment
142+
- Test features independently
143+
- Share working versions with stakeholders
144+
- Validate changes before merging to main branches
145+
146+
The system uses Control Plane's infrastructure to manage these deployments, with each branch getting its own resources as defined in the controlplane.yml configuration.
147+
148+
149+
### Workflow for Developing Github Actions for Review Apps
150+
151+
1. Create a PR with changes to the Github Actions workflow
152+
2. Make edits to file such as `.github/actions/deploy-to-control-plane/action.yml`
153+
3. Run a script like `ga .github && gc -m fixes && gp` to commit and push changes (ga = git add, gc = git commit, gp = git push)
154+
4. Check the Github Actions tab in the PR to see the status of the workflow

.controlplane/shakacode-team.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Internal Notes to the Shakacode Team
2+
3+
## Links
4+
5+
- [Control Plane Org for Staging and Review Apps](https://console.cpln.io/console/org/shakacode-open-source-examples-staging/-info)
6+
- [Control Plane Org for Deployed App](https://console.cpln.io/console/org/shakacode-open-source-examples/-info)

.dockerignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ dump.rdb
1919
.DS_Store
2020

2121
# Ignore bundle dependencies
22-
vendor/ruby
22+
vendor/bundle
23+
24+
# Ignore GitHub Actions and workflows
25+
.github/
2326

2427
# RVM gemset
2528
.ruby-gemset
@@ -45,6 +48,5 @@ yarn-debug.log*
4548
###################################################
4649
# Specific to .dockerignore
4750
.git/
48-
.github/
4951
spec/
5052
scripts/
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Build Docker Image
2+
description: 'Builds a Docker image for the application'
3+
4+
inputs:
5+
app_name:
6+
description: 'Name of the application'
7+
required: true
8+
org:
9+
description: 'Organization name'
10+
required: true
11+
commit:
12+
description: 'Commit SHA to tag the image with'
13+
required: true
14+
PR_NUMBER:
15+
description: 'PR number'
16+
required: true
17+
18+
runs:
19+
using: "composite"
20+
steps:
21+
- name: Build Docker Image
22+
id: build
23+
shell: bash
24+
run: |
25+
echo "🏗️ Building Docker image for PR #${PR_NUMBER} (commit ${{ inputs.commit }})..."
26+
27+
if cpflow build-image -a "${{ inputs.app_name }}" --commit="${{ inputs.commit }}" --org="${{ inputs.org }}"; then
28+
echo "✅ Docker image build successful for PR #${PR_NUMBER} (commit ${{ inputs.commit }})"
29+
else
30+
echo "❌ Docker image build failed for PR #${PR_NUMBER} (commit ${{ inputs.commit }})"
31+
exit 1
32+
fi
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Delete Control Plane App
2+
description: 'Deletes a Control Plane application and all its resources'
3+
4+
inputs:
5+
app_name:
6+
description: 'Name of the application to delete'
7+
required: true
8+
org:
9+
description: 'Organization name'
10+
required: true
11+
12+
runs:
13+
using: "composite"
14+
steps:
15+
- name: Delete Application
16+
shell: bash
17+
run: ${{ github.action_path }}/../deploy-to-control-plane/scripts/delete-app.sh
18+
env:
19+
APP_NAME: ${{ inputs.app_name }}
20+
CPLN_ORG: ${{ inputs.org }}
Lines changed: 68 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,87 @@
11
# Control Plane GitHub Action
22

3-
name: Deploy-To-Control-Plane
4-
description: 'Deploys both to staging and to review apps'
3+
name: Deploy to Control Plane
4+
description: 'Deploys an application to Control Plane'
55

66
inputs:
77
app_name:
8-
description: 'The name of the app to deploy'
8+
description: 'Name of the application'
99
required: true
10-
default:
1110
org:
12-
description: 'The org of the app to deploy'
11+
description: 'Organization name'
1312
required: true
14-
default:
13+
github_token:
14+
description: 'GitHub token'
15+
required: true
16+
wait_timeout:
17+
description: 'Timeout in seconds for waiting for workloads to be ready'
18+
required: false
19+
default: 600
20+
21+
outputs:
22+
review_app_url:
23+
description: 'URL of the deployed application'
24+
value: ${{ steps.deploy.outputs.review_app_url }}
1525

1626
runs:
17-
using: 'composite'
27+
using: "composite"
1828
steps:
1929
- name: Setup Environment
2030
uses: ./.github/actions/setup-environment
2131

22-
- name: Set Short SHA
23-
id: vars
32+
- name: Get Commit SHA
33+
id: get_sha
2434
shell: bash
25-
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
26-
27-
# Caching step
28-
- uses: actions/cache@v2
29-
with:
30-
path: /tmp/.docker-cache
31-
key: ${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }}-${{ github.sha }}
32-
restore-keys: |
33-
${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }}
34-
${{ runner.os }}-docker-
35+
run: ${{ github.action_path }}/scripts/get-commit-sha.sh
36+
env:
37+
GITHUB_TOKEN: ${{ inputs.github_token }}
38+
PR_NUMBER: ${{ env.PR_NUMBER }}
3539

36-
- name: cpflow setup-app
37-
shell: bash
38-
run: |
39-
if ! cpflow exists -a ${{ inputs.app_name }} ; then
40-
cpflow setup-app -a ${{ inputs.app_name }}
41-
fi
42-
# Provision all infrastructure on Control Plane.
43-
# app react-webpack-rails-tutorial will be created per definition in .controlplane/controlplane.yml
44-
- name: cpflow build-image
45-
shell: bash
46-
run: |
47-
cpln image docker-login
48-
# Use BUILDKIT_PROGRESS=plain to get more verbose logging of the build
49-
# BUILDKIT_PROGRESS=plain cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}}
50-
cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}}
51-
# --cache /tmp/.docker-cache
5240
- name: Deploy to Control Plane
41+
id: deploy
5342
shell: bash
5443
run: |
55-
echo "Deploying to Control Plane"
56-
cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose
44+
echo "🚀 Deploying app for PR #${PR_NUMBER}..."
45+
46+
# Create temp file for output
47+
TEMP_OUTPUT=$(mktemp)
48+
trap 'rm -f "${TEMP_OUTPUT}"' EXIT
49+
50+
# Deploy the application and show output in real-time while capturing it
51+
if ! cpflow deploy-image -a "${{ inputs.app_name }}" --run-release-phase --org "${{ inputs.org }}" 2>&1 | tee "${TEMP_OUTPUT}"; then
52+
echo "❌ Deployment failed for PR #${PR_NUMBER}"
53+
echo "Error output:"
54+
cat "${TEMP_OUTPUT}"
55+
exit 1
56+
fi
57+
58+
# Extract app URL from captured output
59+
REVIEW_APP_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "${TEMP_OUTPUT}" | head -n1)
60+
if [ -z "${REVIEW_APP_URL}" ]; then
61+
echo "❌ Failed to get app URL from deployment output"
62+
echo "Deployment output:"
63+
cat "${TEMP_OUTPUT}"
64+
exit 1
65+
fi
66+
67+
# Wait for all workloads to be ready
68+
WAIT_TIMEOUT=${WAIT_TIMEOUT:-${{ inputs.wait_timeout }}}
69+
echo "⏳ Waiting for all workloads to be ready (timeout: ${WAIT_TIMEOUT}s)..."
70+
71+
# Use timeout command with ps:wait and show output in real-time
72+
if ! timeout "${WAIT_TIMEOUT}" bash -c "cpflow ps:wait -a \"${{ inputs.app_name }}\"" 2>&1 | tee -a "${TEMP_OUTPUT}"; then
73+
TIMEOUT_EXIT=$?
74+
if [ ${TIMEOUT_EXIT} -eq 124 ]; then
75+
echo "❌ Timed out waiting for workloads after ${WAIT_TIMEOUT} seconds"
76+
else
77+
echo "❌ Workloads did not become ready for PR #${PR_NUMBER} (exit code: ${TIMEOUT_EXIT})"
78+
fi
79+
echo "Full output:"
80+
cat "${TEMP_OUTPUT}"
81+
exit 1
82+
fi
83+
84+
echo "✅ Deployment successful for PR #${PR_NUMBER}"
85+
echo "🌐 App URL: ${REVIEW_APP_URL}"
86+
echo "review_app_url=${REVIEW_APP_URL}" >> $GITHUB_OUTPUT
87+
echo "REVIEW_APP_URL=${REVIEW_APP_URL}" >> $GITHUB_ENV
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/bash
2+
3+
# Script to delete a Control Plane application
4+
# Required environment variables:
5+
# - APP_NAME: Name of the application to delete
6+
# - CPLN_ORG: Organization name
7+
8+
set -e
9+
10+
# Validate required environment variables
11+
: "${APP_NAME:?APP_NAME environment variable is required}"
12+
: "${CPLN_ORG:?CPLN_ORG environment variable is required}"
13+
14+
# Safety check: prevent deletion of production or staging apps
15+
if echo "$APP_NAME" | grep -iqE '(production|staging)'; then
16+
echo "❌ ERROR: Cannot delete apps containing 'production' or 'staging' in their name" >&2
17+
echo "🛑 This is a safety measure to prevent accidental deletion of production or staging environments" >&2
18+
echo " App name: $APP_NAME" >&2
19+
exit 1
20+
fi
21+
22+
# Check if app exists before attempting to delete
23+
echo "🔍 Checking if application exists: $APP_NAME"
24+
if ! cpflow exists -a "$APP_NAME"; then
25+
echo "⚠️ Application does not exist: $APP_NAME"
26+
exit 0
27+
fi
28+
29+
# Delete the application
30+
echo "🗑️ Deleting application: $APP_NAME"
31+
if ! cpflow delete -a "$APP_NAME" --force; then
32+
echo "❌ Failed to delete application: $APP_NAME" >&2
33+
exit 1
34+
fi
35+
36+
echo "✅ Successfully deleted application: $APP_NAME"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/bin/bash
2+
3+
# This script handles the deployment to Control Plane and extracts the Rails URL
4+
#
5+
# Required environment variables:
6+
# - APP_NAME: Name of the application to deploy
7+
# - CPLN_ORG: Control Plane organization
8+
#
9+
# Outputs:
10+
# - rails_url: URL of the deployed Rails application
11+
12+
set -e
13+
14+
# Validate required environment variables
15+
: "${APP_NAME:?APP_NAME environment variable is required}"
16+
: "${CPLN_ORG:?CPLN_ORG environment variable is required}"
17+
18+
# Set deployment timeout (15 minutes)
19+
TIMEOUT=900
20+
21+
TEMP_OUTPUT=$(mktemp)
22+
trap 'rm -f "$TEMP_OUTPUT"' EXIT
23+
24+
# Deploy the application
25+
echo "🚀 Deploying to Control Plane..."
26+
if timeout "$TIMEOUT" cpflow deploy-image -a "$APP_NAME" --run-release-phase --org "$CPLN_ORG" --verbose | tee "$TEMP_OUTPUT"; then
27+
# Extract Rails URL from deployment output
28+
RAILS_URL=$(grep -oP 'https://rails-[^[:space:]]*\.cpln\.app(?=\s|$)' "$TEMP_OUTPUT" | head -n1)
29+
if [ -n "$RAILS_URL" ]; then
30+
echo "rails_url=$RAILS_URL" >> "$GITHUB_OUTPUT"
31+
echo "✅ Deployment successful"
32+
echo "🚀 Rails URL: $RAILS_URL"
33+
else
34+
echo "❌ Failed to extract Rails URL from deployment output"
35+
exit 1
36+
fi
37+
elif [ $? -eq 124 ]; then
38+
echo "❌ Deployment timed out after $TIMEOUT seconds"
39+
exit 1
40+
else
41+
echo "❌ Deployment to Control Plane failed"
42+
exit 1
43+
fi
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/bin/bash
2+
3+
# This script retrieves the commit SHA for deployment
4+
# It handles both PR and direct branch deployments
5+
#
6+
# Required environment variables:
7+
# - PR_NUMBER: Pull request number (optional)
8+
# - GITHUB_TOKEN: GitHub token for API access
9+
#
10+
# Outputs:
11+
# - sha: Full commit SHA
12+
# - sha_short: Short (7 char) commit SHA
13+
14+
set -e
15+
16+
if [ -n "${PR_NUMBER}" ]; then
17+
# If PR_NUMBER is set, get the PR's head SHA
18+
if ! PR_SHA=$(gh pr view "${PR_NUMBER}" --json headRefOid --jq '.headRefOid'); then
19+
echo "Failed to get PR head SHA" >&2
20+
exit 1
21+
fi
22+
echo "sha=${PR_SHA}" >> "$GITHUB_OUTPUT"
23+
echo "sha_short=${PR_SHA:0:7}" >> "$GITHUB_OUTPUT"
24+
echo "Using PR head commit SHA: ${PR_SHA:0:7}"
25+
else
26+
# For direct branch deployments, use the current commit SHA
27+
if ! CURRENT_SHA=$(git rev-parse HEAD); then
28+
echo "Failed to get current SHA" >&2
29+
exit 1
30+
fi
31+
echo "sha=${CURRENT_SHA}" >> "$GITHUB_OUTPUT"
32+
echo "sha_short=${CURRENT_SHA:0:7}" >> "$GITHUB_OUTPUT"
33+
echo "Using branch commit SHA: ${CURRENT_SHA:0:7}"
34+
fi

0 commit comments

Comments
 (0)