1+ name : Continuous Integration
2+ run-name : ${{ github.event_name == 'pull_request' && format('Pull Request "{0}" - Complete CI Pipeline', github.event.pull_request.title) || (github.event_name == 'schedule' && 'Scheduled Weekly Deployment and Testing' || format('Main Branch Deploy - {0}', github.sha)) }}
3+
4+ on :
5+ pull_request :
6+ branches :
7+ - main
8+ push :
9+ branches :
10+ - main
11+ paths :
12+ - src
13+ - scripts
14+ - build
15+ - deploy
16+ - .github/workflows/continuous-integration.yml
17+ schedule :
18+ # Sunday at 2 PM UTC (Sunday afternoon)
19+ - cron : ' 0 14 * * 0'
20+
21+ env :
22+ PR_NUMBER : ${{ github.event.number }}
23+
24+ concurrency :
25+ group : aks-sample-environment
26+ cancel-in-progress : false
27+
28+ jobs :
29+ check-recording-bot-changes :
30+ runs-on : ubuntu-latest
31+ outputs :
32+ build : ${{ steps.changes.outputs.build }}
33+ deploy : ${{ steps.changes.outputs.deploy }}
34+ docs : ${{ steps.changes.outputs.docs }}
35+ scripts : ${{ steps.changes.outputs.scripts }}
36+ src : ${{ steps.changes.outputs.src }}
37+ steps :
38+ - uses : actions/checkout@v4
39+ - shell : pwsh
40+ id : changes
41+ run : |
42+ if ('${{ github.event_name }}' -eq 'push' -or '${{ github.event_name }}' -eq 'schedule') {
43+ # For main branch pushes and scheduled runs, always consider all changes as relevant
44+ echo "build=True" >> $env:GITHUB_OUTPUT
45+ echo "deploy=True" >> $env:GITHUB_OUTPUT
46+ echo "docs=True" >> $env:GITHUB_OUTPUT
47+ echo "scripts=True" >> $env:GITHUB_OUTPUT
48+ echo "src=True" >> $env:GITHUB_OUTPUT
49+ } else {
50+ # For pull requests, check actual changes
51+ git fetch
52+ git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
53+ $diff = git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}
54+
55+ # Check if a file has changed (added, modified, deleted)
56+ $BuildDiff = $diff | Where-Object { $_ -match '^build/' }
57+ $DeployDiff = $diff | Where-Object { $_ -match '^deploy/' }
58+ $DocsDiff = $diff | Where-Object { $_ -match '^docs/' -or $_ -match '.md$' }
59+ $ScriptsDiff = $diff | Where-Object { $_ -match '^scripts/' }
60+ $SrcDiff = $diff | Where-Object { $_ -match '^src/' }
61+
62+ $HasBuildDiff = $BuildDiff.Length -gt 0
63+ $HasDeployDiff = $DeployDiff.Length -gt 0
64+ $HasDocsDiff = $DocsDiff.Length -gt 0
65+ $HasScriptsDiff = $ScriptsDiff.Length -gt 0
66+ $HasSrcDiff = $SrcDiff.Length -gt 0
67+
68+ # Set the outputs
69+ echo "build=$HasBuildDiff" >> $env:GITHUB_OUTPUT
70+ echo "deploy=$HasDeployDiff" >> $env:GITHUB_OUTPUT
71+ echo "docs=$HasDocsDiff" >> $env:GITHUB_OUTPUT
72+ echo "scripts=$HasScriptsDiff" >> $env:GITHUB_OUTPUT
73+ echo "src=$HasSrcDiff" >> $env:GITHUB_OUTPUT
74+ }
75+
76+ chart-version-checks :
77+ runs-on : ubuntu-latest
78+ needs : check-recording-bot-changes
79+ if : |
80+ needs.check-recording-bot-changes.outputs.build == 'True' ||
81+ needs.check-recording-bot-changes.outputs.deploy == 'True' ||
82+ needs.check-recording-bot-changes.outputs.scripts == 'True' ||
83+ needs.check-recording-bot-changes.outputs.src == 'True'
84+
85+ defaults :
86+ run :
87+ working-directory : deploy
88+
89+ outputs :
90+ app-version-check-passed : ${{ steps.app-version-check.outcome }}
91+ chart-version-check-passed : ${{ steps.chart-version-check.outcome }}
92+
93+ steps :
94+ - uses : actions/checkout@v4
95+ - run : |
96+ git fetch
97+ git branch -a
98+
99+ - name : Install Helm
100+ uses : azure/setup-helm@v3
101+ with :
102+ version : ' latest'
103+
104+ - name : Lint Helm Chart
105+ working-directory : deploy/teams-recording-bot
106+ if : needs.check-recording-bot-changes.outputs.deploy == 'True'
107+ run : |
108+ echo "🔍 Linting Helm chart..."
109+ helm lint
110+ echo "✅ Helm chart lint passed"
111+
112+ - name : Check App Version Change (PR only)
113+ id : app-version-check
114+ if : |
115+ github.event_name == 'pull_request' &&
116+ (
117+ needs.check-recording-bot-changes.outputs.build == 'True' ||
118+ needs.check-recording-bot-changes.outputs.scripts == 'True' ||
119+ needs.check-recording-bot-changes.outputs.src == 'True'
120+ )
121+ shell : bash
122+ run : |
123+ echo "🔍 Checking app version changes..."
124+ oldVersion=$(MSYS_NO_PATHCONV=1 git show remotes/origin/$GITHUB_BASE_REF:deploy/teams-recording-bot/Chart.yaml | sed -n "s/^appVersion: \([0-9\.]*\)$/\1/p")
125+ echo "Previous app Version: $oldVersion"
126+ [ -z "$oldVersion" ] && exit 1
127+
128+ newVersion=$(cat teams-recording-bot/Chart.yaml | sed -n "s/^appVersion: \([0-9\.]*\)$/\1/p")
129+ echo "New app Version: $newVersion"
130+ [ -z "$newVersion" ] && exit 1
131+
132+ echo "Check if app Version was updated"
133+ [ "$newVersion" = "$oldVersion" ] && exit 1
134+ newerVersion=$(echo -e "$oldVersion\n$newVersion" | sort -V | tail -1)
135+ [ "$newerVersion" = "$newVersion" ] || exit 1
136+ echo "✅ Success app Version was updated!"
137+
138+ - name : Check Chart Version Change (PR only)
139+ if : github.event_name == 'pull_request' && needs.check-recording-bot-changes.outputs.deploy == 'True'
140+ shell : bash
141+ run : |
142+ echo "🔍 Checking chart version changes..."
143+ oldVersion=$(MSYS_NO_PATHCONV=1 git show remotes/origin/$GITHUB_BASE_REF:deploy/teams-recording-bot/Chart.yaml | sed -n "s/^version: \([0-9\.]*\)$/\1/p")
144+ echo "Previous Version: $oldVersion"
145+ [ -z "$oldVersion" ] && exit 1
146+
147+ newVersion=$(cat teams-recording-bot/Chart.yaml | sed -n "s/^version : \([0-9\.]*\)$/\1/p")
148+ echo "New Version : $newVersion"
149+ [ -z "$newVersion" ] && exit 1
150+
151+ echo "Check if Version was updated"
152+ [ "$newVersion" = "$oldVersion" ] && exit 1
153+ newerVersion=$(echo -e "$oldVersion\n$newVersion" | sort -V | tail -1)
154+ [ "$newerVersion" = "$newVersion" ] || exit 1
155+ echo "✅ Success Version was updated!"
156+
157+ retag-and-push :
158+ runs-on : ubuntu-latest
159+ needs : [check-recording-bot-changes, chart-version-checks]
160+ if : |
161+ (github.event_name == 'push' || github.event_name == 'schedule') &&
162+ needs.chart-version-checks.result == 'success' &&
163+ (
164+ needs.check-recording-bot-changes.outputs.build == 'True' ||
165+ needs.check-recording-bot-changes.outputs.scripts == 'True' ||
166+ needs.check-recording-bot-changes.outputs.src == 'True'
167+ )
168+
169+ permissions :
170+ packages : write
171+
172+ outputs :
173+ image-exists : ${{ steps.check-image.outputs.image-exists }}
174+
175+ steps :
176+ - uses : actions/checkout@v4
177+
178+ - name : Login to GitHub Container Registry
179+ uses : docker/login-action@v3
180+ with :
181+ registry : ghcr.io
182+ username : ${{ github.actor }}
183+ password : ${{ secrets.GITHUB_TOKEN }}
184+
185+ - name : Generate Docker image tag
186+ id : generate-tag
187+ run : |
188+ hash=$(find src build scripts -type f -exec sha256sum {} \; | sort | sha256sum | awk '{print $1}')
189+ echo "tag=$hash" >> $GITHUB_OUTPUT
190+
191+ - name : Check if image exists
192+ id : check-image
193+ run : |
194+ if docker manifest inspect ${{ vars.CR_NAMESPACE_REPOSITORY }}:${{ steps.generate-tag.outputs.tag }} > /dev/null 2>&1; then
195+ echo "Image already exists"
196+ echo "image-exists=true" >> $GITHUB_OUTPUT
197+ else
198+ echo "image-exists=false" >> $GITHUB_OUTPUT
199+ fi
200+
201+ - name : Pull PR image and retag as latest
202+ if : steps.check-image.outputs.image-exists == 'true'
203+ run : |
204+ TAG="${{ steps.generate-tag.outputs.tag }}"
205+ REGISTRY="${{ vars.CR_NAMESPACE_REPOSITORY }}"
206+
207+ echo "🔍 Pulling image with tag: $TAG"
208+ docker pull ${REGISTRY}:${TAG}
209+
210+ echo "🏷️ Retagging image as latest"
211+ docker tag ${REGISTRY}:${TAG} ${REGISTRY}:latest
212+
213+ echo "🚀 Pushing latest image"
214+ docker push ${REGISTRY}:latest
215+
216+ echo "✅ Successfully promoted ${REGISTRY}:${TAG} to ${REGISTRY}:latest"
217+
218+ start-cluster :
219+ needs : [check-recording-bot-changes, chart-version-checks]
220+ if : |
221+ needs.chart-version-checks.result == 'success' &&
222+ (
223+ needs.check-recording-bot-changes.outputs.build == 'True' ||
224+ needs.check-recording-bot-changes.outputs.deploy == 'True' ||
225+ needs.check-recording-bot-changes.outputs.scripts == 'True' ||
226+ needs.check-recording-bot-changes.outputs.src == 'True'
227+ )
228+ uses : ./.github/workflows/routine-managecluster.yml
229+ with :
230+ action : ' start'
231+ cluster-name : ${{ vars.AKS_CLUSTER_NAME }}
232+ resource-group : ${{ vars.AKS_RESOURCE_GROUP }}
233+ subscription : ${{ vars.AZURE_SUBSCRIPTION_ID }}
234+ secrets :
235+ AZURE_CREDENTIALS : ${{ secrets.AZURE_CREDENTIALS }}
236+
237+ generate-image-tag :
238+ needs : [check-recording-bot-changes, chart-version-checks, retag-and-push]
239+ if : |
240+ always() &&
241+ needs.chart-version-checks.result == 'success' &&
242+ (
243+ needs.check-recording-bot-changes.outputs.build == 'True' ||
244+ needs.check-recording-bot-changes.outputs.src == 'True' ||
245+ needs.check-recording-bot-changes.outputs.scripts == 'True'
246+ ) &&
247+ (
248+ github.event_name == 'pull_request' ||
249+ ((github.event_name == 'push' || github.event_name == 'schedule') && needs.retag-and-push.outputs.image-exists == 'false')
250+ )
251+ runs-on : ubuntu-latest
252+
253+ outputs :
254+ image-tag : ${{ steps.generate-tag.outputs.tag }}
255+
256+ steps :
257+ - uses : actions/checkout@v4
258+
259+ - name : Generate content-based image tag
260+ id : generate-tag
261+ run : |
262+ hash=$(find src build scripts -type f -exec sha256sum {} \; | sort | sha256sum | awk '{print $1}')
263+ if [ '${{ github.event_name }}' = 'pull_request' ]; then
264+ echo "tag=pr-${{ github.event.number }}-${hash:0:8}" >> $GITHUB_OUTPUT
265+ else
266+ echo "tag=latest" >> $GITHUB_OUTPUT
267+ fi
268+
269+ build-docker-image :
270+ needs : [check-recording-bot-changes, chart-version-checks, retag-and-push, generate-image-tag]
271+ if : |
272+ always() &&
273+ needs.chart-version-checks.result == 'success' &&
274+ (
275+ needs.check-recording-bot-changes.outputs.build == 'True' ||
276+ needs.check-recording-bot-changes.outputs.src == 'True' ||
277+ needs.check-recording-bot-changes.outputs.scripts == 'True'
278+ ) &&
279+ (
280+ github.event_name == 'pull_request' ||
281+ ((github.event_name == 'push' || github.event_name == 'schedule') && needs.retag-and-push.outputs.image-exists == 'false')
282+ )
283+ uses : ./.github/workflows/routine-buildimage.yml
284+ permissions :
285+ packages : write
286+ with :
287+ tag : ${{ needs.generate-image-tag.outputs.image-tag }}
288+ cr-namespace-repository : ${{ vars.CR_NAMESPACE_REPOSITORY }}
289+ secrets : inherit
290+
291+ deploy-to-environment :
292+ needs : [check-recording-bot-changes, chart-version-checks, start-cluster, build-docker-image, retag-and-push, generate-image-tag]
293+ if : |
294+ always() &&
295+ needs.start-cluster.result == 'success' &&
296+ (
297+ needs.build-docker-image.result == 'success' ||
298+ (needs.retag-and-push.result == 'success' && (github.event_name == 'push' || github.event_name == 'schedule')) ||
299+ (needs.check-recording-bot-changes.outputs.deploy == 'True' && (needs.build-docker-image.result == 'skipped' || needs.retag-and-push.result == 'skipped'))
300+ )
301+ uses : ./.github/workflows/routine-deployenvironment.yml
302+ with :
303+ environment-name : aks-sample
304+ port : ' 28550'
305+ cluster-name : ${{ vars.AKS_CLUSTER_NAME }}
306+ resource-group : ${{ vars.AKS_RESOURCE_GROUP }}
307+ subscription : ${{ vars.AZURE_SUBSCRIPTION_ID }}
308+ namespace : teams-recording-bot
309+ host : ${{ needs.start-cluster.outputs.cluster-fqdn }}
310+ image-registry : ${{ vars.CR_REGISTRY }}
311+ image-name : ${{ vars.CR_IMAGE_NAME }}
312+ image-tag : ${{ needs.generate-image-tag.outputs.image-tag || 'latest' }}
313+ public-ip : ${{ needs.start-cluster.outputs.cluster-ip }}
314+ tls-email : ${{ vars.TLS_EMAIL }}
315+ enable-nginx : true
316+ replica-count : ' 1'
317+ secrets :
318+ AZURE_CREDENTIALS : ${{ secrets.AZURE_CREDENTIALS }}
319+
320+ run-tests :
321+ needs : [check-recording-bot-changes, chart-version-checks, start-cluster, build-docker-image, deploy-to-environment, generate-image-tag]
322+ if : always() && needs.deploy-to-environment.result == 'success'
323+ uses : ./.github/workflows/routine-runtests.yml
324+ with :
325+ headless-mode : true
326+ test-environment : ${{ needs.generate-image-tag.outputs.image-tag || 'latest' }}
327+ github-issue-number : ${{ github.event.number || '' }}
328+ secrets :
329+ USER_A_USERNAME : ${{ vars.TEST_USER_A_USERNAME }}
330+ USER_A_PASSWORD : ${{ secrets.TEST_USER_A_PASSWORD }}
331+ USER_A_SEED : ${{ secrets.TEST_USER_A_SEED }}
332+ USER_B_USERNAME : ${{ vars.TEST_USER_B_USERNAME }}
333+ USER_B_PASSWORD : ${{ secrets.TEST_USER_B_PASSWORD }}
334+ USER_B_SEED : ${{ secrets.TEST_USER_B_SEED }}
335+ USER_C_USERNAME : ${{ vars.TEST_USER_C_USERNAME }}
336+ USER_C_PASSWORD : ${{ secrets.TEST_USER_C_PASSWORD }}
337+ USER_C_SEED : ${{ secrets.TEST_USER_C_SEED }}
0 commit comments