8
8
branches :
9
9
- ' *'
10
10
11
+ concurrency :
12
+ group : ${{ github.workflow }}-${{ github.ref }}
13
+
11
14
jobs :
12
15
build-and-deploy :
13
16
runs-on : ubuntu-latest
14
17
15
18
steps :
16
- - name : Configure Git Credentials
17
- uses : de-vri-es/setup-git-credentials@v2
18
- with :
19
- credentials : ${{ secrets.GIT_CREDENTIALS }}
20
-
21
19
- name : Checkout Repository
22
20
uses : actions/checkout@v4
23
21
@@ -26,134 +24,183 @@ jobs:
26
24
with :
27
25
node-version : 21.6.1
28
26
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 }}"
31
38
32
39
- 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
38
40
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
39
75
40
76
- name : Build UI Bundle Preview
77
+ if : success()
41
78
run : |
42
79
set -o pipefail
43
80
gulp lint |& tee $GITHUB_WORKSPACE/build.log
44
81
gulp preview:build |& tee $GITHUB_WORKSPACE/build.log
82
+ env :
83
+ NO_COLOR : 1
45
84
46
85
- name : Check Build Result
47
- id : logFail
86
+ id : buildLogFail
48
87
if : failure()
49
88
run : |
50
89
MULTILINE_LOG=$(cat $GITHUB_WORKSPACE/build.log)
51
90
echo "BUILD_FAILURE<<EOF" >> $GITHUB_ENV
52
91
echo $MULTILINE_LOG >> $GITHUB_ENV
53
92
echo "EOF" >> $GITHUB_ENV
54
93
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
+
55
104
- name : Create Build Success Comment
56
105
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
58
107
with :
59
- token : ${{ secrets.DOCS_GITHUB_PAT }}
60
108
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 }}"
64
110
reactions : rocket
65
111
66
112
- name : Create Build Failure Comment
67
113
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
69
115
with :
70
- token : ${{ secrets.DOCS_GITHUB_PAT }}
71
116
issue-number : ${{ github.event.pull_request.number }}
72
117
body : |
73
118
UI bundle preview build failure! :x:
74
119
> ${{ env.BUILD_FAILURE }}
75
120
reactions : confused
76
121
77
122
- name : Find Comment
78
- if : ${{ success() && github.event.pull_request.number }}
79
- uses : peter-evans/find-comment@v2
80
123
id : fc
124
+ if : ${{ success() && github.event.pull_request.number }}
125
+ uses : peter-evans/find-comment@v3
81
126
with :
82
- token : ${{ secrets.DOCS_GITHUB_PAT }}
83
127
issue-number : ${{ github.event.pull_request.number }}
84
128
body-includes : UI bundle preview build successful!
85
129
direction : last
86
130
87
- - name : Deploy to GitHub Pages
131
+ - name : Configure AWS CLI
88
132
if : success()
89
133
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
98
137
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
101
145
102
146
# Records the repository that originally triggered the build so we can post back
103
147
# 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
145
179
if : success()
146
180
shell : bash
147
181
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)\" }"
150
183
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
152
193
if : ${{ steps.fc.outputs.comment-id != '' }}
153
- uses : peter-evans/create-or-update-comment@v3
194
+ uses : peter-evans/create-or-update-comment@v4
154
195
with :
155
- token : ${{ secrets.DOCS_GITHUB_PAT }}
156
196
comment-id : ${{ steps.fc.outputs.comment-id }}
157
197
body : |
158
- Deployment successful! [View preview](${{ steps.draft_url.outputs.url }})
198
+ Deploy successful! [View preview](${{ steps.draft_url.outputs.url }})
159
199
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