Skip to content

Commit f0478ed

Browse files
committed
add auto deploy
1 parent 27fe2f4 commit f0478ed

File tree

1 file changed

+92
-44
lines changed

1 file changed

+92
-44
lines changed

.github/workflows/pr-deploy.yaml

Lines changed: 92 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
# This action will trigger when a PR is commented on with `/deploy-pr` or when the workflow is manually triggered.
1+
# This action will trigger when
2+
# 1. A PR is commented on with `/deploy-pr`
3+
# 2. when the workflow is manually triggered
4+
# 3. ./scripts/deploy_pr.sh is run locally
5+
# 4. when a PR is updated
26
name: Deploy PR
37
on:
48
issue_comment:
5-
types: [created, edited]
9+
types: created
10+
pull_request:
11+
types: synchronize
612
workflow_dispatch:
713
inputs:
814
pr_number:
@@ -33,7 +39,7 @@ concurrency:
3339
cancel-in-progress: true
3440

3541
jobs:
36-
pr_commented:
42+
get_info:
3743
if: (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/deploy-pr') && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR' || github.event.comment.author_association == 'OWNER')) || github.event_name == 'workflow_dispatch'
3844
outputs:
3945
PR_NUMBER: ${{ steps.pr_info.outputs.PR_NUMBER }}
@@ -42,18 +48,15 @@ jobs:
4248
PR_BRANCH: ${{ steps.pr_info.outputs.PR_BRANCH }}
4349
CODER_BASE_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_BASE_IMAGE_TAG }}
4450
CODER_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_IMAGE_TAG }}
51+
NEW: ${{ steps.check_deployment.outputs.new }}
4552

4653
runs-on: "ubuntu-latest"
4754
steps:
4855
- name: Get PR number, title, and branch name
4956
id: pr_info
5057
run: |
5158
set -euxo pipefail
52-
if [[ ${{ github.event_name }} == "workflow_dispatch" ]]; then
53-
PR_NUMBER=${{ github.event.inputs.pr_number }}
54-
else
55-
PR_NUMBER=${{ github.event.issue.number }}
56-
fi
59+
PR_NUMBER=${{ github.event.inputs.pr_number || github.event.pull_request.number || github.event.issue.number }}
5760
PR_TITLE=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.title')
5861
PR_BRANCH=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.head.ref')
5962
echo "PR_URL=https://github.com/coder/coder/pull/$PR_NUMBER" >> $GITHUB_OUTPUT
@@ -71,28 +74,52 @@ jobs:
7174
CODER_BASE_IMAGE_TAG: ghcr.io/coder/coder-preview-base:pr${{ steps.pr_info.outputs.PR_NUMBER }}
7275
CODER_IMAGE_TAG: ghcr.io/coder/coder-preview:pr${{ steps.pr_info.outputs.PR_NUMBER }}
7376

77+
- name: Set up kubeconfig
78+
run: |
79+
set -euxo pipefail
80+
mkdir -p ~/.kube
81+
echo "${{ secrets.PR_DEPLOYMENTS_KUBECONFIG }}" > ~/.kube/config
82+
export KUBECONFIG=~/.kube/config
83+
84+
- name: Check if the helm deployment already exists
85+
id: check_deployment
86+
run: |
87+
set -euxo pipefail
88+
if helm status "pr${{ steps.pr_info.outputs.PR_NUMBER }}" --namespace "pr${{ steps.pr_info.outputs.PR_NUMBER }}" > /dev/null 2>&1; then
89+
echo "Deployment already exists. Skipping deployment."
90+
new=false
91+
else
92+
echo "Deployment doesn't exist. Creating a new one."
93+
new=true
94+
fi
95+
echo "new=$new" >> $GITHUB_OUTPUT
96+
7497
- name: Comment on PR
7598
id: comment_id
7699
if: github.event_name == 'issue_comment'
77100
uses: peter-evans/create-or-update-comment@v3
78101
with:
79102
issue-number: ${{ steps.pr_info.outputs.PR_NUMBER }}
80103
body: |
104+
---
81105
:rocket: Deploying PR ${{ steps.pr_info.outputs.PR_NUMBER }} ...
82-
:warning: This deployment will be deleted when the PR is closed.
83-
reactions: "+1"
106+
---
84107
85108
build:
86-
needs: pr_commented
109+
needs: get_info
87110
# Skips the build job if the workflow was triggered by a workflow_dispatch event and the skip_build input is set to true
88111
# or if the workflow was triggered by an issue_comment event and the comment body contains --skip-build
89-
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)
112+
# alwyas run the build job if the workflow was triggered by a pull_request event
113+
if: |
114+
(github.event_name == 'workflow_dispatch' && github.event.inputs.skip_build == 'false') ||
115+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '--skip-build') == false) ||
116+
(github.event_name == 'pull_request' && needs.get_info.outputs.NEW == 'false')
90117
runs-on: ${{ github.repository_owner == 'coder' && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-latest' }}
91118
env:
92119
DOCKER_CLI_EXPERIMENTAL: "enabled"
93-
CODER_IMAGE_TAG: ${{ needs.pr_commented.outputs.CODER_IMAGE_TAG }}
94-
PR_NUMBER: ${{ needs.pr_commented.outputs.PR_NUMBER }}
95-
PR_BRANCH: ${{ needs.pr_commented.outputs.PR_BRANCH }}
120+
CODER_IMAGE_TAG: ${{ needs.get_info.outputs.CODER_IMAGE_TAG }}
121+
PR_NUMBER: ${{ needs.get_info.outputs.PR_NUMBER }}
122+
PR_BRANCH: ${{ needs.get_info.outputs.PR_BRANCH }}
96123
steps:
97124
- name: Checkout
98125
uses: actions/checkout@v3
@@ -133,19 +160,27 @@ jobs:
133160
build/coder_linux_amd64
134161
135162
deploy:
136-
needs: [build, pr_commented]
163+
needs: [build, get_info]
137164
# Run deploy job only if build job was successful or skipped
138-
if: always() && (needs.build.result == 'success' || needs.build.result == 'skipped') && needs.pr_commented.result == 'success'
165+
if: always() && (needs.build.result == 'success' || needs.build.result == 'skipped') && needs.get_info.result == 'success'
139166
runs-on: "ubuntu-latest"
140167
env:
141-
CODER_IMAGE_TAG: ${{ needs.pr_commented.outputs.CODER_IMAGE_TAG }}
142-
PR_NUMBER: ${{ needs.pr_commented.outputs.PR_NUMBER }}
143-
PR_TITLE: ${{ needs.pr_commented.outputs.PR_TITLE }}
144-
PR_URL: ${{ needs.pr_commented.outputs.PR_URL }}
145-
PR_BRANCH: ${{ needs.pr_commented.outputs.PR_BRANCH }}
146-
PR_DEPLOYMENT_ACCESS_URL: "pr${{ needs.pr_commented.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
168+
CODER_IMAGE_TAG: ${{ needs.get_info.outputs.CODER_IMAGE_TAG }}
169+
PR_NUMBER: ${{ needs.get_info.outputs.PR_NUMBER }}
170+
PR_TITLE: ${{ needs.get_info.outputs.PR_TITLE }}
171+
PR_URL: ${{ needs.get_info.outputs.PR_URL }}
172+
PR_BRANCH: ${{ needs.get_info.outputs.PR_BRANCH }}
173+
PR_DEPLOYMENT_ACCESS_URL: "pr${{ needs.get_info.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
147174
steps:
175+
- name: Set up kubeconfig
176+
run: |
177+
set -euxo pipefail
178+
mkdir -p ~/.kube
179+
echo "${{ secrets.PR_DEPLOYMENTS_KUBECONFIG }}" > ~/.kube/config
180+
export KUBECONFIG=~/.kube/config
181+
148182
- name: Check if image exists
183+
if: needs.get_info.outputs.NEW == 'true'
149184
run: |
150185
set -euxo pipefail
151186
foundTag=$(curl -fsSL https://github.com/coder/coder/pkgs/container/coder-preview | grep -o ${{ env.CODER_IMAGE_TAG }} | head -n 1)
@@ -157,34 +192,28 @@ jobs:
157192
fi
158193
159194
- name: Add DNS record to Cloudflare
195+
if: needs.get_info.outputs.NEW == 'true'
160196
run: |
161-
(
162-
curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \
163-
-H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \
164-
-H "Content-Type:application/json" \
165-
--data '{"type":"CNAME","name":"*.${{ env.PR_DEPLOYMENT_ACCESS_URL }}","content":"${{ env.PR_DEPLOYMENT_ACCESS_URL }}","ttl":1,"proxied":false}'
166-
)
197+
curl -X POST "https://api.cloudflare.com/client/v4/zones/${{ secrets.PR_DEPLOYMENTS_ZONE_ID }}/dns_records" \
198+
-H "Authorization: Bearer ${{ secrets.PR_DEPLOYMENTS_CLOUDFLARE_API_TOKEN }}" \
199+
-H "Content-Type:application/json" \
200+
--data '{"type":"CNAME","name":"*.${{ env.PR_DEPLOYMENT_ACCESS_URL }}","content":"${{ env.PR_DEPLOYMENT_ACCESS_URL }}","ttl":1,"proxied":false}'
167201
168202
- name: Checkout
169203
uses: actions/checkout@v3
170204
with:
171205
ref: ${{ env.PR_BRANCH }}
172206

173-
- name: Set up kubeconfig
174-
run: |
175-
set -euxo pipefail
176-
mkdir -p ~/.kube
177-
echo "${{ secrets.PR_DEPLOYMENTS_KUBECONFIG }}" > ~/.kube/config
178-
export KUBECONFIG=~/.kube/config
179-
180207
- name: Create PR namespace
208+
if: needs.get_info.outputs.NEW == 'true'
181209
run: |
182210
set -euxo pipefail
183211
# try to delete the namespace, but don't fail if it doesn't exist
184212
kubectl delete namespace "pr${{ env.PR_NUMBER }}" || true
185213
kubectl create namespace "pr${{ env.PR_NUMBER }}"
186214
187215
- name: Check and Create Certificate
216+
if: needs.get_info.outputs.NEW == 'true'
188217
run: |
189218
# Using kubectl to check if a Certificate resource already exists
190219
# we are doing this to avoid letsenrypt rate limits
@@ -216,6 +245,7 @@ jobs:
216245
)
217246
218247
- name: Set up PostgreSQL database
248+
if: needs.get_info.outputs.NEW == 'true'
219249
run: |
220250
helm repo add bitnami https://charts.bitnami.com/bitnami
221251
helm install coder-db bitnami/postgresql \
@@ -228,6 +258,7 @@ jobs:
228258
--from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable"
229259
230260
- name: Get experiments
261+
if: needs.get_info.outputs.NEW == 'true'
231262
id: get_experiments
232263
run: |
233264
set -euxo pipefail
@@ -249,6 +280,7 @@ jobs:
249280
COMMENT_BODY: ${{ github.event.comment.body || '' }}
250281

251282
- name: Create values.yaml
283+
if: needs.get_info.outputs.NEW == 'true'
252284
run: |
253285
cat <<EOF > pr-deploy-values.yaml
254286
coder:
@@ -291,19 +323,30 @@ jobs:
291323
292324
- name: Install Helm chart
293325
run: |
294-
helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm \
295-
--namespace "pr${{ env.PR_NUMBER }}" \
296-
--values ./pr-deploy-values.yaml \
297-
--force
326+
set -euxo pipefail
327+
# if the deployment already exists, we need to upgrade it by resuing the existing values
328+
if [[ ${{ needs.get_info.outputs.NEW }} == "false" ]]; then
329+
helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm \
330+
--namespace "pr${{ env.PR_NUMBER }}" \
331+
--reuse-values \
332+
--force
333+
else
334+
helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm \
335+
--namespace "pr${{ env.PR_NUMBER }}" \
336+
--values ./pr-deploy-values.yaml \
337+
--force
338+
fi
298339
299340
- name: Install coder-logstream-kube
341+
if: needs.get_info.outputs.NEW == 'true'
300342
run: |
301343
helm repo add coder-logstream-kube https://helm.coder.com/logstream-kube
302344
helm upgrade --install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \
303345
--namespace "pr${{ env.PR_NUMBER }}" \
304346
--set url="https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
305347
306348
- name: Get Coder binary
349+
if: needs.get_info.outputs.NEW == 'true'
307350
run: |
308351
set -euxo pipefail
309352
@@ -329,6 +372,7 @@ jobs:
329372
mv "${DEST}" /usr/local/bin/coder
330373
331374
- name: Create first user, template and workspace
375+
if: needs.get_info.outputs.NEW == 'true'
332376
id: setup_deployment
333377
run: |
334378
set -euxo pipefail
@@ -364,6 +408,7 @@ jobs:
364408
coder stop test -y
365409
366410
- name: Send Slack notification
411+
if: needs.get_info.outputs.NEW == 'true'
367412
run: |
368413
curl -s -o /dev/null -X POST -H 'Content-type: application/json' \
369414
-d \
@@ -387,18 +432,21 @@ jobs:
387432
with:
388433
issue-number: ${{ env.PR_NUMBER }}
389434
comment-author: "github-actions[bot]"
390-
body-includes: This deployment will be deleted when the PR is closed
435+
body-includes: ---
391436
direction: last
392437

393438
- name: Comment on PR
394439
uses: peter-evans/create-or-update-comment@v3
395440
if: github.event_name == 'issue_comment'
441+
env:
442+
STATUS: ${{ needs.get_info.outputs.NEW == 'true' && 'Created' || 'Updated' }}
396443
with:
397444
issue-number: ${{ env.PR_NUMBER }}
398445
edit-mode: replace
399446
comment-id: ${{ steps.fc.outputs.comment-id }}
400447
body: |
401-
:heavy_check_mark: Deployed PR ${{ env.PR_NUMBER }} successfully.
402-
:rocket: Access the deployment link [here](https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}).
403-
:warning: This deployment will be deleted when the PR is closed.
448+
---
449+
:heavy_check_mark: PR ${{ env.PR_NUMBER }} ${{ env.STATUS }} successfully.
450+
:rocket: Access the credentials [here]( {{ secrets.PR_DEPLOYMENTS_SLACK_CHANNEL_URL }} ).
451+
---
404452
reactions: rocket

0 commit comments

Comments
 (0)