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,187 @@ 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 : cd docs && yarn install
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
+ cd docs
83
+ yarn build |& tee $GITHUB_WORKSPACE/build.log
84
+ env :
85
+ BASE_URL : /docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}
86
+ FORCE_COLOR : 0 # Disable color output
45
87
46
88
- name : Check Build Result
47
- id : logFail
89
+ id : buildLogFail
48
90
if : failure()
49
91
run : |
50
92
MULTILINE_LOG=$(cat $GITHUB_WORKSPACE/build.log)
51
93
echo "BUILD_FAILURE<<EOF" >> $GITHUB_ENV
52
94
echo $MULTILINE_LOG >> $GITHUB_ENV
53
95
echo "EOF" >> $GITHUB_ENV
54
96
97
+ - name : Assemble Build Success Comment
98
+ if : ${{ success() && github.event.pull_request.number }}
99
+ run : |
100
+ build_success_comment="Build successful! :white_check_mark:"
101
+ build_success_comment+="\nDeploying docs draft."
102
+
103
+ echo "BUILD_SUCCESS_COMMENT<<EOF" >> $GITHUB_ENV
104
+ echo -e "$build_success_comment" >> $GITHUB_ENV
105
+ echo "EOF" >> $GITHUB_ENV
106
+
55
107
- name : Create Build Success Comment
56
108
if : ${{ success() && github.event.pull_request.number }}
57
- uses : peter-evans/create-or-update-comment@v3
109
+ uses : peter-evans/create-or-update-comment@v4
58
110
with :
59
- token : ${{ secrets.DOCS_GITHUB_PAT }}
60
111
issue-number : ${{ github.event.pull_request.number }}
61
- body : |
62
- UI bundle preview build successful! :white_check_mark:
63
- Deploying preview to GitHub Pages.
112
+ body : " ${{ env.BUILD_SUCCESS_COMMENT }}"
64
113
reactions : rocket
65
114
66
115
- name : Create Build Failure Comment
67
116
if : ${{ failure() && github.event.pull_request.number }}
68
- uses : peter-evans/create-or-update-comment@v3
117
+ uses : peter-evans/create-or-update-comment@v4
69
118
with :
70
- token : ${{ secrets.DOCS_GITHUB_PAT }}
71
119
issue-number : ${{ github.event.pull_request.number }}
72
120
body : |
73
121
UI bundle preview build failure! :x:
74
122
> ${{ env.BUILD_FAILURE }}
75
123
reactions : confused
76
124
77
125
- name : Find Comment
78
- if : ${{ success() && github.event.pull_request.number }}
79
- uses : peter-evans/find-comment@v2
80
126
id : fc
127
+ if : ${{ success() && github.event.pull_request.number }}
128
+ uses : peter-evans/find-comment@v3
81
129
with :
82
- token : ${{ secrets.DOCS_GITHUB_PAT }}
83
130
issue-number : ${{ github.event.pull_request.number }}
84
131
body-includes : UI bundle preview build successful!
85
132
direction : last
86
133
87
- - name : Deploy to GitHub Pages
134
+ - name : Configure AWS CLI
88
135
if : success()
89
136
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 }}
137
+ aws configure set aws_access_key_id ${{ secrets.DOCS_UI_AWS_ACCESS_KEY_ID }}
138
+ aws configure set aws_secret_access_key ${{ secrets.DOCS_UI_AWS_SECRET_ACCESS_KEY }}
139
+ aws configure set region us-west-2
98
140
99
- mkdir -p ${{ steps.extract_branch.outputs.draft_branch }}
100
- cp -r ../public/* ${{ steps.extract_branch.outputs.draft_branch }}/.
141
+ - name : Deploy to S3
142
+ if : success()
143
+ run : |
144
+ set -o pipefail
145
+ cd docs
146
+ mkdir docs-ui-drafts
147
+ mv build docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}
148
+ cd docs-ui-drafts
101
149
102
150
# Records the repository that originally triggered the build so we can post back
103
151
# 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
152
+ echo "${{ github.event.repository.full_name }}" > ${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository
153
+
154
+ s3_params=(
155
+ # Hide upload progress for a cleaner sync log
156
+ --no-progress
157
+ # Because the build will produce new timestamps
158
+ # on each build, sync files based on size.
159
+ --size-only
160
+ --delete
161
+ --exclude "*"
162
+ --include "${{ steps.extract_branch.outputs.draft_directory }}/*"
163
+ )
164
+
165
+ echo "Deploying draft to S3." |& tee -a $GITHUB_WORKSPACE/deploy.log
166
+ echo "aws s3 sync . s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts ${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
167
+ aws s3 sync . "s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/docs-ui-drafts" "${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
168
+
169
+ # Update .github_source_repository file metadata to mark last modified time of the draft.
170
+ # This will allow us to later determine if a draft is stale and needs to be cleaned up.
171
+ echo "Marking last modified time of the draft." |& tee -a $GITHUB_WORKSPACE/deploy.log
172
+ echo "aws s3 cp --metadata '{\"touched\": \"now\"}' \
173
+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
174
+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository" \
175
+ |& tee -a $GITHUB_WORKSPACE/deploy.log
176
+
177
+ aws s3 cp --metadata '{ "touched": "now" }' \
178
+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
179
+ s3://${{ vars.BUNDLE_PREVIEW_S3_BUCKET_NAME }}/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
180
+ |& tee -a $GITHUB_WORKSPACE/deploy.log
181
+
182
+ - name : Invalidate CloudFront Cache
145
183
if : success()
146
184
shell : bash
147
185
run : |
148
- echo "url=https://riptano.github.io/${{ github.event.repository.name }}/${{ steps.extract_branch.outputs.draft_branch }}/" >> $GITHUB_OUTPUT
149
- id : draft_url
186
+ invalidation_batch="{ \"Paths\": { \"Quantity\": 1, \"Items\": [\"/docs-ui-drafts/${{ steps.extract_branch.outputs.draft_directory }}/*\"] }, \"CallerReference\": \"docs-ui-draft-files-$(date +%s)\" }"
150
187
151
- - name : Update comment
188
+ echo $invalidation_batch | jq . |& tee -a "$GITHUB_WORKSPACE/deploy.log"
189
+ echo "Creating invalidation." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
190
+ 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")
191
+
192
+ echo "Awaiting invalidation." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
193
+ aws cloudfront wait invalidation-completed --distribution-id "${{ vars.BUNDLE_PREVIEW_CLOUD_FRONT_DISTRIBUTION_ID }}" --id "$invalidation_id" |& tee -a "$GITHUB_WORKSPACE/deploy.log"
194
+ echo "Invalidation complete." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
195
+
196
+ - name : Update Comment
152
197
if : ${{ steps.fc.outputs.comment-id != '' }}
153
- uses : peter-evans/create-or-update-comment@v3
198
+ uses : peter-evans/create-or-update-comment@v4
154
199
with :
155
- token : ${{ secrets.DOCS_GITHUB_PAT }}
156
200
comment-id : ${{ steps.fc.outputs.comment-id }}
157
201
body : |
158
- Deployment successful! [View preview](${{ steps.draft_url.outputs.url }})
202
+ Deploy successful! [View preview](${{ steps.draft_url.outputs.url }})
159
203
reactions : hooray
204
+
205
+ - name : Upload Deploy Log
206
+ uses : actions/upload-artifact@v4
207
+ if : always()
208
+ with :
209
+ name : deploy.log
210
+ path : ${{ github.workspace }}/deploy.log
0 commit comments