@@ -20,12 +20,144 @@ permissions:
20
20
contents : read
21
21
deployments : write
22
22
23
+ # This allows a subsequently queued workflow run to take priority over
24
+ # previously queued runs but NOT interrupt currently executing runs
25
+ concurrency :
26
+ group : ' staging-env @ ${{ github.head_ref || github.run_id }} for ${{ github.event.number || github.event.inputs.PR_NUMBER }}'
27
+ cancel-in-progress : true
28
+
23
29
jobs :
24
30
azure-staging-build-and-deploy :
25
31
if : ${{ github.repository == 'github/docs-internal' }}
26
32
runs-on : ubuntu-latest
33
+ timeout-minutes : 20
34
+ environment :
35
+ # TODO: Update name and url to point to a specific slot for the branch/PR
36
+ name : staging-env
37
+ url : ${{ env.APP_URL }}
38
+ env :
39
+ PR_NUMBER : ${{ github.event.number || github.event.inputs.PR_NUMBER || github.run_id }}
40
+ COMMIT_REF : ${{ github.event.pull_request.head.sha || github.event.inputs.COMMIT_REF }}
41
+ IMAGE_REPO : ${{ github.repository }}/pr-${{ github.event.number || github.event.inputs.PR_NUMBER || github.run_id }}
42
+ RESOURCE_GROUP_NAME : docs-staging
43
+ APP_SERVICE_NAME : ghdocs-staging
44
+ SLOT_NAME : canary
27
45
28
46
steps :
29
- - name : ' No-op'
47
+ - name : ' Az CLI login'
48
+ uses : azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
49
+ with :
50
+ creds : ${{ secrets.PROD_AZURE_CREDENTIALS }}
51
+
52
+ - name : ' Docker login'
53
+ uses : azure/docker-login@81744f9799e7eaa418697cb168452a2882ae844a
54
+ with :
55
+ login-server : ${{ secrets.NONPROD_REGISTRY_SERVER }}
56
+ username : ${{ secrets.NONPROD_REGISTRY_USERNAME }}
57
+ password : ${{ secrets.NONPROD_REGISTRY_PASSWORD }}
58
+
59
+ - name : Set up Docker Buildx
60
+ uses : docker/setup-buildx-action@94ab11c41e45d028884a99163086648e898eed25
61
+
62
+ - name : Check out repo
63
+ uses : actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
64
+ with :
65
+ ref : ${{ env.COMMIT_REF }}
66
+ # To prevent issues with cloning early access content later
67
+ persist-credentials : ' false'
68
+ lfs : ' true'
69
+
70
+ - name : Check out LFS objects
71
+ run : git lfs checkout
72
+
73
+ - name : ' Set env vars'
74
+ run : |
75
+ # Set APP_URL
76
+ echo "APP_URL=${{ secrets.STAGING_APP_URL }}" >> $GITHUB_ENV
77
+ # Image tag is unique to each workflow run so that it always triggers a new deployment
78
+ echo "DOCKER_IMAGE=${{ secrets.NONPROD_REGISTRY_SERVER }}/${{ env.IMAGE_REPO }}:${{ env.COMMIT_REF }}-${{ github.run_number }}-${{ github.run_attempt }}" >> $GITHUB_ENV
79
+
80
+ - name : Setup node
81
+ uses : actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561
82
+ with :
83
+ node-version : 16.15.x
84
+ cache : npm
85
+
86
+ - name : Clone docs-early-access
87
+ uses : actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
88
+ with :
89
+ repository : github/docs-early-access
90
+ token : ${{ secrets.DOCUBOT_REPO_PAT }}
91
+ path : docs-early-access
92
+ ref : main
93
+
94
+ - name : Merge docs-early-access repo's folders
95
+ run : .github/actions-scripts/merge-early-access.sh
96
+
97
+ - name : ' Build and push image'
98
+ uses : docker/build-push-action@7f9d37fa544684fb73bfe4835ed7214c255ce02b
99
+ with :
100
+ context : .
101
+ push : true
102
+ target : production
103
+ tags : ${{ env.DOCKER_IMAGE }}
104
+ build-args : |
105
+ BUILD_SHA=${{ env.COMMIT_REF }}
106
+
107
+ - name : ' Update docker-compose.staging.yaml template file'
108
+ run : |
109
+ sed 's|#{IMAGE}#|${{ env.DOCKER_IMAGE }}|g' docker-compose.staging.tmpl.yaml > docker-compose.staging.yaml
110
+
111
+ - name : ' Apply updated docker-compose.staging.yaml config to deployment slot'
112
+ run : |
113
+ 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 }}
114
+
115
+ # Watch deployment slot instances to see when all the instances are ready
116
+ - name : Check that deployment slot is ready
117
+ uses : actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d
118
+ env :
119
+ CHECK_INTERVAL : 10000
120
+ with :
121
+ script : |
122
+ const { execSync } = require('child_process')
123
+
124
+ const slotName = process.env.SLOT_NAME
125
+ const appServiceName = process.env.APP_SERVICE_NAME
126
+ const resourceGroupName = process.env.RESOURCE_GROUP_NAME
127
+
128
+ const getStatesForSlot = (slot, appService, resourceGroup) => {
129
+ return JSON.parse(
130
+ execSync(
131
+ `az webapp list-instances --slot ${slot} --query "[].state" -n ${appService} -g ${resourceGroup}`,
132
+ { encoding: 'utf8' }
133
+ )
134
+ )
135
+ }
136
+
137
+ let hasStopped = false
138
+ const waitDuration = parseInt(process.env.CHECK_INTERVAL, 10) || 10000
139
+ async function doCheck() {
140
+ const states = getStatesForSlot(slotName, appServiceName, resourceGroupName)
141
+ console.log(`Instance states:`, states)
142
+
143
+ // We must wait until at-least 1 instance has STOPPED to know we're looking at the "next" deployment and not the "previous" one
144
+ // That way we don't immediately succeed just because all the previous instances were READY
145
+ if (!hasStopped) {
146
+ hasStopped = states.some((s) => s === 'STOPPED')
147
+ }
148
+
149
+ const isAllReady = states.every((s) => s === 'READY')
150
+
151
+ if (hasStopped && isAllReady) {
152
+ process.exit(0) // success
153
+ }
154
+
155
+ console.log(`checking again in ${waitDuration}ms`)
156
+ setTimeout(doCheck, waitDuration)
157
+ }
158
+
159
+ doCheck()
160
+
161
+ - name : ' Swap deployment slot to production'
30
162
run : |
31
- echo "No-op"
163
+ az webapp deployment slot swap --slot ${{ env.SLOT_NAME }} --target-slot production -n ${{ env.APP_SERVICE_NAME }} -g ${{ env.RESOURCE_GROUP_NAME }}
0 commit comments