Skip to content

Commit 2285c0a

Browse files
Test GitHub triggering review app deployments (#597)
* WIP * provision the appˆ * WIP * Updates for deployment * test error handling * Updates for deployment * chore: remove error test * refactor: rename job to deploy-to-control-plane-review * feat: trigger deploying to control-plane review on opening a PR * feat: change setup_app_templates: from gvc to app * refactor: delete unneeded code * fix: typo * fix: styling * feat: add a comment on opening PRs as an instruction for deploying review apps * feat: trigger review-app deployment on commenting "/deploy-review-app" * feat: Add Github confirmation comment upon starting to deploy * fix: deprecated cpflow option * feat: move confirmation comment to first thing in the review app workflow * feat: get correct checkout ref in issue_comment event * fix: typo * fix: coderabbit suggestions --------- Co-authored-by: Justin Gordon <[email protected]>
1 parent f2bb05f commit 2285c0a

File tree

11 files changed

+174
-42
lines changed

11 files changed

+174
-42
lines changed

.controlplane/controlplane.yml

+18-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ aliases:
1414
# Production apps will use a different org than staging for security.
1515
# Change this value to your org name
1616
# or set ENV CPLN_ORG to your org name as that will override whatever is used here for all cpflow commands
17-
# cpln_org: shakacode-open-source-examples
17+
cpln_org: shakacode-open-source-examples-staging
1818

1919
# Example apps use only location. CPLN offers the ability to use multiple locations.
2020
default_location: aws-us-east-2
@@ -34,6 +34,9 @@ aliases:
3434
# Configure the workload name used when maintenance mode is on (defaults to "maintenance").
3535
maintenance_workload: maintenance
3636

37+
# Configure the script to run when releasing an app., either with deploy-image or promote-app-from-upstream
38+
release_script: release_script.sh
39+
3740
apps:
3841
react-webpack-rails-tutorial:
3942
# Simulate Production Version
@@ -47,14 +50,24 @@ apps:
4750

4851
upstream: react-webpack-rails-tutorial-staging
4952

50-
release_script: release_script.sh
51-
5253
react-webpack-rails-tutorial-staging:
5354
<<: *common
5455
# QA Apps are like Heroku review apps, but the use `prefix` so you can run a commmand like
5556
# this to create a QA app for the tutorial app.
5657
# `cpflow setup gvc postgres redis rails -a qa-react-webpack-rails-tutorial-pr-1234`
5758
qa-react-webpack-rails-tutorial:
5859
<<: *common
59-
# Prefix is used to identify these "qa" apps.
60-
prefix: true
60+
# Order matters!
61+
setup_app_templates:
62+
# GVC template contains the identity
63+
- app
64+
65+
# Resources
66+
- postgres
67+
- redis
68+
69+
# Workloads, like Dynos types on Heroku
70+
- daily-task
71+
- rails
72+
# match_if_app_name_starts_with is used to identify these "qa" apps.
73+
match_if_app_name_starts_with: true

.controlplane/readme.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export APP_NAME=react-webpack-rails-tutorial
7474

7575
# Provision all infrastructure on Control Plane.
7676
# app react-webpack-rails-tutorial will be created per definition in .controlplane/controlplane.yml
77-
cpflow apply-template gvc postgres redis rails daily-task -a $APP_NAME
77+
cpflow setup-app -a $APP_NAME
7878

7979
# Build and push docker image to Control Plane repository
8080
# Note, may take many minutes. Be patient.

.controlplane/release_script.sh

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
11
#!/bin/bash -e
22

3-
echo 'Running release_script.sh per controlplane.yml'
43

5-
echo 'Run DB migrations'
6-
./bin/rails db:prepare
4+
log() {
5+
echo "[`date +%Y-%m-%d:%H:%M:%S`]: $1"
6+
}
77

8-
echo 'Completed release_script.sh per controlplane.yml'
8+
error_exit() {
9+
log "$1" 1>&2
10+
exit 1
11+
}
12+
13+
log 'Running release_script.sh per controlplane.yml'
14+
15+
if [ -x ./bin/rails ]; then
16+
log 'Run DB migrations'
17+
./bin/rails db:prepare || error_exit "Failed to run DB migrations"
18+
else
19+
error_exit "./bin/rails does not exist or is not executable"
20+
fi
21+
22+
log 'Completed release_script.sh per controlplane.yml'
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# Template setup of the GVC, roughly corresponding to a Heroku app
22
kind: gvc
3-
name: APP_GVC
3+
name: { { APP_NAME } }
44
spec:
55
# For using templates for test apps, put ENV values here, stored in git repo.
66
# Production apps will have values configured manually after app creation.
77
env:
88
- name: DATABASE_URL
9-
# Password does not matter because host postgres.APP_GVC.cpln.local can only be accessed
9+
# Password does not matter because host postgres.{{APP_NAME}}.cpln.local can only be accessed
1010
# locally within CPLN GVC, and postgres running on a CPLN workload is something only for a
1111
# test app that lacks persistence.
12-
value: 'postgres://the_user:the_password@postgres.APP_GVC.cpln.local:5432/APP_GVC'
12+
value: 'postgres://the_user:the_password@postgres.{{APP_NAME}}.cpln.local:5432/{{APP_NAME}}'
1313
- name: RAILS_ENV
1414
value: production
1515
- name: NODE_ENV
@@ -18,8 +18,13 @@ spec:
1818
value: 'true'
1919
- name: REDIS_URL
2020
# No password for GVC local Redis. See comment above for postgres.
21-
value: 'redis://redis.APP_GVC.cpln.local:6379'
21+
value: 'redis://redis.{{APP_NAME}}.cpln.local:6379'
2222
# Part of standard configuration
2323
staticPlacement:
2424
locationLinks:
25-
- /org/APP_ORG/location/APP_LOCATION
25+
- { { APP_LOCATION_LINK } }
26+
27+
---
28+
# Identity is needed to access secrets
29+
kind: identity
30+
name: { { APP_IDENTITY } }

.controlplane/templates/daily-task.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ spec:
2020
- rake
2121
- daily
2222
inheritEnv: true
23-
image: "/org/APP_ORG/image/APP_IMAGE"
23+
image: {{APP_IMAGE_LINK}}
2424
defaultOptions:
2525
autoscaling:
2626
minScale: 1
@@ -30,4 +30,5 @@ spec:
3030
external:
3131
outboundAllowCIDR:
3232
- 0.0.0.0/0
33-
identityLink: /org/APP_ORG/gvc/APP_GVC/identity/postgres-poc-identity
33+
# Identity is used for binding workload to secrets
34+
identityLink: {{APP_IDENTITY_LINK}}

.controlplane/templates/org.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Org level secrets are used to store sensitive information that is
2+
# shared across multiple apps in the same organization. This is
3+
# useful for storing things like API keys, database credentials, and
4+
# other sensitive information that is shared across multiple apps
5+
# in the same organization.
6+
7+
# This is how you apply this once (not during CI)
8+
# cpl apply-template secrets -a qa-react-webpack-rails-tutorial --org shakacode-open-source-examples-staging
9+
10+
kind: secret
11+
name: {{APP_SECRETS}}
12+
type: dictionary
13+
data:
14+
SOME_ENV: "123456"
15+
16+
---
17+
18+
# Policy is needed to allow identities to access secrets
19+
kind: policy
20+
name: {{APP_SECRETS_POLICY}}
21+
targetKind: secret
22+
targetLinks:
23+
- //secret/{{APP_SECRETS}}

.controlplane/templates/postgres.yml

+1-4
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ bindings:
106106
# - use
107107
# - view
108108
principalLinks:
109-
- //gvc/APP_GVC/identity/postgres-poc-identity
109+
- //gvc/{{APP_NAME}}/identity/postgres-poc-identity
110110
targetKind: secret
111111
targetLinks:
112112
- //secret/postgres-poc-credentials
@@ -139,9 +139,6 @@ spec:
139139
args:
140140
- "-c"
141141
- "cat /usr/local/bin/cpln-entrypoint.sh >> ./cpln-entrypoint.sh && chmod u+x ./cpln-entrypoint.sh && ./cpln-entrypoint.sh postgres"
142-
#command: "cpln-entrypoint.sh"
143-
#args:
144-
# - "postgres"
145142
ports:
146143
- number: 5432
147144
protocol: tcp

.controlplane/templates/rails.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ spec:
1414
value: debug
1515
# Inherit other ENV values from GVC
1616
inheritEnv: true
17-
image: '/org/APP_ORG/image/APP_IMAGE'
17+
image: {{APP_IMAGE_LINK}}
1818
# 512 corresponds to a standard 1x dyno type
1919
memory: 512Mi
2020
ports:
@@ -34,3 +34,5 @@ spec:
3434
# Could configure outbound for more security
3535
outboundAllowCIDR:
3636
- 0.0.0.0/0
37+
# Identity is used for binding workload to secrets
38+
identityLink: {{APP_IDENTITY_LINK}}

.github/actions/deploy-to-control-plane/action.yml

+16-15
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ name: Deploy-To-Control-Plane
44
description: 'Deploys both to staging and to review apps'
55

66
inputs:
7-
# The name of the app to deploy
87
app_name:
98
description: 'The name of the app to deploy'
109
required: true
@@ -20,25 +19,25 @@ runs:
2019
- name: Set up Ruby
2120
uses: ruby/setup-ruby@v1
2221
with:
23-
ruby-version: '3.2' # Specify your Ruby version here
22+
ruby-version: '3.3.3' # Specify your Ruby version here
2423

2524
- name: Install Control Plane CLI
2625
shell: bash
2726
run: |
2827
sudo npm install -g @controlplane/[email protected]
2928
cpln --version
3029
gem install cpflow -v 4.0.0
30+
cpflow --version
3131
3232
- name: Set Short SHA
3333
id: vars
3434
shell: bash
3535
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
3636

37-
- name: cpflow profile
37+
- name: cpln profile
3838
shell: bash
3939
run: |
4040
cpln profile update default
41-
# cpln profile update default --token ${CPLN_TOKEN}
4241
4342
# Caching step
4443
- uses: actions/cache@v2
@@ -49,22 +48,24 @@ runs:
4948
${{ runner.os }}-docker-${{ hashFiles('**/Dockerfile', '**/package.json', '**/yarn.lock') }}
5049
${{ runner.os }}-docker-
5150
51+
- name: cpflow setup-app
52+
shell: bash
53+
run: |
54+
if ! cpflow exists -a ${{ inputs.app_name }} ; then
55+
cpflow setup-app -a ${{ inputs.app_name }}
56+
fi
57+
# Provision all infrastructure on Control Plane.
58+
# app react-webpack-rails-tutorial will be created per definition in .controlplane/controlplane.yml
5259
- name: cpflow build-image
5360
shell: bash
5461
run: |
5562
cpln image docker-login
63+
# Use BUILDKIT_PROGRESS=plain to get more verbose logging of the build
64+
# BUILDKIT_PROGRESS=plain cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}}
5665
cpflow build-image -a ${{ inputs.app_name }} --commit ${{steps.vars.outputs.sha_short}} --org ${{inputs.org}}
57-
# --cache /tmp/.docker-cache
58-
59-
- name: Run release script
60-
shell: bash
61-
run: |
62-
# Run database migrations (or other release tasks) with the latest image,
63-
# while the app is still running on the previous image.
64-
# This is analogous to the release phase.
65-
cpflow run './.controlplane/release_script.sh' -a ${{ inputs.app_name }} --image latest
66-
66+
# --cache /tmp/.docker-cache
6767
- name: Deploy to Control Plane
6868
shell: bash
6969
run: |
70-
cpflow deploy-image -a ${{ inputs.app_name }} --org ${{inputs.org}}
70+
echo "Deploying to Control Plane"
71+
cpflow deploy-image -a ${{ inputs.app_name }} --run-release-phase --org ${{inputs.org}} --verbose
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Add helper Comment on PR creation
2+
3+
on:
4+
pull_request:
5+
types: [opened]
6+
7+
jobs:
8+
comment-on-pr:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Add GitHub Comment for review app instructions
12+
uses: actions/github-script@v6
13+
with:
14+
script: |
15+
github.rest.issues.createComment({
16+
issue_number: context.issue.number,
17+
owner: context.repo.owner,
18+
repo: context.repo.repo,
19+
body: "Hi 👋 To deploy a review app, please comment `/deploy-review-app`"
20+
})

.github/workflows/deploy-to-control-plane-review.yml

+61-5
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,80 @@ name: Deploy Review App to Control Plane
66
on:
77
# Allows you to run this workflow manually from the Actions tab
88
workflow_dispatch:
9+
10+
# Uncomment these lines to trigger the workflow on pull request events
11+
# pull_request:
12+
# branches:
13+
# - master
14+
15+
# deploy on comment "/deploy-review-app"
916
issue_comment:
1017
types: [created, edited]
1118

1219
# Convert the GitHub secret variables to environment variables for use by the Control Plane CLI
1320
env:
1421
CPLN_ORG: ${{secrets.CPLN_ORG_STAGING}}
1522
CPLN_TOKEN: ${{secrets.CPLN_TOKEN_STAGING}}
23+
# Uncomment this line to use the PR number from the pull requests trigger event (that trigger is commented)
24+
# PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
25+
PR_NUMBER: ${{ github.event.issue.number }}
1626

1727
jobs:
18-
deploy-to-control-plane-staging:
28+
deploy-to-control-plane-review:
1929
if: ${{ github.event_name != 'issue_comment' || (github.event.comment.body == '/deploy-review-app' && github.event.issue.pull_request) }}
2030
runs-on: ubuntu-latest
2131

2232
steps:
23-
- name: Check out the repo
24-
uses: actions/checkout@v2
33+
- name: Get PR HEAD Ref
34+
if: ${{ github.event_name == 'issue_comment' }}
35+
id: getRef
36+
run: echo "PR_REF=$(gh pr view \"$PR_NUMBER\" --repo \"${{ github.repository }}\" --json headRefName | jq -r '.headRefName')" >> $GITHUB_OUTPUT
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
40+
- name: Checkout source code from Github
41+
uses: actions/checkout@v4
42+
with:
43+
fetch-depth: 0
44+
ref: ${{ steps.getRef.outputs.PR_REF || github.ref }}
45+
46+
- name: Add GitHub Comment
47+
if: ${{ github.event_name == 'issue_comment' }}
48+
uses: actions/github-script@v6
49+
with:
50+
script: |
51+
github.rest.issues.createComment({
52+
issue_number: context.issue.number,
53+
owner: context.repo.owner,
54+
repo: context.repo.repo,
55+
body: "We started working on your review-app deployment. You can track progress in the "Actions" Tab [here](https://github.com/shakacode/react-webpack-rails-tutorial/actions/workflows/deploy-to-control-plane-review.yml) on Github."
56+
})
2557
58+
- name: Get PR number
59+
if: ${{ github.event_name != 'issue_comment' }}
60+
run: |
61+
echo "GITHUB_REPOSITORY: \"$GITHUB_REPOSITORY\""
62+
if [ -z "$PR_NUMBER" ]; then
63+
echo "PR_NUMBER is not in the trigger event. Fetching PR number from open PRs."
64+
REF="${{ github.ref }}"
65+
REF=${REF#refs/heads/} # Remove 'refs/heads/' prefix
66+
echo "REF: \"$REF\""
67+
API_RESPONSE=$(curl --location --request GET "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls?state=open" \
68+
--header 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}')
69+
PR_NUMBER=$(echo "$API_RESPONSE" | jq '.[] | select(.head.ref=="'$REF'") | .number')
70+
fi
71+
echo "PR_NUMBER: $PR_NUMBER"
72+
if [ -z "$PR_NUMBER" ]; then
73+
echo "PR_NUMBER is not set. Aborting."
74+
exit 1
75+
fi
76+
echo "PR_NUMBER=\"$PR_NUMBER\"" >> $GITHUB_ENV
77+
- name: Get App Name
78+
run: |
79+
echo "PR_NUMBER: ${{ env.PR_NUMBER }}"
80+
echo "APP_NAME=qa-react-webpack-rails-tutorial-pr-${{ env.PR_NUMBER }}" >> "$GITHUB_ENV"
81+
echo "App Name: ${{ env.APP_NAME }}"
2682
- uses: ./.github/actions/deploy-to-control-plane
2783
with:
28-
app_name: qa-react-webpack-rails-tutorial-pr-${{ github.event.pull_request.number }}
29-
org: ${{ secrets.CPLN_ORG_STAGING }}
84+
app_name: ${{ env.APP_NAME }}
85+
org: ${{ env.CPLN_ORG }}

0 commit comments

Comments
 (0)