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,183 @@ 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
82+ env :
83+ NO_COLOR : 1
4584
4685 - name : Check Build Result
47- id : logFail
86+ id : buildLogFail
4887 if : failure()
4988 run : |
5089 MULTILINE_LOG=$(cat $GITHUB_WORKSPACE/build.log)
5190 echo "BUILD_FAILURE<<EOF" >> $GITHUB_ENV
5291 echo $MULTILINE_LOG >> $GITHUB_ENV
5392 echo "EOF" >> $GITHUB_ENV
5493
94+ - name : Assemble Build Success Comment
95+ if : ${{ success() && github.event.pull_request.number }}
96+ run : |
97+ build_success_comment="UI bundle preview build successful! :white_check_mark:"
98+ build_success_comment+="\nDeploying bundle preview."
99+
100+ echo "BUILD_SUCCESS_COMMENT<<EOF" >> $GITHUB_ENV
101+ echo -e "$build_success_comment" >> $GITHUB_ENV
102+ echo "EOF" >> $GITHUB_ENV
103+
55104 - name : Create Build Success Comment
56105 if : ${{ success() && github.event.pull_request.number }}
57- uses : peter-evans/create-or-update-comment@v3
106+ uses : peter-evans/create-or-update-comment@v4
58107 with :
59- token : ${{ secrets.DOCS_GITHUB_PAT }}
60108 issue-number : ${{ github.event.pull_request.number }}
61- body : |
62- UI bundle preview build successful! :white_check_mark:
63- Deploying preview to GitHub Pages.
109+ body : " ${{ env.BUILD_SUCCESS_COMMENT }}"
64110 reactions : rocket
65111
66112 - name : Create Build Failure Comment
67113 if : ${{ failure() && github.event.pull_request.number }}
68- uses : peter-evans/create-or-update-comment@v3
114+ uses : peter-evans/create-or-update-comment@v4
69115 with :
70- token : ${{ secrets.DOCS_GITHUB_PAT }}
71116 issue-number : ${{ github.event.pull_request.number }}
72117 body : |
73118 UI bundle preview build failure! :x:
74119 > ${{ env.BUILD_FAILURE }}
75120 reactions : confused
76121
77122 - name : Find Comment
78- if : ${{ success() && github.event.pull_request.number }}
79- uses : peter-evans/find-comment@v2
80123 id : fc
124+ if : ${{ success() && github.event.pull_request.number }}
125+ uses : peter-evans/find-comment@v3
81126 with :
82- token : ${{ secrets.DOCS_GITHUB_PAT }}
83127 issue-number : ${{ github.event.pull_request.number }}
84128 body-includes : UI bundle preview build successful!
85129 direction : last
86130
87- - name : Deploy to GitHub Pages
131+ - name : Configure AWS CLI
88132 if : success()
89133 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 }}
134+ aws configure set aws_access_key_id ${{ secrets.DOCS_UI_AWS_ACCESS_KEY_ID }}
135+ aws configure set aws_secret_access_key ${{ secrets.DOCS_UI_AWS_SECRET_ACCESS_KEY }}
136+ aws configure set region us-west-2
98137
99- mkdir -p ${{ steps.extract_branch.outputs.draft_branch }}
100- cp -r ../public/* ${{ steps.extract_branch.outputs.draft_branch }}/.
138+ - name : Deploy to S3
139+ if : success()
140+ run : |
141+ set -o pipefail
142+ mkdir docs-ui-drafts
143+ mv public docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}
144+ cd docs-ui-drafts
101145
102146 # Records the repository that originally triggered the build so we can post back
103147 # 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
148+ echo "${{ github.event.repository.full_name }}" > ${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository
149+
150+ s3_params=(
151+ # Hide upload progress for a cleaner sync log
152+ --no-progress
153+ # Because the build will produce new timestamps
154+ # on each build, sync files based on size.
155+ --size-only
156+ --delete
157+ --exclude "*"
158+ --include "${{ steps.extract_branch.outputs.draft_directory }}/*"
159+ )
160+
161+ echo "Deploying draft to S3." |& tee -a $GITHUB_WORKSPACE/deploy.log
162+ echo "aws s3 sync . s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts ${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
163+ aws s3 sync . "s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts" "${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
164+
165+ # Update .github_source_repository file metadata to mark last modified time of the draft.
166+ # This will allow us to later determine if a draft is stale and needs to be cleaned up.
167+ echo "Marking last modified time of the draft." |& tee -a $GITHUB_WORKSPACE/deploy.log
168+ echo "aws s3 cp --metadata '{\"touched\": \"now\"}' \
169+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
170+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository" \
171+ |& tee -a $GITHUB_WORKSPACE/deploy.log
172+
173+ aws s3 cp --metadata '{ "touched": "now" }' \
174+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
175+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
176+ |& tee -a $GITHUB_WORKSPACE/deploy.log
177+
178+ - name : Invalidate CloudFront Cache
145179 if : success()
146180 shell : bash
147181 run : |
148- echo "url=https://riptano.github.io/${{ github.event.repository.name }}/${{ steps.extract_branch.outputs.draft_branch }}/" >> $GITHUB_OUTPUT
149- id : draft_url
182+ invalidation_batch="{ \"Paths\": { \"Quantity\": 1, \"Items\": [\"/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/*\"] }, \"CallerReference\": \"docs-ui-draft-files-$(date +%s)\" }"
150183
151- - name : Update comment
184+ echo $invalidation_batch | jq . |& tee -a "$GITHUB_WORKSPACE/deploy.log"
185+ echo "Creating invalidation." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
186+ 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")
187+
188+ echo "Awaiting invalidation." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
189+ aws cloudfront wait invalidation-completed --distribution-id "${{ vars.BUNDLE_PREVIEW_CLOUD_FRONT_DISTRIBUTION_ID }}" --id "$invalidation_id" |& tee -a "$GITHUB_WORKSPACE/deploy.log"
190+ echo "Invalidation complete." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
191+
192+ - name : Update Comment
152193 if : ${{ steps.fc.outputs.comment-id != '' }}
153- uses : peter-evans/create-or-update-comment@v3
194+ uses : peter-evans/create-or-update-comment@v4
154195 with :
155- token : ${{ secrets.DOCS_GITHUB_PAT }}
156196 comment-id : ${{ steps.fc.outputs.comment-id }}
157197 body : |
158- Deployment successful! [View preview](${{ steps.draft_url.outputs.url }})
198+ Deploy successful! [View preview](${{ steps.draft_url.outputs.url }})
159199 reactions : hooray
200+
201+ - name : Upload Deploy Log
202+ uses : actions/upload-artifact@v4
203+ if : always()
204+ with :
205+ name : deploy.log
206+ path : ${{ github.workspace }}/deploy.log
0 commit comments