diff --git a/.github/workflows/docs-build-push.yml b/.github/workflows/docs-build-push.yml index cd423a6..785af18 100644 --- a/.github/workflows/docs-build-push.yml +++ b/.github/workflows/docs-build-push.yml @@ -1,5 +1,4 @@ name: Docs Build Push - on: workflow_call: secrets: @@ -9,12 +8,12 @@ on: required: true inputs: environment: - description: "This will be appended to the baseURL for for production builds. For example, main docs will be `/` where agent would be `/nginx-agent`" + description: "Deployment environment. Must be one of: preview, dev, staging, prod, staging_techdocs, prod_techdocs" required: false default: preview type: string production_url_path: - description: "This will be appended to the baseURL for for production builds. For example, main docs will be `/` where agent would be `/nginx-agent`" + description: "This will be appended to the baseURL for production builds. For example, main docs will be `/` where agent would be `/nginx-agent`" required: true type: string preview_url_path: @@ -26,14 +25,10 @@ on: required: true type: string docs_build_path: - description: "Directory where hugo or sphinx build command should be run from" + description: "Directory where hugo build command should be run from" required: false type: string default: ./ - doc_type: - type: string - description: "Type of source docs. Currently supports 'hugo' and 'sphinx'" - default: hugo force_hugo_theme_version: type: string description: "Overrides default of latest hugo theme. Useful for testing pre-release versions. Must start with 'v' before version." @@ -47,23 +42,28 @@ on: node_dep: type: boolean description: "Defines should we run npm ci or not" + default: false outputs: + DEPLOY_URL: + description: String representing the URL of the deployed build (preview or environment) + value: ${{ jobs.build.outputs.DEPLOY_URL }} PREVIEW_URL: - description: String representing the URL to preview the build + description: String representing the URL to preview the build (only meaningful for preview deployments) value: ${{ jobs.build.outputs.PREVIEW_URL }} + env: - GO_VERISON: "1.21" # Go version used for `hugo mod get` + GO_VERSION: "1.21" # Go version used for `hugo mod get` HUGO_VERSION: "0.147.8" # Hugo version used for building docs - THEME_MODULE: "github.com/nginxinc/nginx-hugo-theme/v2" # Name of source repo for module. For example; github.com/nginxinc/nginx-hugo-theme + THEME_MODULE: "github.com/nginxinc/nginx-hugo-theme/v2" + PR_NUMBER: ${{ github.event.pull_request.number }} - PR_NUMBER: ${{github.event.pull_request.number}} - - # environments + # domains DOMAIN_PREVIEW: "frontdoor-test-docs.nginx.com" DOMAIN_DEV: "docs-dev.nginx.com" DOMAIN_STAGING: "docs-staging.nginx.com" DOMAIN_PROD: "docs.nginx.com" - DOMAIN_UNIT: "unit.nginx.org" + DOMAIN_STAGING_TECHDOCS: "staging.techdocs.f5.com" + DOMAIN_PROD_TECHDOCS: "techdocs.f5.com" jobs: checks: @@ -76,7 +76,6 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Set Variables id: vars run: | @@ -84,28 +83,28 @@ jobs: - name: Output variables run: | echo forked_workflow: ${{ steps.vars.outputs.forked_workflow }} + build: needs: [checks] if: ${{ needs.checks.outputs.forked_workflow == 'false' }} runs-on: ubuntu-24.04 - outputs: + outputs: + DEPLOY_URL: ${{ steps.summary.outputs.DEPLOY_URL }} PREVIEW_URL: ${{ steps.summary.outputs.PREVIEW_URL }} env: # Remapping of inputs to envs - PRODUCTION_URL_PATH: ${{inputs.production_url_path}} - PREVIEW_URL_PATH: ${{inputs.preview_url_path}} - DOCS_SOURCE_PATH: ${{inputs.docs_source_path}} - EVENT_ACTION: ${{github.event.action}} - DEPLOYMENT_ENV: ${{inputs.environment}} - THEME_VERSION: ${{inputs.force_hugo_theme_version}} - AUTO_DEPLOY_BRANCH: ${{inputs.auto_deploy_branch}} - AUTO_DEPLOY_ENV: ${{inputs.auto_deploy_env}} - + PRODUCTION_URL_PATH: ${{ inputs.production_url_path }} + PREVIEW_URL_PATH: ${{ inputs.preview_url_path }} + DOCS_SOURCE_PATH: ${{ inputs.docs_source_path }} + DEPLOYMENT_ENV: ${{ inputs.environment }} + THEME_VERSION: ${{ inputs.force_hugo_theme_version }} + AUTO_DEPLOY_BRANCH: ${{ inputs.auto_deploy_branch }} + AUTO_DEPLOY_ENV: ${{ inputs.auto_deploy_env }} concurrency: group: ${{ github.workflow }}-${{ github.ref }} steps: - name: Check and setup auto-deploy - # Auto deploy should only trigger when the auto_deploy_branch match the current ref. + # Auto deploy should only trigger when the auto_deploy_branch matches the current ref. # We also check if `environment` has already been set, otherwise this flow could cause # manual triggers to deploy to `auto_deploy_env` instead of the one specified in the trigger. if: (inputs.auto_deploy_branch == github.ref_name) && inputs.environment == '' @@ -115,16 +114,8 @@ jobs: - name: Validate environment inputs run: | - if [[ -z "${DEPLOYMENT_ENV}" ]]; then - # for use in this step - export DEPLOYMENT_ENV="preview" - - # for use in subsequent steps - echo "DEPLOYMENT_ENV=preview" >> "$GITHUB_ENV" - fi - - if [[ ! "${DEPLOYMENT_ENV}" =~ ^(dev|staging|prod|preview)$ ]]; then - echo "::error::Invalid environment input: ${DEPLOYMENT_ENV}. Must be one of dev, staging, prod, preview" + if [[ ! "${DEPLOYMENT_ENV}" =~ ^(dev|staging|prod|preview|staging_techdocs|prod_techdocs)$ ]]; then + echo "::error::Invalid environment input: ${DEPLOYMENT_ENV}. Must be one of dev, staging, prod, preview, staging_techdocs, prod_techdocs" exit 1 fi @@ -133,33 +124,50 @@ jobs: echo "::notice::PR_NUMBER set to short commit hash: ${GITHUB_SHA::7}" fi - if [[ -z "${GITHUB_SHA}" ]]; then - echo "::error::GITHUB_SHA not set. This shouldn't happen!" - exit 1 - fi - - - name: Set deployment domain + - name: Set deployment variables id: deployment run: | - case ${DEPLOYMENT_ENV}/${{github.repository}} in - dev/*) + # Compute preview state once (used for build/upload/comment) + if [[ "${DEPLOYMENT_ENV}" == "preview" ]] || [[ "${{ github.event.action }}" == "opened" ]] || [[ "${{ github.event.action }}" == "synchronize" ]]; then + echo "IS_PREVIEW=true" >> "$GITHUB_ENV" + else + echo "IS_PREVIEW=false" >> "$GITHUB_ENV" + fi + + # Map environment -> domain + storage prefix + case "${DEPLOYMENT_ENV}" in + dev) DOMAIN="${DOMAIN_DEV}" + STORAGE_PREFIX="dev" ;; - staging/*) + staging) DOMAIN="${DOMAIN_STAGING}" + STORAGE_PREFIX="staging" ;; - prod/nginx/unit-docs) - DOMAIN="${DOMAIN_UNIT}" - ;; - prod/*) + prod) DOMAIN="${DOMAIN_PROD}" + STORAGE_PREFIX="prod" + ;; + staging_techdocs) + DOMAIN="${DOMAIN_STAGING_TECHDOCS}" + STORAGE_PREFIX="staging_techdocs" + ;; + prod_techdocs) + DOMAIN="${DOMAIN_PROD_TECHDOCS}" + STORAGE_PREFIX="prod_techdocs" ;; - preview/*) + preview) DOMAIN="${DOMAIN_PREVIEW}" + STORAGE_PREFIX="dev" + ;; + *) + echo "::error::Unhandled DEPLOYMENT_ENV '${DEPLOYMENT_ENV}'" + exit 1 ;; esac - echo "DEPLOYMENT_DOMAIN=${DOMAIN}" >> $GITHUB_ENV + echo "DEPLOYMENT_DOMAIN=${DOMAIN}" >> "$GITHUB_ENV" + echo "STORAGE_PREFIX=${STORAGE_PREFIX}" >> "$GITHUB_ENV" - name: Azure login uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0 @@ -172,43 +180,39 @@ jobs: with: inlineScript: | secrets_get=(resourceGroupName cdnProfileName cdnName accountName) - for secret_get in ${secrets_get[@]} + for secret_get in "${secrets_get[@]}" do - value=$(az keyvault secret show --name $secret_get --vault-name ${{ secrets.AZURE_KEY_VAULT }} --query value --output tsv) + value=$(az keyvault secret show --name "$secret_get" --vault-name "${{ secrets.AZURE_KEY_VAULT }}" --query value --output tsv) echo "::add-mask::$value" - echo "$secret_get=$value" >> $GITHUB_OUTPUT + echo "$secret_get=$value" >> "$GITHUB_OUTPUT" done - name: Checkout docs content - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.7.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - fetch-depth: 0 # This is required for hugo Lastmod to function properly + fetch-depth: 0 # Required for hugo Lastmod - name: Get latest hugo theme - if: inputs.doc_type == 'hugo' && inputs.force_hugo_theme_version == '' + if: inputs.force_hugo_theme_version == '' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - RESPONSE=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/nginxinc/nginx-hugo-theme/releases/latest) - echo $RESPONSE - echo "THEME_VERSION=$(echo $RESPONSE | jq -r ".tag_name")" >> "$GITHUB_ENV" - - ### Hugo builds + THEME_VERSION="$(gh api repos/nginxinc/nginx-hugo-theme/releases/latest -q .tag_name)" + echo "THEME_VERSION=${THEME_VERSION}" >> "$GITHUB_ENV" - name: Setup Go uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 - if: inputs.doc_type == 'hugo' with: - go-version: ${{env.GO_VERISON}} + go-version: ${{ env.GO_VERSION }} cache: false - name: Setup Hugo uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3.0.0 - if: inputs.doc_type == 'hugo' with: - hugo-version: ${{env.HUGO_VERSION}} + hugo-version: ${{ env.HUGO_VERSION }} extended: true - name: Add hugo build info - if: inputs.doc_type == 'hugo' run: | timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ') cat < buildInfo.json @@ -217,133 +221,104 @@ jobs: "buildDate": "$timestamp" } EOF - mkdir -p ${{inputs.docs_build_path}}/static/ - cp buildInfo.json ${{inputs.docs_build_path}}/static/ + mkdir -p "${{ inputs.docs_build_path }}/static/" + cp buildInfo.json "${{ inputs.docs_build_path }}/static/" - name: Setup node deps if: inputs.node_dep == true + working-directory: ${{ inputs.docs_build_path }} run: npm ci - - name: Build Hugo for PR preview - if: inputs.doc_type == 'hugo' && (github.event.action == 'synchronize' || github.event.action == 'opened' || env.DEPLOYMENT_ENV == 'preview') - working-directory: ${{inputs.docs_build_path}} + - name: Build Hugo (preview) + if: env.IS_PREVIEW == 'true' + working-directory: ${{ inputs.docs_build_path }} run: | hugo mod get -v "$THEME_MODULE@$THEME_VERSION" hugo --gc -e production --baseURL="https://${DEPLOYMENT_DOMAIN}${PREVIEW_URL_PATH}/${PR_NUMBER}" - - name: Build Hugo for environment - working-directory: ${{inputs.docs_build_path}} - if: inputs.doc_type == 'hugo' && env.DEPLOYMENT_ENV != 'preview' + - name: Build Hugo (environment) + if: env.IS_PREVIEW != 'true' + working-directory: ${{ inputs.docs_build_path }} run: | - hugo mod get "$THEME_MODULE@$THEME_VERSION" + hugo mod get -v "$THEME_MODULE@$THEME_VERSION" hugo --gc -e production --baseURL="https://${DEPLOYMENT_DOMAIN}${PRODUCTION_URL_PATH}" - ### Sphinx builds - - - name: Setup Sphinx - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0 - if: inputs.doc_type == 'sphinx' - with: - python-version: "3.9" - - - name: Install python dependencies - if: inputs.doc_type == 'sphinx' - run: pip install -r requirements.txt - - - name: Setup Gnupg directories - if: inputs.doc_type == 'sphinx' - run: | - mkdir -p /home/runner/.gnupg - chmod 700 /home/runner/.gnupg - - - name: Build Sphinx for PR preview and production - working-directory: ${{inputs.docs_build_path}} - if: inputs.doc_type == 'sphinx' - run: | - make deploy - ### Azure upload - - - name: Azure upload PR preview + - name: Azure upload (preview) uses: azure/cli@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 - if: github.event.action == 'synchronize' || github.event.action == 'opened' || env.DEPLOYMENT_ENV == 'preview' + if: env.IS_PREVIEW == 'true' with: inlineScript: | - cd ${{inputs.docs_build_path}} \ - && az storage blob upload-batch \ - -s $DOCS_SOURCE_PATH \ - -d '$web' \ - --destination-path "dev/${{github.repository}}/previews/${PR_NUMBER}" \ - --account-name ${{steps.keyvault.outputs.accountName}} \ - --overwrite \ - --content-cache-control "max-age=3600" \ - --auth-mode login - - az afd endpoint purge \ - --resource-group ${{steps.keyvault.outputs.resourceGroupName}} \ - --profile-name ${{steps.keyvault.outputs.cdnProfileName}} \ - --endpoint-name ${{steps.keyvault.outputs.cdnName}} \ - --domains $DOMAIN_PREVIEW \ - --content-paths "${PREVIEW_URL_PATH}/*" \ - --no-wait - - - name: Azure upload to specified environment + cd "${{ inputs.docs_build_path }}" + + az storage blob upload-batch \ + -s "$DOCS_SOURCE_PATH" \ + -d '$web' \ + --destination-path "dev/${{ github.repository }}/previews/${PR_NUMBER}" \ + --account-name "${{ steps.keyvault.outputs.accountName }}" \ + --overwrite \ + --content-cache-control "max-age=3600" \ + --auth-mode login + + az afd endpoint purge \ + --resource-group "${{ steps.keyvault.outputs.resourceGroupName }}" \ + --profile-name "${{ steps.keyvault.outputs.cdnProfileName }}" \ + --endpoint-name "${{ steps.keyvault.outputs.cdnName }}" \ + --domains "$DOMAIN_PREVIEW" \ + --content-paths "${PREVIEW_URL_PATH}/${PR_NUMBER}/*" \ + --no-wait + + - name: Azure upload (environment) uses: azure/cli@089eac9d8cc39f5d003e94f8b65efc51076c9cbd # v2.1.0 - if: env.DEPLOYMENT_ENV != 'preview' + if: env.IS_PREVIEW != 'true' with: inlineScript: | - cd ${{inputs.docs_build_path}} \ - && az storage blob upload-batch \ - -s $DOCS_SOURCE_PATH \ - -d '$web' \ - --destination-path "${DEPLOYMENT_ENV}/${{github.repository}}/latest/" \ - --account-name ${{steps.keyvault.outputs.accountName}} \ - --overwrite \ - --content-cache-control "max-age=3600" \ - --auth-mode login - - az afd endpoint purge \ - --resource-group ${{steps.keyvault.outputs.resourceGroupName}} \ - --profile-name ${{steps.keyvault.outputs.cdnProfileName}} \ - --endpoint-name ${{steps.keyvault.outputs.cdnName}} \ - --domains $DEPLOYMENT_DOMAIN \ - --content-paths "${PRODUCTION_URL_PATH}/*" \ - --no-wait + cd "${{ inputs.docs_build_path }}" + + az storage blob upload-batch \ + -s "$DOCS_SOURCE_PATH" \ + -d '$web' \ + --destination-path "${STORAGE_PREFIX}/${{ github.repository }}/latest/" \ + --account-name "${{ steps.keyvault.outputs.accountName }}" \ + --overwrite \ + --content-cache-control "max-age=3600" \ + --auth-mode login + + az afd endpoint purge \ + --resource-group "${{ steps.keyvault.outputs.resourceGroupName }}" \ + --profile-name "${{ steps.keyvault.outputs.cdnProfileName }}" \ + --endpoint-name "${{ steps.keyvault.outputs.cdnName }}" \ + --domains "$DEPLOYMENT_DOMAIN" \ + --content-paths "${PRODUCTION_URL_PATH}/*" \ + --no-wait - name: Azure logout + if: always() run: | az logout - if: always() ### PR preview comment - - name: PR preview comment uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 if: env.DEPLOYMENT_ENV == 'preview' && (github.event.action == 'synchronize' || github.event.action == 'opened') with: script: | - // If a comment already exists, skip const { data: comments } = await github.rest.issues.listComments({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, }); - - const existingComment = comments.find(comment => comment.user.login === 'github-actions[bot]' && comment.body.includes('Deploy Preview')); - - if (existingComment) { - core.info('Preview comment already exists. Skipping...'); - return; - } + const existingComment = comments.find( + c => c.user.login === 'github-actions[bot]' && c.body.includes('Deploy Preview') + ); + if (existingComment) return; const previewHostname = process.env.DOMAIN_PREVIEW; const previewUrlPath = process.env.PREVIEW_URL_PATH; const prNumber = context.payload.pull_request.number; - const previewUrl = `https://${previewHostname}${previewUrlPath}/${prNumber}/`; const body = `### Deploy Preview will be available once build job completes! - | Name | Link | |:-:|------------------------| | Deploy Preview | [${previewUrl}](${previewUrl}) | @@ -353,7 +328,7 @@ jobs: issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: body, + body, }); - name: Summary @@ -372,6 +347,5 @@ jobs: echo "| Production URL | [https://${DEPLOYMENT_DOMAIN}${PRODUCTION_URL_PATH}](https://${DEPLOYMENT_DOMAIN}${PRODUCTION_URL_PATH}) |" >> $GITHUB_STEP_SUMMARY echo "PREVIEW_URL=https://${DEPLOYMENT_DOMAIN}${PRODUCTION_URL_PATH}" >> $GITHUB_OUTPUT fi - # TODO(dani): Add more details to the summary