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,181 @@ 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
45
82
46
83
- name : Check Build Result
47
- id : logFail
84
+ id : buildLogFail
48
85
if : failure()
49
86
run : |
50
87
MULTILINE_LOG=$(cat $GITHUB_WORKSPACE/build.log)
51
88
echo "BUILD_FAILURE<<EOF" >> $GITHUB_ENV
52
89
echo $MULTILINE_LOG >> $GITHUB_ENV
53
90
echo "EOF" >> $GITHUB_ENV
54
91
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
+
55
102
- name : Create Build Success Comment
56
103
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
58
105
with :
59
- token : ${{ secrets.DOCS_GITHUB_PAT }}
60
106
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 }}"
64
108
reactions : rocket
65
109
66
110
- name : Create Build Failure Comment
67
111
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
69
113
with :
70
- token : ${{ secrets.DOCS_GITHUB_PAT }}
71
114
issue-number : ${{ github.event.pull_request.number }}
72
115
body : |
73
116
UI bundle preview build failure! :x:
74
117
> ${{ env.BUILD_FAILURE }}
75
118
reactions : confused
76
119
77
120
- name : Find Comment
78
- if : ${{ success() && github.event.pull_request.number }}
79
- uses : peter-evans/find-comment@v2
80
121
id : fc
122
+ if : ${{ success() && github.event.pull_request.number }}
123
+ uses : peter-evans/find-comment@v3
81
124
with :
82
- token : ${{ secrets.DOCS_GITHUB_PAT }}
83
125
issue-number : ${{ github.event.pull_request.number }}
84
126
body-includes : UI bundle preview build successful!
85
127
direction : last
86
128
87
- - name : Deploy to GitHub Pages
129
+ - name : Configure AWS CLI
88
130
if : success()
89
131
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
98
135
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
101
143
102
144
# Records the repository that originally triggered the build so we can post back
103
145
# 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
145
177
if : success()
146
178
shell : bash
147
179
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)\" }"
150
181
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
152
191
if : ${{ steps.fc.outputs.comment-id != '' }}
153
- uses : peter-evans/create-or-update-comment@v3
192
+ uses : peter-evans/create-or-update-comment@v4
154
193
with :
155
- token : ${{ secrets.DOCS_GITHUB_PAT }}
156
194
comment-id : ${{ steps.fc.outputs.comment-id }}
157
195
body : |
158
- Deployment successful! [View preview](${{ steps.draft_url.outputs.url }})
196
+ Deploy successful! [View preview](${{ steps.draft_url.outputs.url }})
159
197
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