Skip to content

Commit b76738c

Browse files
committed
Merge branch 'main' into role-sync-docs
2 parents a4a8f3d + 92798e9 commit b76738c

File tree

214 files changed

+8338
-2442
lines changed

Some content is hidden

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

214 files changed

+8338
-2442
lines changed

.github/workflows/pr-cleanup.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Cleanup PR
1+
name: Cleanup PR deployment and image
22
on:
33
pull_request:
44
types: [closed]

.github/workflows/pr-deploy.yaml

Lines changed: 191 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# This action will trigger when a PR is commentted containing /review-pr by a member of the org.
1+
# This action will trigger when a PR is commented on with `/deploy-pr` or when the workflow is manually triggered.
22
name: Deploy PR
33
on:
44
issue_comment:
@@ -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
@@ -25,29 +29,30 @@ jobs:
2529
pr_commented:
2630
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'
2731
outputs:
28-
PR_NUMBER: ${{ steps.pr_number.outputs.PR_NUMBER }}
29-
PR_TITLE: ${{ steps.pr_number.outputs.PR_TITLE }}
30-
PR_URL: ${{ steps.pr_number.outputs.PR_URL }}
31-
COMMENT_ID: ${{ steps.comment_id.outputs.comment-id }}
32+
PR_NUMBER: ${{ steps.pr_info.outputs.PR_NUMBER }}
33+
PR_TITLE: ${{ steps.pr_info.outputs.PR_TITLE }}
34+
PR_URL: ${{ steps.pr_info.outputs.PR_URL }}
35+
PR_BRANCH: ${{ steps.pr_info.outputs.PR_BRANCH }}
3236
CODER_BASE_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_BASE_IMAGE_TAG }}
3337
CODER_IMAGE_TAG: ${{ steps.set_tags.outputs.CODER_IMAGE_TAG }}
3438

3539
runs-on: "ubuntu-latest"
3640
steps:
37-
- name: Get PR number and title
38-
id: pr_number
41+
- name: Get PR number, title, and branch name
42+
id: pr_info
3943
run: |
4044
set -euxo pipefail
4145
if [[ ${{ github.event_name }} == "workflow_dispatch" ]]; then
4246
PR_NUMBER=${{ github.event.inputs.pr_number }}
43-
PR_TITLE=$(curl -sSL -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER" | jq -r '.title')
4447
else
4548
PR_NUMBER=${{ github.event.issue.number }}
46-
PR_TITLE='${{ github.event.issue.title }}'
4749
fi
50+
PR_TITLE=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.title')
51+
PR_BRANCH=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/coder/coder/pulls/$PR_NUMBER | jq -r '.head.ref')
4852
echo "PR_URL=https://github.com/coder/coder/pull/$PR_NUMBER" >> $GITHUB_OUTPUT
4953
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT
5054
echo "PR_TITLE=$PR_TITLE" >> $GITHUB_OUTPUT
55+
echo "PR_BRANCH=$PR_BRANCH" >> $GITHUB_OUTPUT
5156
5257
- name: Set required tags
5358
id: set_tags
@@ -56,39 +61,36 @@ jobs:
5661
echo "CODER_BASE_IMAGE_TAG=$CODER_BASE_IMAGE_TAG" >> $GITHUB_OUTPUT
5762
echo "CODER_IMAGE_TAG=$CODER_IMAGE_TAG" >> $GITHUB_OUTPUT
5863
env:
59-
CODER_BASE_IMAGE_TAG: ghcr.io/coder/coder-preview-base:pr${{ steps.pr_number.outputs.PR_NUMBER }}
60-
CODER_IMAGE_TAG: ghcr.io/coder/coder-preview:pr${{ steps.pr_number.outputs.PR_NUMBER }}
61-
62-
- name: Find Comment
63-
uses: peter-evans/find-comment@v2
64-
id: fc
65-
with:
66-
issue-number: ${{ steps.pr_number.outputs.PR_NUMBER }}
67-
comment-author: "github-actions[bot]"
68-
body-includes: This deployment will be deleted when the PR is closed
64+
CODER_BASE_IMAGE_TAG: ghcr.io/coder/coder-preview-base:pr${{ steps.pr_info.outputs.PR_NUMBER }}
65+
CODER_IMAGE_TAG: ghcr.io/coder/coder-preview:pr${{ steps.pr_info.outputs.PR_NUMBER }}
6966

7067
- name: Comment on PR
7168
id: comment_id
69+
if: github.event_name == 'issue_comment'
7270
uses: peter-evans/create-or-update-comment@v3
7371
with:
74-
comment-id: ${{ steps.fc.outputs.comment-id }}
75-
issue-number: ${{ steps.pr_number.outputs.PR_NUMBER }}
76-
edit-mode: replace
72+
issue-number: ${{ steps.pr_info.outputs.PR_NUMBER }}
7773
body: |
78-
:rocket: Deploying PR ${{ steps.pr_number.outputs.PR_NUMBER }} ...
74+
:rocket: Deploying PR ${{ steps.pr_info.outputs.PR_NUMBER }} ...
7975
:warning: This deployment will be deleted when the PR is closed.
76+
reactions: "+1"
8077

8178
build:
8279
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)
8383
runs-on: ${{ github.repository_owner == 'coder' && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-latest' }}
8484
env:
8585
DOCKER_CLI_EXPERIMENTAL: "enabled"
86-
CODER_IMAGE_TAG: ${{ needs.pr_commented.outputs.coder_image_tag }}
87-
PR_NUMBER: ${{ needs.pr_commented.outputs.pr_number }}
86+
CODER_IMAGE_TAG: ${{ needs.pr_commented.outputs.CODER_IMAGE_TAG }}
87+
PR_NUMBER: ${{ needs.pr_commented.outputs.PR_NUMBER }}
88+
PR_BRANCH: ${{ needs.pr_commented.outputs.PR_BRANCH }}
8889
steps:
8990
- name: Checkout
9091
uses: actions/checkout@v3
9192
with:
93+
ref: ${{ env.PR_BRANCH }}
9294
fetch-depth: 0
9395

9496
- name: Setup Node
@@ -125,22 +127,38 @@ jobs:
125127
126128
deploy:
127129
needs: [build, pr_commented]
128-
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') && needs.pr_commented.result == 'success'
129132
runs-on: "ubuntu-latest"
130133
env:
131134
CODER_IMAGE_TAG: ${{ needs.pr_commented.outputs.CODER_IMAGE_TAG }}
132135
PR_NUMBER: ${{ needs.pr_commented.outputs.PR_NUMBER }}
133136
PR_TITLE: ${{ needs.pr_commented.outputs.PR_TITLE }}
134137
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 }}"
135140
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+
136152
- name: Checkout
137153
uses: actions/checkout@v3
154+
with:
155+
ref: ${{ env.PR_BRANCH }}
138156

139157
- name: Set up kubeconfig
140158
run: |
141159
set -euxo pipefail
142160
mkdir -p ~/.kube
143-
echo "${{ secrets.DELIVERYBOT_KUBECONFIG }}" > ~/.kube/config
161+
echo "${{ secrets.PR_DEPLOYMENTS_KUBECONFIG }}" > ~/.kube/config
144162
export KUBECONFIG=~/.kube/config
145163
146164
- name: Create PR namespace
@@ -150,53 +168,172 @@ jobs:
150168
kubectl delete namespace "pr${{ env.PR_NUMBER }}" || true
151169
kubectl create namespace "pr${{ env.PR_NUMBER }}"
152170
171+
- name: Setup ingress
172+
run: |
173+
cat <<EOF > ingress.yaml
174+
apiVersion: networking.k8s.io/v1
175+
kind: Ingress
176+
metadata:
177+
name: pr${{ env.PR_NUMBER }}
178+
namespace: pr${{ env.PR_NUMBER }}
179+
annotations:
180+
cert-manager.io/cluster-issuer: letsencrypt
181+
spec:
182+
tls:
183+
- hosts:
184+
- "${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
185+
- "*.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
186+
secretName: pr${{ env.PR_NUMBER }}-tls
187+
rules:
188+
- host: "pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
189+
http:
190+
paths:
191+
- pathType: Prefix
192+
path: "/"
193+
backend:
194+
service:
195+
name: coder
196+
port:
197+
number: 80
198+
EOF
199+
kubectl apply -f ingress.yaml
200+
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+
153228
- name: Install Helm chart
154229
run: |
155-
helm upgrade --install pr${{ env.PR_NUMBER }} ./helm \
230+
helm upgrade --install "pr${{ env.PR_NUMBER }}" ./helm \
156231
--namespace "pr${{ env.PR_NUMBER }}" \
157-
--set coder.image.repo=${{ env.REPO }} \
158-
--set coder.image.tag=pr${{ env.PR_NUMBER }} \
159-
--set coder.service.type=ClusterIP \
160-
--set coder.serviceAccount.enableDeployments=true \
161-
--set coder.env[0].name=CODER_ACCESS_URL \
162-
--set coder.env[0].value="" \
232+
--values ./pr-deploy-values.yaml \
163233
--force
164234
165-
- name: Get deployment URL
166-
id: deployment_url
167-
run: |
168-
set -euo pipefail
169-
kubectl rollout status deployment/coder --namespace "pr${{ env.PR_NUMBER }}"
170-
POD_NAME=$(kubectl get pods -n "pr${{ env.PR_NUMBER }}" | awk 'NR==2{print $1}')
171-
CODER_ACCESS_URL=$(kubectl logs $POD_NAME -n "pr${{ env.PR_NUMBER }}" | grep "Web UI:" | awk -F ':' '{print $2":"$3}' | awk '{$1=$1};1')
172-
echo "::add-mask::$CODER_ACCESS_URL"
173-
echo "CODER_ACCESS_URL=$CODER_ACCESS_URL" >> $GITHUB_OUTPUT
174-
175235
- name: Install coder-logstream-kube
176236
run: |
177237
helm repo add coder-logstream-kube https://helm.coder.com/logstream-kube
178-
helm install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \
238+
helm upgrade --install coder-logstream-kube coder-logstream-kube/coder-logstream-kube \
179239
--namespace "pr${{ env.PR_NUMBER }}" \
180-
--set url="${{ steps.deployment_url.outputs.CODER_ACCESS_URL }}"
240+
--set url="https://pr${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
241+
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
181300
182301
- name: Send Slack notification
183302
run: |
184303
curl -s -o /dev/null -X POST -H 'Content-type: application/json' \
185-
-d '{
186-
"pr_number": "'"${{ env.PR_NUMBER }}"'",
187-
"pr_url": "'"${{ env.PR_URL }}"'",
188-
"pr_title": "'"${{ env.PR_TITLE }}"'",
189-
"pr_access_url": "'"${{ steps.deployment_url.outputs.CODER_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 }}
190316
echo "Slack notification sent"
191317
318+
- name: Find Comment
319+
uses: peter-evans/find-comment@v2
320+
if: github.event_name == 'issue_comment'
321+
id: fc
322+
with:
323+
issue-number: ${{ env.PR_NUMBER }}
324+
comment-author: "github-actions[bot]"
325+
body-includes: This deployment will be deleted when the PR is closed
326+
direction: last
327+
192328
- name: Comment on PR
193329
uses: peter-evans/create-or-update-comment@v3
330+
if: github.event_name == 'issue_comment'
194331
with:
195332
issue-number: ${{ env.PR_NUMBER }}
196333
edit-mode: replace
197-
comment-id: ${{ needs.pr_commented.outputs.COMMENT_ID }}
334+
comment-id: ${{ steps.fc.outputs.comment-id }}
198335
body: |
199336
:heavy_check_mark: Deployed PR ${{ env.PR_NUMBER }} successfully.
200-
:rocket: Access the deployment link [here](https://codercom.slack.com/archives/C05DNE982E8).
337+
:rocket: Access the deployment link [here](${{ env.PR_DEPLOYMENT_ACCESS_URL }}).
201338
:warning: This deployment will be deleted when the PR is closed.
202-
reactions: "+1"
339+
reactions: rocket

0 commit comments

Comments
 (0)