77 inputs :
88 pr_number :
99 description : " PR number"
10+ type : number
1011 required : true
1112 skip_build :
1213 description : " Skip build job"
1314 required : false
15+ type : boolean
1416 default : false
17+ experiments :
18+ description : " Experiments to enable"
19+ required : false
20+ type : string
21+ default : " *"
1522
1623env :
1724 REPO : ghcr.io/coder/coder-preview
@@ -22,8 +29,8 @@ permissions:
2229 pull-requests : write
2330
2431concurrency :
25- group : ${{ github.workflow }}-${{ github.event.issue.number || github.run_id }}
26- cancel-in-progress : false
32+ group : ${{ github.workflow }}-${{ github.repository }}-${{ github.ref }}
33+ cancel-in-progress : true
2734
2835jobs :
2936 pr_commented :
@@ -136,7 +143,7 @@ jobs:
136143 PR_TITLE : ${{ needs.pr_commented.outputs.PR_TITLE }}
137144 PR_URL : ${{ needs.pr_commented.outputs.PR_URL }}
138145 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 }}"
146+ PR_DEPLOYMENT_ACCESS_URL : " pr${{ needs.pr_commented.outputs.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
140147 steps :
141148 - name : Check if image exists
142149 run : |
@@ -145,10 +152,19 @@ jobs:
145152 if [ -z "$foundTag" ]; then
146153 echo "Image not found"
147154 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 "
155+ echo "Please remove --skip-build from the comment and try again "
149156 exit 1
150157 fi
151158
159+ - name : Add DNS record to Cloudflare
160+ 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+ )
167+
152168 - name : Checkout
153169 uses : actions/checkout@v3
154170 with :
@@ -168,35 +184,36 @@ jobs:
168184 kubectl delete namespace "pr${{ env.PR_NUMBER }}" || true
169185 kubectl create namespace "pr${{ env.PR_NUMBER }}"
170186
171- - name : Setup ingress
187+ - name : Check and Create Certificate
172188 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 }}"
189+ # Using kubectl to check if a Certificate resource already exists
190+ # we are doing this to avoid letsenrypt rate limits
191+ if ! kubectl get certificate pr${{ env.PR_NUMBER }}-tls -n pr-deployment-certs > /dev/null 2>&1; then
192+ echo "Certificate doesn't exist. Creating a new one."
193+ cat <<EOF | kubectl apply -f -
194+ apiVersion: cert-manager.io/v1
195+ kind: Certificate
196+ metadata:
197+ name: pr${{ env.PR_NUMBER }}-tls
198+ namespace: pr-deployment-certs
199+ spec:
186200 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
201+ issuerRef:
202+ name: letsencrypt
203+ kind: ClusterIssuer
204+ dnsNames:
205+ - "${{ env.PR_DEPLOYMENT_ACCESS_URL }}"
206+ - "*.${{ env.PR_DEPLOYMENT_ACCESS_URL }}"
198207 EOF
199- kubectl apply -f ingress.yaml
208+ else
209+ echo "Certificate exists. Skipping certificate creation."
210+ echo "Copy certificate from pr-deployment-certs to pr${{ env.PR_NUMBER }} namespace"
211+ (
212+ kubectl get secret pr${{ env.PR_NUMBER }}-tls -n pr-deployment-certs -o json |
213+ jq 'del(.metadata.namespace,.metadata.creationTimestamp,.metadata.resourceVersion,.metadata.selfLink,.metadata.uid,.metadata.managedFields)' |
214+ kubectl -n pr${{ env.PR_NUMBER }} apply -f -
215+ )
216+ fi
200217
201218 - name : Set up PostgreSQL database
202219 run : |
@@ -210,6 +227,17 @@ jobs:
210227 kubectl create secret generic coder-db-url -n pr${{ env.PR_NUMBER }} \
211228 --from-literal=url="postgres://coder:coder@coder-db-postgresql.pr${{ env.PR_NUMBER }}.svc.cluster.local:5432/coder?sslmode=disable"
212229
230+ - name : Get experiments
231+ id : get_experiments
232+ run : |
233+ set -euxo pipefail
234+ if [[ ${{ github.event_name }} == "workflow_dispatch" ]]; then
235+ experiments=${{ github.event.inputs.experiments }}
236+ else
237+ experiments=$(echo "${{ github.event.comment.body }}" | grep -oP '(?<=--experiments )[^ ]+')
238+ fi
239+ echo "experiments=$experiments" >> $GITHUB_OUTPUT
240+
213241 - name : Create values.yaml
214242 run : |
215243 cat <<EOF > pr-deploy-values.yaml
@@ -220,13 +248,22 @@ jobs:
220248 pullPolicy: Always
221249 service:
222250 type: ClusterIP
251+ ingress:
252+ enable: true
253+ className: traefik
254+ host: ${{ env.PR_DEPLOYMENT_ACCESS_URL }}
255+ wildcardHost: "*.${{ env.PR_DEPLOYMENT_ACCESS_URL }}"
256+ tls:
257+ enable: true
258+ secretName: pr${{ env.PR_NUMBER }}-tls
259+ wildcardSecretName: pr${{ env.PR_NUMBER }}-tls
223260 env:
224261 - name: "CODER_ACCESS_URL"
225- value: "https://pr ${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
262+ value: "https://${{ env.PR_DEPLOYMENT_ACCESS_URL }}"
226263 - name: "CODER_WILDCARD_ACCESS_URL"
227- value: "*--pr ${{ env.PR_NUMBER }}.${{ secrets.PR_DEPLOYMENTS_DOMAIN }}"
264+ value: "*. ${{ env.PR_DEPLOYMENT_ACCESS_URL }}"
228265 - name: "CODER_EXPERIMENTS"
229- value: "*"
266+ value: "*,${{ steps.get_experiments.outputs.experiments }} "
230267 - name: CODER_PG_CONNECTION_URL
231268 valueFrom:
232269 secretKeyRef:
@@ -261,7 +298,7 @@ jobs:
261298 set -euxo pipefail
262299
263300 DEST="${HOME}/coder"
264- URL="${{ env.PR_DEPLOYMENT_ACCESS_URL }}/bin/coder-linux-amd64"
301+ URL="https:// ${{ env.PR_DEPLOYMENT_ACCESS_URL }}/bin/coder-linux-amd64"
265302
266303 mkdir -p "$(dirname ${DEST})"
267304
@@ -279,6 +316,7 @@ jobs:
279316 curl -fsSL "$URL" -o "${DEST}"
280317 chmod +x "${DEST}"
281318 "${DEST}" version
319+ mv "${DEST}" /usr/local/bin/coder
282320
283321 - name : Create first user, template and workspace
284322 id : setup_deployment
@@ -294,16 +332,16 @@ jobs:
294332 echo "::add-mask::$password"
295333 echo "password=$password" >> $GITHUB_OUTPUT
296334
297- /home/runner/ coder login \
298- --first-user-username pr${{ env.PR_NUMBER }} \
299- --first-user-email ${{ env.PR_NUMBER }}@coder.com \
335+ coder login \
336+ --first-user-username test \
337+ --first-user-email pr ${{ env.PR_NUMBER }}@coder.com \
300338 --first-user-password $password \
301339 --first-user-trial \
302340 --use-token-as-session \
303- ${{ env.PR_DEPLOYMENT_ACCESS_URL }}
341+ https:// ${{ env.PR_DEPLOYMENT_ACCESS_URL }}
304342
305343 # Create template
306- /home/runner/ coder templates init --id kubernetes && cd ./kubernetes/ && /home/runner/ coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }}
344+ coder templates init --id kubernetes && cd ./kubernetes/ && coder templates create -y --variable namespace=pr${{ env.PR_NUMBER }}
307345
308346 # Create workspace
309347 cat <<EOF > workspace.yaml
@@ -312,8 +350,8 @@ jobs:
312350 home_disk_size: "2"
313351 EOF
314352
315- /home/runner/ coder create --template="kubernetes" pr${{ env.PR_NUMBER }} --rich-parameter-file ./workspace.yaml -y
316- /home/runner/ coder stop pr${{ env.PR_NUMBER }} -y
353+ coder create --template="kubernetes" test --rich-parameter-file ./workspace.yaml -y
354+ coder stop test -y
317355
318356 - name : Send Slack notification
319357 run : |
@@ -323,9 +361,9 @@ jobs:
323361 "pr_number": "'"${{ env.PR_NUMBER }}"'",
324362 "pr_url": "'"${{ env.PR_URL }}"'",
325363 "pr_title": "'"${{ env.PR_TITLE }}"'",
326- "pr_access_url": "'"${{ env.PR_DEPLOYMENT_ACCESS_URL }}"'",
327- "pr_username": "'"pr${{ env.PR_NUMBER }} "'",
328- "pr_email": "'"${{ env.PR_NUMBER }}@coder.com"'",
364+ "pr_access_url": "'"https:// ${{ env.PR_DEPLOYMENT_ACCESS_URL }}"'",
365+ "pr_username": "'"test "'",
366+ "pr_email": "'"pr ${{ env.PR_NUMBER }}@coder.com"'",
329367 "pr_password": "'"${{ steps.setup_deployment.outputs.password }}"'",
330368 "pr_actor": "'"${{ github.actor }}"'"
331369 }' \
@@ -351,6 +389,6 @@ jobs:
351389 comment-id : ${{ steps.fc.outputs.comment-id }}
352390 body : |
353391 :heavy_check_mark: Deployed PR ${{ env.PR_NUMBER }} successfully.
354- :rocket: Access the deployment link [here](${{ env.PR_DEPLOYMENT_ACCESS_URL }}).
392+ :rocket: Access the deployment link [here](https:// ${{ env.PR_DEPLOYMENT_ACCESS_URL }}).
355393 :warning: This deployment will be deleted when the PR is closed.
356394 reactions : rocket
0 commit comments