forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
159 lines (133 loc) · 6.17 KB
/
azure-staging-build-deploy.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
name: Azure Staging - Build and Deploy
# **What it does**: Builds and deploys a branch/PR to staging
# **Why we have it**: To enable us to deploy a branch/PR to staging whenever necessary
# **Who does it impact**: All contributors.
on:
workflow_dispatch:
inputs:
PR_NUMBER:
description: 'PR Number'
type: string
required: true
COMMIT_REF:
description: 'The commit SHA to build'
type: string
required: true
permissions:
contents: read
deployments: write
# This allows a subsequently queued workflow run to take priority over
# previously queued runs but NOT interrupt currently executing runs
concurrency:
group: 'staging-env @ ${{ github.head_ref || github.run_id }} for ${{ github.event.number || inputs.PR_NUMBER }}'
cancel-in-progress: true
jobs:
azure-staging-build-and-deploy:
if: ${{ github.repository == 'github/docs-internal' }}
runs-on: ubuntu-latest
timeout-minutes: 20
environment:
# TODO: Update name and url to point to a specific slot for the branch/PR
name: staging-env
url: ${{ env.APP_URL }}
env:
PR_NUMBER: ${{ github.event.number || inputs.PR_NUMBER || github.run_id }}
COMMIT_REF: ${{ github.event.pull_request.head.sha || inputs.COMMIT_REF }}
IMAGE_REPO: ${{ github.repository }}/pr-${{ github.event.number || inputs.PR_NUMBER || github.run_id }}
RESOURCE_GROUP_NAME: docs-staging
APP_SERVICE_NAME: ghdocs-staging
SLOT_NAME: canary
steps:
- name: 'Az CLI login'
uses: azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # pin @v1.4.6
with:
creds: ${{ secrets.PROD_AZURE_CREDENTIALS }}
- name: 'Docker login'
uses: azure/docker-login@83efeb77770c98b620c73055fbb59b2847e17dc0
with:
login-server: ${{ secrets.NONPROD_REGISTRY_SERVER }}
username: ${{ secrets.NONPROD_REGISTRY_USERNAME }}
password: ${{ secrets.NONPROD_REGISTRY_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226
- name: Check out repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
with:
ref: ${{ env.COMMIT_REF }}
# To prevent issues with cloning early access content later
persist-credentials: 'false'
- name: 'Set env vars'
run: |
# Set APP_URL
echo "APP_URL=${{ secrets.STAGING_APP_URL }}" >> $GITHUB_ENV
# Image tag is unique to each workflow run so that it always triggers a new deployment
echo "DOCKER_IMAGE=${{ secrets.NONPROD_REGISTRY_SERVER }}/${{ env.IMAGE_REPO }}:${{ env.COMMIT_REF }}-${{ github.run_number }}-${{ github.run_attempt }}" >> $GITHUB_ENV
- name: Setup Node.js
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516
with:
node-version-file: 'package.json'
cache: npm
- name: Clone docs-early-access
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
with:
repository: github/docs-early-access
token: ${{ secrets.DOCS_BOT_PAT_READPUBLICKEY }}
path: docs-early-access
ref: main
- name: Merge docs-early-access repo's folders
run: src/early-access/scripts/merge-early-access.sh
- name: 'Build and push image'
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09
with:
context: .
push: true
target: production
tags: ${{ env.DOCKER_IMAGE }}
build-args: |
BUILD_SHA=${{ env.COMMIT_REF }}
- name: 'Update docker-compose.staging.yaml template file'
run: |
sed 's|#{IMAGE}#|${{ env.DOCKER_IMAGE }}|g' docker-compose.staging.tmpl.yaml > docker-compose.staging.yaml
- name: 'Apply updated docker-compose.staging.yaml config to deployment slot'
run: |
az webapp config container set --multicontainer-config-type COMPOSE --multicontainer-config-file docker-compose.staging.yaml --slot ${{ env.SLOT_NAME }} -n ${{ env.APP_SERVICE_NAME }} -g ${{ env.RESOURCE_GROUP_NAME }}
# Watch deployment slot instances to see when all the instances are ready
- name: Check that deployment slot is ready
uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975
env:
CHECK_INTERVAL: 10000
with:
script: |
const { execSync } = require('child_process')
const slotName = process.env.SLOT_NAME
const appServiceName = process.env.APP_SERVICE_NAME
const resourceGroupName = process.env.RESOURCE_GROUP_NAME
const getStatesForSlot = (slot, appService, resourceGroup) => {
return JSON.parse(
execSync(
`az webapp list-instances --slot ${slot} --query "[].state" -n ${appService} -g ${resourceGroup}`,
{ encoding: 'utf8' }
)
)
}
let hasStopped = false
const waitDuration = parseInt(process.env.CHECK_INTERVAL, 10) || 10000
async function doCheck() {
const states = getStatesForSlot(slotName, appServiceName, resourceGroupName)
console.log(`Instance states:`, states)
// We must wait until at-least 1 instance has STOPPED to know we're looking at the "next" deployment and not the "previous" one
// That way we don't immediately succeed just because all the previous instances were READY
if (!hasStopped) {
hasStopped = states.some((s) => s === 'STOPPED')
}
const isAllReady = states.every((s) => s === 'READY')
if (hasStopped && isAllReady) {
process.exit(0) // success
}
console.log(`checking again in ${waitDuration}ms`)
setTimeout(doCheck, waitDuration)
}
doCheck()
- name: 'Swap deployment slot to production'
run: |
az webapp deployment slot swap --slot ${{ env.SLOT_NAME }} --target-slot production -n ${{ env.APP_SERVICE_NAME }} -g ${{ env.RESOURCE_GROUP_NAME }}