Skip to content

Commit bc55ffd

Browse files
authored
ci: improve deploy-pr workflow (#8735)
1 parent 3282908 commit bc55ffd

File tree

2 files changed

+161
-33
lines changed

2 files changed

+161
-33
lines changed

.github/workflows/pr-deploy.yaml

Lines changed: 129 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ on:
88
pr_number:
99
description: "PR number"
1010
required: true
11+
skip_build:
12+
description: "Skip build job"
13+
required: false
14+
default: false
1115

1216
env:
1317
REPO: ghcr.io/coder/coder-preview
@@ -62,6 +66,7 @@ jobs:
6266

6367
- name: Comment on PR
6468
id: comment_id
69+
if: github.event_name == 'issue_comment'
6570
uses: peter-evans/create-or-update-comment@v3
6671
with:
6772
issue-number: ${{ steps.pr_info.outputs.PR_NUMBER }}
@@ -72,6 +77,9 @@ jobs:
7277

7378
build:
7479
needs: pr_commented
80+
# Skips the build job if the workflow was triggered by a workflow_dispatch event and the skip_build input is set to true
81+
# or if the workflow was triggered by an issue_comment event and the comment body contains --skip-build
82+
if: (github.event_name == 'workflow_dispatch' && github.event.inputs.skip_build == 'false') || (github.event_name == 'issue_comment' && contains(github.event.comment.body, '--skip-build') != true)
7583
runs-on: ${{ github.repository_owner == 'coder' && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-latest' }}
7684
env:
7785
DOCKER_CLI_EXPERIMENTAL: "enabled"
@@ -119,16 +127,32 @@ jobs:
119127
120128
deploy:
121129
needs: [build, pr_commented]
122-
if: needs.build.result == 'success'
130+
# Run deploy job only if build job was successful or skipped
131+
if: always() && (needs.build.result == 'success' || needs.build.result == 'skipped')
123132
runs-on: "ubuntu-latest"
124133
env:
125134
CODER_IMAGE_TAG: ${{ needs.pr_commented.outputs.CODER_IMAGE_TAG }}
126135
PR_NUMBER: ${{ needs.pr_commented.outputs.PR_NUMBER }}
127136
PR_TITLE: ${{ needs.pr_commented.outputs.PR_TITLE }}
128137
PR_URL: ${{ needs.pr_commented.outputs.PR_URL }}
138+
PR_BRANCH: ${{ needs.pr_commented.outputs.PR_BRANCH }}
139+
PR_DEPLOYMENT_ACCESS_URL: "https://pr${{ needs.pr_commented.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
129140
steps:
141+
- name: Check if image exists
142+
run: |
143+
set -euxo pipefail
144+
foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o ${{ env.CODER_IMAGE_TAG }} | head -n 1)
145+
if [ -z "$foundTag" ]; then
146+
echo "Image not found"
147+
echo "${{ env.CODER_IMAGE_TAG }} not found in ghcr.io/coder/coder-preview"
148+
echo "Please remove --skip-build from the comment or ./scripts/deploy-pr.sh"
149+
exit 1
150+
fi
151+
130152
- name: Checkout
131153
uses: actions/checkout@v3
154+
with:
155+
ref: ${{ env.PR_BRANCH }}
132156

133157
- name: Set up kubeconfig
134158
run: |
@@ -157,6 +181,7 @@ jobs:
157181
spec:
158182
tls:
159183
- hosts:
184+
- "${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
160185
- "*.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
161186
secretName: pr${{ env.PR_NUMBER }}-tls
162187
rules:
@@ -173,32 +198,39 @@ jobs:
173198
EOF
174199
kubectl apply -f ingress.yaml
175200
201+
- name: Create values.yaml
202+
run: |
203+
cat <<EOF > pr-deploy-values.yaml
204+
coder:
205+
image:
206+
repo: ${{ env.REPO }}
207+
tag: pr${{ env.PR_NUMBER }}
208+
pullPolicy: Always
209+
service:
210+
type: ClusterIP
211+
env:
212+
- name: "CODER_ACCESS_URL"
213+
value: "https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
214+
- name: "CODER_WILDCARD_ACCESS_URL"
215+
value: "*--pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
216+
- name: "CODER_EXPERIMENTS"
217+
value: "*"
218+
- name: "CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS"
219+
value: "true"
220+
- name: "CODER_OAUTH2_GITHUB_CLIENT_ID"
221+
value: "${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_ID }}"
222+
- name: "CODER_OAUTH2_GITHUB_CLIENT_SECRET"
223+
value: "${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_SECRET }}"
224+
- name: "CODER_OAUTH2_GITHUB_ALLOWED_ORGS"
225+
value: "coder"
226+
EOF
227+
176228
- name: Install Helm chart
177229
run: |
178-
helm upgrade --install pr${{ env.PR_NUMBER }} ./helm \
230+
helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm \
179231
--namespace "pr${{ env.PR_NUMBER }}" \
180-
--set coder.image.repo=${{ env.REPO }} \
181-
--set coder.image.tag=pr${{ env.PR_NUMBER }} \
182-
--set coder.service.type=ClusterIP \
183-
--set coder.serviceAccount.enableDeployments=true \
184-
--set coder.env[0].name=CODER_ACCESS_URL \
185-
--set coder.env[0].value="https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" \
186-
--set coder.env[1].name=CODER_WILDCARD_ACCESS_URL \
187-
--set coder.env[1].value="*--pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}" \
188-
--set coder.env[2].name=CODER_EXPERIMENTS \
189-
--set coder.env[2].value="*" \
232+
--values ./pr-deploy-values.yaml \
190233
--force
191-
# Uncomment this when https://github.com/coder/coder/issues/8714 is resolved
192-
# --set coder.env[3].name=CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS \
193-
# --set coder.env[3].value=true \
194-
# --set coder.env[4].name=CODER_OAUTH2_GITHUB_CLIENT_ID \
195-
# --set coder.env[4].value=${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_ID }} \
196-
# --set coder.env[5].name=CODER_OAUTH2_GITHUB_CLIENT_SECRET \
197-
# --set coder.env[5].value=${{ secrets.PR_DEPLOYMENTS_GITHUB_OAUTH_CLIENT_SECRET }} \
198-
# --set coder.env[6].name=CODER_OAUTH2_GITHUB_ALLOWED_ORGS \
199-
# --set coder.env[6].value=coder \
200-
# --set coder.env[7].name=CODER_OAUTH2_GITHUB_REDIRECT_URI \
201-
# --set coder.env[7].value="https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}/gitauth/github/callback
202234
203235
- name: Install coder-logstream-kube
204236
run: |
@@ -207,28 +239,95 @@ jobs:
207239
--namespace "pr${{ env.PR_NUMBER }}" \
208240
--set url="https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
209241
242+
- name: Get Coder binary
243+
run: |
244+
set -euxo pipefail
245+
246+
DEST="${HOME}/coder"
247+
URL="${{ env.PR_DEPLOYMENT_ACCESS_URL }}/bin/coder-linux-amd64"
248+
249+
mkdir -p "$(dirname ${DEST})"
250+
251+
COUNT=0
252+
until $(curl --output /dev/null --silent --head --fail "$URL"); do
253+
printf '.'
254+
sleep 5
255+
COUNT=$((COUNT+1))
256+
if [ $COUNT -ge 60 ]; then
257+
echo "Timed out waiting for URL to be available"
258+
exit 1
259+
fi
260+
done
261+
262+
curl -fsSL "$URL" -o "${DEST}"
263+
chmod +x "${DEST}"
264+
"${DEST}" version
265+
266+
- name: Create first user, template and workspace
267+
id: setup_deployment
268+
run: |
269+
set -euxo pipefail
270+
271+
# Create first user
272+
273+
# create a masked random password 12 characters long
274+
password=$(openssl rand -base64 16 | tr -d "=+/" | cut -c1-12)
275+
276+
# add mask so that the password is not printed to the logs
277+
echo "::add-mask::$password"
278+
echo "password=$password" >> $GITHUB_OUTPUT
279+
280+
/home/runner/coder login \
281+
--first-user-username pr${{ env.PR_NUMBER }} \
282+
--first-user-email ${{ env.PR_NUMBER }}@coder.com \
283+
--first-user-password $password \
284+
--first-user-trial \
285+
--use-token-as-session \
286+
${{ env.PR_DEPLOYMENT_ACCESS_URL }}
287+
288+
# Create template
289+
/home/runner/coder templates init --id kubernetes && cd ./kubernetes/ && /home/runner/coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }}
290+
291+
# Create workspace
292+
cat <<EOF > workspace.yaml
293+
cpu: "2"
294+
memory: "4"
295+
home_disk_size: "2"
296+
EOF
297+
298+
/home/runner/coder create --template="kubernetes" pr${{ env.PR_NUMBER }} --rich-parameter-file ./workspace.yaml -y
299+
/home/runner/coder stop pr${{ env.PR_NUMBER }} -y
300+
210301
- name: Send Slack notification
211302
run: |
212303
curl -s -o /dev/null -X POST -H 'Content-type: application/json' \
213-
-d '{
214-
"pr_number": "'"${{ env.PR_NUMBER }}"'",
215-
"pr_url": "'"${{ env.PR_URL }}"'",
216-
"pr_title": "'"${{ env.PR_TITLE }}"'",
217-
"pr_access_url": "'"${{ env.PR_DEPLOYMENT_ACCESS_URL }}"'" }' ${{ secrets.PR_DEPLOYMENTS_SLACK_WEBHOOK }}
304+
-d \
305+
'{
306+
"pr_number": "'"${{ env.PR_NUMBER }}"'",
307+
"pr_url": "'"${{ env.PR_URL }}"'",
308+
"pr_title": "'"${{ env.PR_TITLE }}"'",
309+
"pr_access_url": "'"${{ env.PR_DEPLOYMENT_ACCESS_URL }}"'",
310+
"pr_username": "'"pr${{ env.PR_NUMBER }}"'",
311+
"pr_email": "'"${{ env.PR_NUMBER }}@coder.com"'",
312+
"pr_password": "'"${{ steps.setup_deployment.outputs.password }}"'",
313+
"pr_actor": "'"${{ github.actor }}"'"
314+
}' \
315+
${{ secrets.PR_DEPLOYMENTS_SLACK_WEBHOOK }}
218316
echo "Slack notification sent"
219-
env:
220-
PR_DEPLOYMENT_ACCESS_URL: "https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
221317
222318
- name: Find Comment
223319
uses: peter-evans/find-comment@v2
320+
if: github.event_name == 'issue_comment'
224321
id: fc
225322
with:
226323
issue-number: ${{ env.PR_NUMBER }}
227324
comment-author: "github-actions[bot]"
228325
body-includes: This deployment will be deleted when the PR is closed
326+
direction: last
229327

230328
- name: Comment on PR
231329
uses: peter-evans/create-or-update-comment@v3
330+
if: github.event_name == 'issue_comment'
232331
with:
233332
issue-number: ${{ env.PR_NUMBER }}
234333
edit-mode: replace
@@ -238,6 +337,3 @@ jobs:
238337
:rocket: Access the deployment link [here](${{ env.PR_DEPLOYMENT_ACCESS_URL }}).
239338
:warning: This deployment will be deleted when the PR is closed.
240339
reactions: rocket
241-
242-
env:
243-
PR_DEPLOYMENT_ACCESS_URL: "https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"

scripts/deploy-pr.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env bash
2+
# Usage: ./deploy-pr.sh --skip-build
3+
# deploys the current branch to a PR environment and posts login credentials to
4+
# [#pr-deployments](https://codercom.slack.com/archives/C05DNE982E8) Slack channel
5+
# if --skip-build is passed, the build step will be skipped and the last build image will be used
6+
7+
set -euox pipefail
8+
9+
branchName=$(gh pr view --json headRefName | jq -r .headRefName)
10+
11+
if [[ "$branchName" == "main" ]]; then
12+
prNumber=$(git rev-parse --short HEAD)
13+
else
14+
prNumber=$(gh pr view --json number | jq -r .number)
15+
fi
16+
17+
# if --skip-build is passed, the build job will be skipped and the last built image will be used
18+
if [[ "$*" == *--skip-build* ]]; then
19+
skipBuild=true
20+
#check if the image exists
21+
foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o "$prNumber" | head -n 1)
22+
if [ -z "${foundTag}" ]; then
23+
echo "Image not found"
24+
echo "${prNumber} tag not found in ghcr.io/coder/coder-preview"
25+
echo "Please remove --skip-build and try again"
26+
exit 1
27+
fi
28+
else
29+
skipBuild=false
30+
fi
31+
32+
gh workflow run pr-deploy.yaml --ref "${branchName}" -f pr_number="${prNumber}" -f skip_build="${skipBuild}"

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy