Skip to content

Commit d4d0ed0

Browse files
authored
Initial commit with clean copy of docs-build-push.yml as docs-build-push-aws.yml
This workflow will the building and deployment of documentation using Hugo or Sphinx, with support for AWS integration and PR previews.
1 parent ba2b0c3 commit d4d0ed0

File tree

1 file changed

+377
-0
lines changed

1 file changed

+377
-0
lines changed
Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
name: Docs Build Push
2+
3+
on:
4+
workflow_call:
5+
secrets:
6+
AZURE_CREDENTIALS:
7+
required: true
8+
AZURE_KEY_VAULT:
9+
required: true
10+
inputs:
11+
environment:
12+
description: "This will be appended to the baseURL for for production builds. For example, main docs will be `/` where agent would be `/nginx-agent`"
13+
required: false
14+
default: preview
15+
type: string
16+
production_url_path:
17+
description: "This will be appended to the baseURL for for production builds. For example, main docs will be `/` where agent would be `/nginx-agent`"
18+
required: true
19+
type: string
20+
preview_url_path:
21+
description: "Appended to the baseURL for PR preview builds"
22+
required: true
23+
type: string
24+
docs_source_path:
25+
description: "Directory of built docs files. Hugo default would be `./public/`"
26+
required: true
27+
type: string
28+
docs_build_path:
29+
description: "Directory where hugo or sphinx build command should be run from"
30+
required: false
31+
type: string
32+
default: ./
33+
doc_type:
34+
type: string
35+
description: "Type of source docs. Currently supports 'hugo' and 'sphinx'"
36+
default: hugo
37+
force_hugo_theme_version:
38+
type: string
39+
description: "Overrides default of latest hugo theme. Useful for testing pre-release versions. Must start with 'v' before version."
40+
default: ""
41+
auto_deploy_branch:
42+
type: string
43+
description: "A branch specified here will autodeploy to the environment specified in auto_deploy_env. An on.push event for this branch must be specified in caller."
44+
auto_deploy_env:
45+
type: string
46+
description: "Env to which auto_deploy_branch will be deployed to. Preview is not supported."
47+
node_dep:
48+
type: boolean
49+
description: "Defines should we run npm ci or not"
50+
outputs:
51+
PREVIEW_URL:
52+
description: String representing the URL to preview the build
53+
value: ${{ jobs.build.outputs.PREVIEW_URL }}
54+
env:
55+
GO_VERISON: "1.21" # Go version used for `hugo mod get`
56+
HUGO_VERSION: "0.147.8" # Hugo version used for building docs
57+
THEME_MODULE: "github.com/nginxinc/nginx-hugo-theme" # Name of source repo for module. For example; github.com/nginxinc/nginx-hugo-theme
58+
59+
PR_NUMBER: ${{github.event.pull_request.number}}
60+
61+
# environments
62+
DOMAIN_PREVIEW: "frontdoor-test-docs.nginx.com"
63+
DOMAIN_DEV: "docs-dev.nginx.com"
64+
DOMAIN_STAGING: "docs-staging.nginx.com"
65+
DOMAIN_PROD: "docs.nginx.com"
66+
DOMAIN_UNIT: "unit.nginx.org"
67+
68+
jobs:
69+
checks:
70+
name: Checks and variables
71+
runs-on: ubuntu-24.04
72+
permissions:
73+
contents: read
74+
outputs:
75+
forked_workflow: ${{ steps.vars.outputs.forked_workflow }}
76+
steps:
77+
- name: Checkout Repository
78+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
79+
80+
- name: Set Variables
81+
id: vars
82+
run: |
83+
echo "forked_workflow=${{ (github.event.pull_request && github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) || !(startsWith(github.repository, 'nginx/') || startsWith(github.repository, 'nginxinc/')) }}" >> $GITHUB_OUTPUT
84+
- name: Output variables
85+
run: |
86+
echo forked_workflow: ${{ steps.vars.outputs.forked_workflow }}
87+
build:
88+
needs: [checks]
89+
if: ${{ needs.checks.outputs.forked_workflow == 'false' }}
90+
runs-on: ubuntu-24.04
91+
outputs:
92+
PREVIEW_URL: ${{ steps.summary.outputs.PREVIEW_URL }}
93+
env:
94+
# Remapping of inputs to envs
95+
PRODUCTION_URL_PATH: ${{inputs.production_url_path}}
96+
PREVIEW_URL_PATH: ${{inputs.preview_url_path}}
97+
DOCS_SOURCE_PATH: ${{inputs.docs_source_path}}
98+
EVENT_ACTION: ${{github.event.action}}
99+
DEPLOYMENT_ENV: ${{inputs.environment}}
100+
THEME_VERSION: ${{inputs.force_hugo_theme_version}}
101+
AUTO_DEPLOY_BRANCH: ${{inputs.auto_deploy_branch}}
102+
AUTO_DEPLOY_ENV: ${{inputs.auto_deploy_env}}
103+
104+
concurrency:
105+
group: ${{ github.workflow }}-${{ github.ref }}
106+
steps:
107+
- name: Check and setup auto-deploy
108+
# Auto deploy should only trigger when the auto_deploy_branch match the current ref.
109+
# We also check if `environment` has already been set, otherwise this flow could cause
110+
# manual triggers to deploy to `auto_deploy_env` instead of the one specified in the trigger.
111+
if: (inputs.auto_deploy_branch == github.ref_name) && inputs.environment == ''
112+
run: |
113+
echo "Auto deploy branch ($AUTO_DEPLOY_BRANCH) matches current branch. Attempting autodeploy to $AUTO_DEPLOY_ENV."
114+
echo "DEPLOYMENT_ENV=${AUTO_DEPLOY_ENV}" >> $GITHUB_ENV
115+
116+
- name: Validate environment inputs
117+
run: |
118+
if [[ -z "${DEPLOYMENT_ENV}" ]]; then
119+
# for use in this step
120+
export DEPLOYMENT_ENV="preview"
121+
122+
# for use in subsequent steps
123+
echo "DEPLOYMENT_ENV=preview" >> "$GITHUB_ENV"
124+
fi
125+
126+
if [[ ! "${DEPLOYMENT_ENV}" =~ ^(dev|staging|prod|preview)$ ]]; then
127+
echo "::error::Invalid environment input: ${DEPLOYMENT_ENV}. Must be one of dev, staging, prod, preview"
128+
exit 1
129+
fi
130+
131+
if [[ "${DEPLOYMENT_ENV}" == "preview" && -z "${PR_NUMBER}" ]]; then
132+
echo "PR_NUMBER=${GITHUB_SHA::7}" >> "$GITHUB_ENV"
133+
echo "::notice::PR_NUMBER set to short commit hash: ${GITHUB_SHA::7}"
134+
fi
135+
136+
if [[ -z "${GITHUB_SHA}" ]]; then
137+
echo "::error::GITHUB_SHA not set. This shouldn't happen!"
138+
exit 1
139+
fi
140+
141+
- name: Set deployment domain
142+
id: deployment
143+
run: |
144+
case ${DEPLOYMENT_ENV}/${{github.repository}} in
145+
dev/*)
146+
DOMAIN="${DOMAIN_DEV}"
147+
;;
148+
staging/*)
149+
DOMAIN="${DOMAIN_STAGING}"
150+
;;
151+
prod/nginx/unit-docs)
152+
DOMAIN="${DOMAIN_UNIT}"
153+
;;
154+
prod/*)
155+
DOMAIN="${DOMAIN_PROD}"
156+
;;
157+
preview/*)
158+
DOMAIN="${DOMAIN_PREVIEW}"
159+
;;
160+
esac
161+
162+
echo "DEPLOYMENT_DOMAIN=${DOMAIN}" >> $GITHUB_ENV
163+
164+
- name: Azure login
165+
uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0
166+
with:
167+
creds: ${{ secrets.AZURE_CREDENTIALS }}
168+
169+
- name: Retrieve secrets from Keyvault
170+
id: keyvault
171+
uses: azure/cli@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0
172+
with:
173+
inlineScript: |
174+
secrets_get=(resourceGroupName cdnProfileName cdnName accountName)
175+
for secret_get in ${secrets_get[@]}
176+
do
177+
value=$(az keyvault secret show --name $secret_get --vault-name ${{ secrets.AZURE_KEY_VAULT }} --query value --output tsv)
178+
echo "::add-mask::$value"
179+
echo "$secret_get=$value" >> $GITHUB_OUTPUT
180+
done
181+
182+
- name: Checkout docs content
183+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.7.1
184+
with:
185+
fetch-depth: 0 # This is required for hugo Lastmod to function properly
186+
187+
- name: Get latest hugo theme
188+
if: inputs.doc_type == 'hugo' && inputs.force_hugo_theme_version == ''
189+
run: |
190+
RESPONSE=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/nginxinc/nginx-hugo-theme/releases/latest)
191+
echo $RESPONSE
192+
echo "THEME_VERSION=$(echo $RESPONSE | jq -r ".tag_name")" >> "$GITHUB_ENV"
193+
194+
### Hugo builds
195+
196+
- name: Setup Go
197+
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
198+
if: inputs.doc_type == 'hugo'
199+
with:
200+
go-version: ${{env.GO_VERISON}}
201+
cache: false
202+
203+
- name: Setup Hugo
204+
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0
205+
if: inputs.doc_type == 'hugo'
206+
with:
207+
hugo-version: ${{env.HUGO_VERSION}}
208+
extended: true
209+
210+
- name: Add hugo build info
211+
if: inputs.doc_type == 'hugo'
212+
run: |
213+
timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
214+
cat <<EOF > buildInfo.json
215+
{
216+
"nginxHugoThemeVersion": "$THEME_MODULE@$THEME_VERSION",
217+
"buildDate": "$timestamp"
218+
}
219+
EOF
220+
mkdir -p ${{inputs.docs_build_path}}/static/
221+
cp buildInfo.json ${{inputs.docs_build_path}}/static/
222+
223+
- name: Setup node deps
224+
if: inputs.node_dep == true
225+
run: npm ci
226+
227+
- name: Build Hugo for PR preview
228+
if: inputs.doc_type == 'hugo' && (github.event.action == 'synchronize' || github.event.action == 'opened' || env.DEPLOYMENT_ENV == 'preview')
229+
working-directory: ${{inputs.docs_build_path}}
230+
run: |
231+
hugo mod get -v "$THEME_MODULE@$THEME_VERSION"
232+
hugo --gc -e production --baseURL="https://${DEPLOYMENT_DOMAIN}${PREVIEW_URL_PATH}/${PR_NUMBER}"
233+
234+
- name: Build Hugo for environment
235+
working-directory: ${{inputs.docs_build_path}}
236+
if: inputs.doc_type == 'hugo' && env.DEPLOYMENT_ENV != 'preview'
237+
run: |
238+
hugo mod get "$THEME_MODULE@$THEME_VERSION"
239+
hugo --gc -e production --baseURL="https://${DEPLOYMENT_DOMAIN}${PRODUCTION_URL_PATH}"
240+
241+
### Sphinx builds
242+
243+
- name: Setup Sphinx
244+
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
245+
if: inputs.doc_type == 'sphinx'
246+
with:
247+
python-version: "3.9"
248+
249+
- name: Install python dependencies
250+
if: inputs.doc_type == 'sphinx'
251+
run: pip install -r requirements.txt
252+
253+
- name: Setup Gnupg directories
254+
if: inputs.doc_type == 'sphinx'
255+
run: |
256+
mkdir -p /home/runner/.gnupg
257+
chmod 700 /home/runner/.gnupg
258+
259+
- name: Build Sphinx for PR preview and production
260+
working-directory: ${{inputs.docs_build_path}}
261+
if: inputs.doc_type == 'sphinx'
262+
run: |
263+
make deploy
264+
265+
### Azure upload
266+
267+
- name: Azure upload PR preview
268+
uses: azure/cli@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0
269+
if: github.event.action == 'synchronize' || github.event.action == 'opened' || env.DEPLOYMENT_ENV == 'preview'
270+
with:
271+
inlineScript: |
272+
cd ${{inputs.docs_build_path}} \
273+
&& az storage blob upload-batch \
274+
-s $DOCS_SOURCE_PATH \
275+
-d '$web' \
276+
--destination-path "dev/${{github.repository}}/previews/${PR_NUMBER}" \
277+
--account-name ${{steps.keyvault.outputs.accountName}} \
278+
--overwrite \
279+
--content-cache-control "max-age=3600" \
280+
--auth-mode login
281+
282+
az afd endpoint purge \
283+
--resource-group ${{steps.keyvault.outputs.resourceGroupName}} \
284+
--profile-name ${{steps.keyvault.outputs.cdnProfileName}} \
285+
--endpoint-name ${{steps.keyvault.outputs.cdnName}} \
286+
--domains $DOMAIN_PREVIEW \
287+
--content-paths "${PREVIEW_URL_PATH}/*" \
288+
--no-wait
289+
290+
- name: Azure upload to specified environment
291+
uses: azure/cli@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0
292+
if: env.DEPLOYMENT_ENV != 'preview'
293+
with:
294+
inlineScript: |
295+
cd ${{inputs.docs_build_path}} \
296+
&& az storage blob upload-batch \
297+
-s $DOCS_SOURCE_PATH \
298+
-d '$web' \
299+
--destination-path "${DEPLOYMENT_ENV}/${{github.repository}}/latest/" \
300+
--account-name ${{steps.keyvault.outputs.accountName}} \
301+
--overwrite \
302+
--content-cache-control "max-age=3600" \
303+
--auth-mode login
304+
305+
az afd endpoint purge \
306+
--resource-group ${{steps.keyvault.outputs.resourceGroupName}} \
307+
--profile-name ${{steps.keyvault.outputs.cdnProfileName}} \
308+
--endpoint-name ${{steps.keyvault.outputs.cdnName}} \
309+
--domains $DEPLOYMENT_DOMAIN \
310+
--content-paths "${PRODUCTION_URL_PATH}/*" \
311+
--no-wait
312+
313+
- name: Azure logout
314+
run: |
315+
az logout
316+
if: always()
317+
318+
### PR preview comment
319+
320+
- name: PR preview comment
321+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
322+
if: env.DEPLOYMENT_ENV == 'preview' && (github.event.action == 'synchronize' || github.event.action == 'opened')
323+
with:
324+
script: |
325+
// If a comment already exists, skip
326+
const { data: comments } = await github.rest.issues.listComments({
327+
issue_number: context.issue.number,
328+
owner: context.repo.owner,
329+
repo: context.repo.repo,
330+
});
331+
332+
const existingComment = comments.find(comment => comment.user.login === 'github-actions[bot]' && comment.body.includes('Deploy Preview'));
333+
334+
if (existingComment) {
335+
core.info('Preview comment already exists. Skipping...');
336+
return;
337+
}
338+
339+
const previewHostname = process.env.DOMAIN_PREVIEW;
340+
const previewUrlPath = process.env.PREVIEW_URL_PATH;
341+
const prNumber = context.payload.pull_request.number;
342+
343+
const previewUrl = `https://${previewHostname}${previewUrlPath}/${prNumber}/`;
344+
345+
const body = `### <span aria-hidden="true">✅</span> Deploy Preview will be available once build job completes!
346+
347+
| Name | Link |
348+
|:-:|------------------------|
349+
|<span aria-hidden="true">😎</span> Deploy Preview | [${previewUrl}](${previewUrl}) |
350+
---`;
351+
352+
await github.rest.issues.createComment({
353+
issue_number: context.issue.number,
354+
owner: context.repo.owner,
355+
repo: context.repo.repo,
356+
body: body,
357+
});
358+
359+
- name: Summary
360+
# TODO(dani): Extract this into a reusable Markdown template for comments and summaries?
361+
id: summary
362+
run: |
363+
echo "### Deployment Summary" >> $GITHUB_STEP_SUMMARY
364+
echo "" >> $GITHUB_STEP_SUMMARY
365+
echo "| Task | Result |" >> $GITHUB_STEP_SUMMARY
366+
echo "|---|---|" >> $GITHUB_STEP_SUMMARY
367+
echo "| Deployment environment | \`${DEPLOYMENT_ENV}\`|" >> $GITHUB_STEP_SUMMARY
368+
if [[ "${DEPLOYMENT_ENV}" == "preview" ]]; then
369+
echo "| Preview URL | [https://${DOMAIN_PREVIEW}${PREVIEW_URL_PATH}/${PR_NUMBER}/](https://${DOMAIN_PREVIEW}${PREVIEW_URL_PATH}/${PR_NUMBER}/) |" >> $GITHUB_STEP_SUMMARY
370+
echo "PREVIEW_URL=https://${DOMAIN_PREVIEW}${PREVIEW_URL_PATH}/${PR_NUMBER}/" >> $GITHUB_OUTPUT
371+
else
372+
echo "| Production URL | [https://${DEPLOYMENT_DOMAIN}${PRODUCTION_URL_PATH}](https://${DEPLOYMENT_DOMAIN}${PRODUCTION_URL_PATH}) |" >> $GITHUB_STEP_SUMMARY
373+
echo "PREVIEW_URL=https://${DEPLOYMENT_DOMAIN}${PRODUCTION_URL_PATH}" >> $GITHUB_OUTPUT
374+
fi
375+
376+
377+
# TODO(dani): Add more details to the summary

0 commit comments

Comments
 (0)