forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 3
225 lines (191 loc) · 8.36 KB
/
azure-prod-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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
name: Azure Production - Build and Deploy
# **What it does**: Builds and deploys the default branch to production
# **Why we have it**: To enable us to deploy the latest to production whenever necessary rather than relying on PR merges.
# **Who does it impact**: All contributors.
on:
push:
branches:
- main
workflow_dispatch:
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: '${{ github.workflow }}'
cancel-in-progress: false
jobs:
azure-prod-build-and-deploy:
if: ${{ github.repository == 'github/docs-internal' }}
runs-on: ubuntu-20.04-xl
timeout-minutes: 20
environment:
name: production
url: 'https://docs.github.com'
env:
DOCKER_IMAGE: ${{ secrets.PROD_REGISTRY_SERVER }}/${{ github.repository }}:${{ github.sha }}
DOCKER_IMAGE_CACHE_REF: ${{ secrets.PROD_REGISTRY_SERVER }}/${{ github.repository }}:main-production
steps:
- name: 'Az CLI login'
uses: azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
with:
creds: ${{ secrets.PROD_AZURE_CREDENTIALS }}
- name: 'Docker login'
uses: azure/docker-login@83efeb77770c98b620c73055fbb59b2847e17dc0
with:
login-server: ${{ secrets.PROD_REGISTRY_SERVER }}
username: ${{ secrets.PROD_REGISTRY_USERNAME }}
password: ${{ secrets.PROD_REGISTRY_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@95cb08cb2672c73d4ffd2f422e6d11953d2a9c70
- name: Check out repo
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
ref: ${{ github.sha }}
# To prevent issues with cloning early access content later
persist-credentials: 'false'
- name: Setup node
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516
with:
node-version: '16.17.0'
cache: npm
- name: Clone docs-early-access
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
repository: github/docs-early-access
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: docs-early-access
- name: Merge docs-early-access repo's folders
run: .github/actions-scripts/merge-early-access.sh
- name: Clone Simplified Chinese
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
repository: github/docs-internal.zh-cn
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: translations/zh-cn
- name: Clone Japanese
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
repository: github/docs-internal.ja-jp
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: translations/ja-jp
- name: Clone Spanish
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
repository: github/docs-internal.es-es
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: translations/es-es
- name: Clone Portuguese
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
repository: github/docs-internal.pt-br
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: translations/pt-br
- name: Clone German
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
repository: github/docs-internal.de-de
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: translations/de-de
- name: Clone French
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
repository: github/docs-internal.fr-fr
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: translations/fr-fr
- name: Clone Russian
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
repository: github/docs-internal.ru-ru
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: translations/ru-ru
- name: Clone Korean
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
repository: github/docs-internal.ko-kr
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: translations/ko-kr
# As of Dec 2022, we still have checked in translations into
# the main repo.
# We're going to remove that later.
# For now, just delete the excess directories so they don't add
# unnecessary weight to the container image.
- name: Delete old checked in translation directories (TEMPORARY)
run: |
rm -fr translations/zh-CN
rm -fr translations/ja-JP
rm -fr translations/es-ES
rm -fr translations/pt-BR
rm -fr translations/de-DE
rm -fr translations/fr-FR
rm -fr translations/ru-RU
rm -fr translations/ko-KR
- name: 'Build and push image'
uses: docker/build-push-action@1cb9d22b932e4832bb29793b7777ec860fc1cde0
with:
context: .
push: true
target: production
tags: ${{ env.DOCKER_IMAGE }}, ${{ env.DOCKER_IMAGE_CACHE_REF }}
cache-from: type=registry,ref=${{ env.DOCKER_IMAGE_CACHE_REF }}
cache-to: type=registry,mode=max,ref=${{ env.DOCKER_IMAGE_CACHE_REF }}
build-args: |
BUILD_SHA=${{ github.sha }}
- name: 'Update docker-compose.prod.yaml template file'
run: |
sed 's|#{IMAGE}#|${{ env.DOCKER_IMAGE }}|g' docker-compose.prod.tmpl.yaml > docker-compose.prod.yaml
- name: 'Apply updated docker-compose.prod.yaml config to canary slot'
run: |
az webapp config container set --multicontainer-config-type COMPOSE --multicontainer-config-file docker-compose.prod.yaml --slot canary -n ghdocs-prod -g docs-prod
# Watch canary slot instances to see when all the instances are ready
- name: Check that canary slot is ready
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d
env:
CHECK_INTERVAL: 10000
with:
script: |
const { execSync } = require('child_process')
const getStatesForSlot = (slot) => {
return JSON.parse(
execSync(
`az webapp list-instances --slot ${slot} --query "[].state" -n ghdocs-prod -g docs-prod`,
{ encoding: 'utf8' }
)
)
}
let hasStopped = false
const waitDuration = parseInt(process.env.CHECK_INTERVAL, 10) || 10000
async function doCheck() {
const states = getStatesForSlot('canary')
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()
# TODO - make a request to verify the canary app version aligns with *this* github action workflow commit sha
- name: 'Swap canary slot to production'
run: |
az webapp deployment slot swap --slot canary --target-slot production -n ghdocs-prod -g docs-prod
send-slack-notification-on-failure:
needs: [azure-prod-build-and-deploy]
runs-on: ubuntu-latest
if: ${{ failure() }}
steps:
- name: Send Slack notification if workflow failed
uses: someimportantcompany/github-actions-slack-message@f8d28715e7b8a4717047d23f48c39827cacad340
if: ${{ failure() }}
with:
channel: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
bot-token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
color: failure
text: Production deployment (Azure) failed at commit ${{ github.sha }}. See https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}