88 branches :
99 - ' *'
1010
11+ concurrency :
12+ group : ${{ github.workflow }}-${{ github.ref }}
13+
1114jobs :
1215 build-and-deploy :
1316 runs-on : ubuntu-latest
1417
1518 steps :
16- - name : Configure Git Credentials
17- uses : de-vri-es/setup-git-credentials@v2
18- with :
19- credentials : ${{ secrets.GIT_CREDENTIALS }}
20-
2119 - name : Checkout Repository
2220 uses : actions/checkout@v4
2321
@@ -26,134 +24,181 @@ jobs:
2624 with :
2725 node-version : 21.6.1
2826
29- - name : Install Dependencies
30- run : npm ci
27+ - name : Validate Branch Names
28+ run : |
29+ # Check if branch names contain invalid characters. Only alphanumeric, _, -, ., and / are allowed.
30+ validate_branch_name() {
31+ local branch_name="$1"
32+ if [[ ! "$branch_name" =~ ^[a-zA-Z0-9/_\.-]+$ ]]; then
33+ echo "Error: Branch name contains invalid characters. Only alphanumeric, _, -, ., and / are allowed."
34+ exit 1
35+ fi
36+ }
37+ validate_branch_name "${{ github.event.pull_request.head.ref }}"
3138
3239 - name : Extract Branch Names
33- shell : bash
34- run : |
35- # transform branch names in form of `refs/heads/main` to `main`
36- draft_branch=$(basename ${{ github.event.pull_request.head.ref || github.event.ref }})
37- echo "draft_branch=$draft_branch" >> $GITHUB_OUTPUT
3840 id : extract_branch
41+ run : |
42+ # Extract and transform branch names
43+ extract_branch() {
44+ local input_branch="$1"
45+ # Check if input_branch starts with "refs/heads/"
46+ if [[ "$input_branch" == refs/heads/* ]]; then
47+ # Remove "refs/heads/" prefix safely using parameter expansion
48+ branch_name="${input_branch#refs/heads/}"
49+ echo "$branch_name"
50+ else
51+ echo "$input_branch"
52+ fi
53+ }
54+
55+ # Transform branch names in form of `refs/heads/main` to `main`
56+ draft_branch=$(extract_branch "${{ github.event.pull_request.head.ref }}")
57+
58+ # Replace / with - in the draft branch name to use as a directory name
59+ draft_directory=$(echo "$draft_branch" | tr / -)
60+
61+ # Safe echo to $GITHUB_OUTPUT
62+ {
63+ echo "draft_branch=$draft_branch"
64+ echo "draft_directory=$draft_directory"
65+ } >> "$GITHUB_OUTPUT"
66+
67+ - name : Set Draft URL
68+ id : draft_url
69+ if : success()
70+ run : |
71+ echo "url=${{ vars.BUNDLE_PREVIEW_BASE_URL }}/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/index.html" >> $GITHUB_OUTPUT
72+
73+ - name : Install Dependencies
74+ run : npm ci
3975
4076 - name : Build UI Bundle Preview
77+ if : success()
4178 run : |
4279 set -o pipefail
4380 gulp lint |& tee $GITHUB_WORKSPACE/build.log
4481 gulp preview:build |& tee $GITHUB_WORKSPACE/build.log
4582
4683 - name : Check Build Result
47- id : logFail
84+ id : buildLogFail
4885 if : failure()
4986 run : |
5087 MULTILINE_LOG=$(cat $GITHUB_WORKSPACE/build.log)
5188 echo "BUILD_FAILURE<<EOF" >> $GITHUB_ENV
5289 echo $MULTILINE_LOG >> $GITHUB_ENV
5390 echo "EOF" >> $GITHUB_ENV
5491
92+ - name : Assemble Build Success Comment
93+ if : ${{ success() && github.event.pull_request.number }}
94+ run : |
95+ build_success_comment="UI bundle preview build successful! :white_check_mark:"
96+ build_success_comment+="\nDeploying bundle preview."
97+
98+ echo "BUILD_SUCCESS_COMMENT<<EOF" >> $GITHUB_ENV
99+ echo -e "$build_success_comment" >> $GITHUB_ENV
100+ echo "EOF" >> $GITHUB_ENV
101+
55102 - name : Create Build Success Comment
56103 if : ${{ success() && github.event.pull_request.number }}
57- uses : peter-evans/create-or-update-comment@v3
104+ uses : peter-evans/create-or-update-comment@v4
58105 with :
59- token : ${{ secrets.DOCS_GITHUB_PAT }}
60106 issue-number : ${{ github.event.pull_request.number }}
61- body : |
62- UI bundle preview build successful! :white_check_mark:
63- Deploying preview to GitHub Pages.
107+ body : " ${{ env.BUILD_SUCCESS_COMMENT }}"
64108 reactions : rocket
65109
66110 - name : Create Build Failure Comment
67111 if : ${{ failure() && github.event.pull_request.number }}
68- uses : peter-evans/create-or-update-comment@v3
112+ uses : peter-evans/create-or-update-comment@v4
69113 with :
70- token : ${{ secrets.DOCS_GITHUB_PAT }}
71114 issue-number : ${{ github.event.pull_request.number }}
72115 body : |
73116 UI bundle preview build failure! :x:
74117 > ${{ env.BUILD_FAILURE }}
75118 reactions : confused
76119
77120 - name : Find Comment
78- if : ${{ success() && github.event.pull_request.number }}
79- uses : peter-evans/find-comment@v2
80121 id : fc
122+ if : ${{ success() && github.event.pull_request.number }}
123+ uses : peter-evans/find-comment@v3
81124 with :
82- token : ${{ secrets.DOCS_GITHUB_PAT }}
83125 issue-number : ${{ github.event.pull_request.number }}
84126 body-includes : UI bundle preview build successful!
85127 direction : last
86128
87- - name : Deploy to GitHub Pages
129+ - name : Configure AWS CLI
88130 if : success()
89131 run : |
90- git clone https://github.com/$GITHUB_REPOSITORY.git pages
91- cd pages
92- git checkout gh-pages
93-
94- # If there was previously a build for the preview, then remove it
95- # so we get a clean build. This is needed in case a follow up
96- # build of the same pull request contains content deletions.
97- rm -rf ${{ steps.extract_branch.outputs.draft_branch }}
132+ aws configure set aws_access_key_id ${{ secrets.DOCS_UI_AWS_ACCESS_KEY_ID }}
133+ aws configure set aws_secret_access_key ${{ secrets.DOCS_UI_AWS_SECRET_ACCESS_KEY }}
134+ aws configure set region us-west-2
98135
99- mkdir -p ${{ steps.extract_branch.outputs.draft_branch }}
100- cp -r ../public/* ${{ steps.extract_branch.outputs.draft_branch }}/.
136+ - name : Deploy to S3
137+ if : success()
138+ run : |
139+ set -o pipefail
140+ mkdir docs-ui-drafts
141+ mv public docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}
142+ cd docs-ui-drafts
101143
102144 # Records the repository that originally triggered the build so we can post back
103145 # comments upon clean up of a stale draft if it still has an open pull request.
104- echo "${{ github.event.repository.full_name }}" > ${{ steps.extract_branch.outputs.draft_branch }}/.github_source_repository
105-
106- git add .
107- git config user.name 'github-actions[bot]'
108- git config user.email 'github-actions[bot]@users.noreply.github.com'
109- git commit --allow-empty -m "Auto-deployed from GitHub Actions"
110- git push -u origin gh-pages
111-
112- - name : Obtain GitHub Pages build URL
113- if : success()
114- run : |
115- sleep 5 # Allow time for build to initiate
116- build_url=$(curl -s -L \
117- -H "Accept: application/vnd.github+json" \
118- -H "Authorization: Bearer ${{ secrets.DOCS_GITHUB_PAT }}" \
119- -H "X-GitHub-Api-Version: 2022-11-28" 'https://api.github.com/repos/${{ github.event.repository.full_name }}/pages/builds/latest' \
120- | jq -r .url)
121- echo "url=$build_url" >> $GITHUB_OUTPUT
122- id : ghpages_build
123-
124- - name : Wait for Github Pages deployment
125- if : success()
126- run : |
127- for i in {1..60}; do
128- build_status=$(curl -s -L \
129- -H "Accept: application/vnd.github+json" \
130- -H "Authorization: Bearer ${{ secrets.DOCS_GITHUB_PAT }}" \
131- -H "X-GitHub-Api-Version: 2022-11-28" '${{ steps.ghpages_build.outputs.url }}' \
132- | jq -r .status)
133-
134- if [ "$build_status" == "built" ]; then echo "Deploy is complete."
135- exit 0
136- else
137- echo "Deploy is not complete. Status: $build_status. Retrying in 10 seconds..."
138- sleep 10
139- fi
140- done
141- echo "Deploy is still not complete after approximately 10 minutes."
142- exit 1
143-
144- - name : Get GitHub Pages Preview URL
146+ echo "${{ github.event.repository.full_name }}" > ${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository
147+
148+ s3_params=(
149+ # Hide upload progress for a cleaner sync log
150+ --no-progress
151+ # Because the build will produce new timestamps
152+ # on each build, sync files based on size.
153+ --size-only
154+ --delete
155+ --exclude "*"
156+ --include "${{ steps.extract_branch.outputs.draft_directory }}/*"
157+ )
158+
159+ echo "Deploying draft to S3." |& tee -a $GITHUB_WORKSPACE/deploy.log
160+ echo "aws s3 sync . s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts ${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
161+ aws s3 sync . "s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts" "${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
162+
163+ # Update .github_source_repository file metadata to mark last modified time of the draft.
164+ # This will allow us to later determine if a draft is stale and needs to be cleaned up.
165+ echo "Marking last modified time of the draft." |& tee -a $GITHUB_WORKSPACE/deploy.log
166+ echo "aws s3 cp --metadata '{\"touched\": \"now\"}' \
167+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
168+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository" \
169+ |& tee -a $GITHUB_WORKSPACE/deploy.log
170+
171+ aws s3 cp --metadata '{ "touched": "now" }' \
172+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
173+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
174+ |& tee -a $GITHUB_WORKSPACE/deploy.log
175+
176+ - name : Invalidate CloudFront Cache
145177 if : success()
146178 shell : bash
147179 run : |
148- echo "url=https://riptano.github.io/${{ github.event.repository.name }}/${{ steps.extract_branch.outputs.draft_branch }}/" >> $GITHUB_OUTPUT
149- id : draft_url
180+ invalidation_batch="{ \"Paths\": { \"Quantity\": 1, \"Items\": [\"/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/*\"] }, \"CallerReference\": \"docs-ui-draft-files-$(date +%s)\" }"
150181
151- - name : Update comment
182+ echo $invalidation_batch | jq . |& tee -a "$GITHUB_WORKSPACE/deploy.log"
183+ echo "Creating invalidation." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
184+ invalidation_id=$(aws cloudfront create-invalidation --distribution-id "${{ vars.BUNDLE_PREVIEW_CLOUD_FRONT_DISTRIBUTION_ID }}" --invalidation-batch "$invalidation_batch" --query 'Invalidation.Id' --output text |& tee -a "$GITHUB_WORKSPACE/deploy.log")
185+
186+ echo "Awaiting invalidation." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
187+ aws cloudfront wait invalidation-completed --distribution-id "${{ vars.BUNDLE_PREVIEW_CLOUD_FRONT_DISTRIBUTION_ID }}" --id "$invalidation_id" |& tee -a "$GITHUB_WORKSPACE/deploy.log"
188+ echo "Invalidation complete." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
189+
190+ - name : Update Comment
152191 if : ${{ steps.fc.outputs.comment-id != '' }}
153- uses : peter-evans/create-or-update-comment@v3
192+ uses : peter-evans/create-or-update-comment@v4
154193 with :
155- token : ${{ secrets.DOCS_GITHUB_PAT }}
156194 comment-id : ${{ steps.fc.outputs.comment-id }}
157195 body : |
158- Deployment successful! [View preview](${{ steps.draft_url.outputs.url }})
196+ Deploy successful! [View preview](${{ steps.draft_url.outputs.url }})
159197 reactions : hooray
198+
199+ - name : Upload Deploy Log
200+ uses : actions/upload-artifact@v4
201+ if : always()
202+ with :
203+ name : deploy.log
204+ path : ${{ github.workspace }}/deploy.log
0 commit comments