|
| 1 | +name: Azure - Deploy Preview Environment (public) |
| 2 | + |
| 3 | +# NOTE! This is specifically and only for github/docs. |
| 4 | + |
| 5 | +# **What it does**: Build and deploy an Azure preview environment for this PR in github/docs |
| 6 | +# **Why we have it**: It's our preview environment deploy mechanism, to docs public repo |
| 7 | +# **Who does it impact**: All open source contributors. |
| 8 | + |
| 9 | +# !!! |
| 10 | +# ! This worflow has access to secrets, runs in the public repository, and clones untrusted user code. |
| 11 | +# ! Modify with extreme caution |
| 12 | +# !!! |
| 13 | + |
| 14 | +on: |
| 15 | + pull_request_target: |
| 16 | + # Note that if someone makes a PR that touches `Dockerfile` |
| 17 | + # and `content/index.md`, this use of `paths` will still run. |
| 18 | + # It would run even if we appended `- '!Dockerfile'` to the list. |
| 19 | + # But if someone makes a PR that touches `Dockerfile` only, the |
| 20 | + # workflow will not run. |
| 21 | + paths: |
| 22 | + - 'content/**' |
| 23 | + - 'data/**' |
| 24 | + - 'assets/**' |
| 25 | + merge_group: |
| 26 | + |
| 27 | +permissions: |
| 28 | + contents: read |
| 29 | + deployments: write |
| 30 | + |
| 31 | +# This allows one deploy workflow to interrupt another |
| 32 | +concurrency: |
| 33 | + group: 'preview-env @ ${{ github.head_ref || github.run_id }} for ${{ github.event.number || inputs.PR_NUMBER }}' |
| 34 | + cancel-in-progress: true |
| 35 | + |
| 36 | +jobs: |
| 37 | + build-and-deploy-azure-preview-public: |
| 38 | + name: Build and deploy Azure preview environment (public) |
| 39 | + runs-on: ubuntu-latest |
| 40 | + if: github.repository == 'github/docs' |
| 41 | + timeout-minutes: 15 |
| 42 | + environment: |
| 43 | + name: preview-env-${{ github.event.number }} |
| 44 | + # The environment variable is computer later in this job in |
| 45 | + # the "Get preview app info" step. |
| 46 | + # That script sets environment variables which is used by Actions |
| 47 | + # to link a PR to a list of environments later. |
| 48 | + url: ${{ env.APP_URL }} |
| 49 | + env: |
| 50 | + PR_NUMBER: ${{ github.event.number || github.run_id }} |
| 51 | + COMMIT_REF: ${{ github.event.pull_request.head.sha }} |
| 52 | + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} |
| 53 | + NONPROD_REGISTRY_USERNAME: ghdocs |
| 54 | + |
| 55 | + steps: |
| 56 | + - name: 'Az CLI login' |
| 57 | + uses: azure/login@8c334a195cbb38e46038007b304988d888bf676a # pin @v2 |
| 58 | + with: |
| 59 | + creds: ${{ secrets.NONPROD_AZURE_CREDENTIALS }} |
| 60 | + |
| 61 | + - name: 'Docker login' |
| 62 | + uses: azure/docker-login@15c4aadf093404726ab2ff205b2cdd33fa6d054c |
| 63 | + with: |
| 64 | + login-server: ${{ secrets.NONPROD_REGISTRY_SERVER }} |
| 65 | + username: ${{ env.NONPROD_REGISTRY_USERNAME }} |
| 66 | + password: ${{ secrets.NONPROD_REGISTRY_PASSWORD }} |
| 67 | + |
| 68 | + - name: Set up Docker Buildx |
| 69 | + uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb |
| 70 | + |
| 71 | + - name: Check out main branch |
| 72 | + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 |
| 73 | + with: |
| 74 | + ref: 'main' |
| 75 | + persist-credentials: 'false' |
| 76 | + |
| 77 | + - name: Get preview app info |
| 78 | + env: |
| 79 | + APP_NAME_SEED: ${{ secrets.PREVIEW_ENV_NAME_SEED }} |
| 80 | + run: src/workflows/get-preview-app-info.sh |
| 81 | + |
| 82 | + - name: 'Set env vars' |
| 83 | + run: | |
| 84 | + # Image tag is unique to each workflow run so that it always triggers a new deployment |
| 85 | + echo "DOCKER_IMAGE=${{ secrets.NONPROD_REGISTRY_SERVER }}/${IMAGE_REPO}:${{ env.COMMIT_REF }}-${{ github.run_number }}-${{ github.run_attempt }}" >> $GITHUB_ENV |
| 86 | +
|
| 87 | + - name: Check out user code to temp directory |
| 88 | + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 |
| 89 | + with: |
| 90 | + path: ./user-code |
| 91 | + ref: ${{ env.COMMIT_REF }} |
| 92 | + |
| 93 | + # Move acceptable user changes into our main branch checkout |
| 94 | + - name: Move acceptable user changes |
| 95 | + run: | |
| 96 | + # Make sure recursive path expansion is enabled |
| 97 | + shopt -s globstar |
| 98 | + rsync -rptovR ./user-code/content/./**/*.md ./content |
| 99 | + rsync -rptovR ./user-code/assets/./**/*.png ./assets |
| 100 | + rsync -rptovR ./user-code/data/./**/*.{yml,md} ./data |
| 101 | +
|
| 102 | + - uses: ./.github/actions/warmup-remotejson-cache |
| 103 | + with: |
| 104 | + restore-only: true |
| 105 | + |
| 106 | + - uses: ./.github/actions/precompute-pageinfo |
| 107 | + with: |
| 108 | + restore-only: true |
| 109 | + |
| 110 | + # In addition to making the final image smaller, we also save time by not sending unnecessary files to the docker build context |
| 111 | + - name: 'Prune for preview env' |
| 112 | + run: src/workflows/prune-for-preview-env.sh |
| 113 | + |
| 114 | + - name: 'Build and push image' |
| 115 | + uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 |
| 116 | + with: |
| 117 | + context: . |
| 118 | + push: true |
| 119 | + target: preview |
| 120 | + tags: ${{ env.DOCKER_IMAGE }} |
| 121 | + # we only pull the `main` cache image |
| 122 | + cache-from: type=registry,ref=${{ secrets.NONPROD_REGISTRY_SERVER }}/${{ github.repository }}:main-preview |
| 123 | + # `main-docker-cache.yml` handles updating the remote cache so we don't pollute it with PR specific code |
| 124 | + cache-to: '' |
| 125 | + build-args: | |
| 126 | + BUILD_SHA=${{ env.COMMIT_REF }} |
| 127 | +
|
| 128 | + # Succeed despite any non-zero exit code (e.g. if there is no deployment to cancel) |
| 129 | + - name: 'Cancel any existing deployments for this PR' |
| 130 | + run: | |
| 131 | + az deployment group cancel --name ${{ env.DEPLOYMENT_NAME }} -g ${{ secrets.PREVIEW_ENV_RESOURCE_GROUP }} || true |
| 132 | +
|
| 133 | + # Deploy ARM template is idempotent |
| 134 | + # Note: once the resources exist the image tag must change for a new deployment to occur (the image tag includes workflow run number, run attempt, as well as sha) |
| 135 | + - name: Run ARM deploy |
| 136 | + uses: azure/arm-deploy@a1361c2c2cd398621955b16ca32e01c65ea340f5 |
| 137 | + with: |
| 138 | + scope: resourcegroup |
| 139 | + resourceGroupName: ${{ secrets.PREVIEW_ENV_RESOURCE_GROUP }} |
| 140 | + subscriptionId: ${{ secrets.NONPROD_SUBSCRIPTION_ID }} |
| 141 | + template: ./src/workflows/azure-preview-env-template.json |
| 142 | + deploymentName: ${{ env.DEPLOYMENT_NAME }} |
| 143 | + parameters: appName="${{ env.APP_NAME }}" |
| 144 | + containerImage="${{ env.DOCKER_IMAGE }}" |
| 145 | + dockerRegistryUrl="${{ secrets.NONPROD_REGISTRY_SERVER }}" |
| 146 | + dockerRegistryUsername="${{ env.NONPROD_REGISTRY_USERNAME }}" |
| 147 | + dockerRegistryPassword="${{ secrets.NONPROD_REGISTRY_PASSWORD }}" |
| 148 | + |
| 149 | + - name: Check that it can be reached |
| 150 | + # This introduces a necessary delay. Because the preview evironment |
| 151 | + # URL is announced to the pull request as soon as all the steps |
| 152 | + # finish, what sometimes happens is that a viewer of the PR clicks |
| 153 | + # that link too fast and are confronted with a broken page. |
| 154 | + # It's because there's a delay between the `azure/arm-deploy` |
| 155 | + # and when the server is actually started and can receive and |
| 156 | + # process requests. |
| 157 | + # By introducing a slight "delay" here we avoid announcing a |
| 158 | + # preview environment URL that isn't actually working just yet. |
| 159 | + # Note the use of `--fail`. It which means that if it actually |
| 160 | + # did connect but the error code was >=400, the command will fail. |
| 161 | + # The `--fail --retry N` combination means that a 4xx response |
| 162 | + # code will exit immediately but a 5xx will exhaust the retries. |
| 163 | + run: curl --fail --retry-connrefused --retry 5 -I ${{ env.APP_URL }} |
0 commit comments