|
| 1 | +# Automatic build previews with GitHub Actions and Netlify |
| 2 | + |
| 3 | +This document is an attempt at documenting the process of automating the build previews with GitHub Actions and Netlify. |
| 4 | + |
| 5 | +The following instructions assume that you already have an account with [Netlify](https://app.netlify.com/signup). |
| 6 | + |
| 7 | + |
| 8 | +## Step 1: Connect your GitHub repository to Netlify |
| 9 | + |
| 10 | +Once you've logged in to Netlify, you can connect your GitHub repository to your site by heading over to [https://app.netlify.com/start](https://app.netlify.com/start) and choosing your Git provider. For our use case, we'll be using GitHub. |
| 11 | + |
| 12 | + |
| 13 | + |
| 14 | +After selecting GitHub, you'll see a new page with the GitHub organizations/accounts connected to your Netlify account. To select a repository, ensure that you've connected the right organization. Netlify will then show you the repositories that you can connect to your site. If not, click on the `configure the Netlify app...` option and follow the prompts. |
| 15 | + |
| 16 | + |
| 17 | + |
| 18 | + |
| 19 | + |
| 20 | +--- |
| 21 | + |
| 22 | +## Step 2: Update domain settings |
| 23 | + |
| 24 | +Once you've deployed the site, Netlify will assign it a random domain name. You can use the domain settings to change the domain name to something more meaningful. |
| 25 | + |
| 26 | + |
| 27 | + |
| 28 | + |
| 29 | +We'll be using the `projectpythia-org.netlify.app` domain. |
| 30 | + |
| 31 | +--- |
| 32 | + |
| 33 | +## Step 3: Update site settings |
| 34 | + |
| 35 | +Netlify will automatically try to build and deploy your site when you push to the GitHub repository. We are going to disable this behavior because we will be using GitHub Actions to build the site ourselves. |
| 36 | + |
| 37 | + |
| 38 | + |
| 39 | + |
| 40 | + |
| 41 | + |
| 42 | +--- |
| 43 | + |
| 44 | + |
| 45 | +## Step 4: Configure GitHub Actions |
| 46 | + |
| 47 | +Whenever a pull request or a push event is triggered on our GitHub repository, we'll build the site using GitHub Actions. Once the site's HTML pages are built, we send them to Netlify for deployment. Netlify will then deploy the site to the domain we specified and we'll be able to preview the site. |
| 48 | + |
| 49 | + |
| 50 | +### Building the site |
| 51 | + |
| 52 | +We're going to create a GitHub workflow for building and deploying the site. The configurations for this workflow are saved in `.github/workflows/ci.yaml`: |
| 53 | + |
| 54 | +<details> |
| 55 | +<summary> |
| 56 | +GitHub workflow configuration: |
| 57 | +</summary> |
| 58 | + |
| 59 | +```yaml |
| 60 | +name: deploy-site |
| 61 | + |
| 62 | +# Only run this when the master branch changes |
| 63 | +on: |
| 64 | + push: |
| 65 | + pull_request: |
| 66 | + workflow_dispatch: |
| 67 | +jobs: |
| 68 | + build: |
| 69 | + runs-on: ubuntu-latest |
| 70 | + defaults: |
| 71 | + run: |
| 72 | + shell: bash -l {0} |
| 73 | + if: github.repository == 'ProjectPythia/projectpythia.github.io' |
| 74 | + steps: |
| 75 | + - name: Cancel previous runs |
| 76 | + |
| 77 | + with: |
| 78 | + access_token: ${{ github.token }} |
| 79 | + - uses: actions/checkout@v2 |
| 80 | + - uses: conda-incubator/setup-miniconda@master |
| 81 | + with: |
| 82 | + channels: conda-forge |
| 83 | + channel-priority: strict |
| 84 | + activate-environment: pythia-site-dev |
| 85 | + auto-update-conda: false |
| 86 | + python-version: 3.8 |
| 87 | + environment-file: environment.yml |
| 88 | + mamba-version: '*' |
| 89 | + use-mamba: true |
| 90 | + |
| 91 | + # Build the site |
| 92 | + - name: Build the site |
| 93 | + run: | |
| 94 | + make html |
| 95 | +
|
| 96 | + - name: Zip the site |
| 97 | + run: | |
| 98 | + set -x |
| 99 | + set -e |
| 100 | +
|
| 101 | + if [ -f site.zip ]; then |
| 102 | + rm -rf site.zip |
| 103 | + fi |
| 104 | + zip -r site.zip ./_build/html |
| 105 | +
|
| 106 | + - uses: actions/upload-artifact@v2 |
| 107 | + with: |
| 108 | + name: site-zip |
| 109 | + path: ./site.zip |
| 110 | + # Push the site's HTML to github-pages |
| 111 | + - name: Deploy to GitHub pages |
| 112 | + if: github.ref == 'refs/heads/main' |
| 113 | + |
| 114 | + with: |
| 115 | + github_token: ${{ secrets.GITHUB_TOKEN }} |
| 116 | + publish_dir: ./_build/html |
| 117 | + enable_jekyll: false |
| 118 | + cname: projectpythia.org |
| 119 | +``` |
| 120 | +</details> |
| 121 | +
|
| 122 | +
|
| 123 | +### Previewing the built site |
| 124 | +
|
| 125 | +To preview the built site, we'll be using GitHub Actions to interact with Netlify API so as to retrieve the site's URL and posts this URL as a comment on the pull request. GitHub workflow for building and deploying the site. This workflow is saved in `.github/workflows/preview.yaml`: |
| 126 | + |
| 127 | +<details> |
| 128 | +<summary> |
| 129 | +GitHub workflow configuration: |
| 130 | +</summary> |
| 131 | + |
| 132 | +```yaml |
| 133 | +name: preview-site |
| 134 | +on: |
| 135 | + workflow_run: |
| 136 | + workflows: |
| 137 | + - deploy-site |
| 138 | + types: |
| 139 | + - requested |
| 140 | + - completed |
| 141 | +jobs: |
| 142 | + deploy: |
| 143 | + if: github.repository == 'ProjectPythia/projectpythia.github.io' |
| 144 | + runs-on: ubuntu-latest |
| 145 | + defaults: |
| 146 | + run: |
| 147 | + shell: bash |
| 148 | + steps: |
| 149 | + - uses: actions/checkout@v2 |
| 150 | + - name: Set message value |
| 151 | + run: | |
| 152 | + echo "comment_message=This pull request is being automatically built with [GitHub Actions](https://github.com/features/actions) and [Netlify](https://www.netlify.com/). To see the status of your deployment, click below." >> $GITHUB_ENV |
| 153 | + - name: Find Pull Request |
| 154 | + uses: actions/github-script@v4 |
| 155 | + id: find-pull-request |
| 156 | + with: |
| 157 | + script: | |
| 158 | + let pullRequestNumber = '' |
| 159 | + let pullRequestHeadSHA = '' |
| 160 | + core.info('Finding pull request...') |
| 161 | +
|
| 162 | + const pullRequests = await github.pulls.list({owner: context.repo.owner, repo: context.repo.repo}) |
| 163 | + for (let pullRequest of pullRequests.data) { |
| 164 | + if(pullRequest.head.sha === context.payload.workflow_run.head_commit.id) { |
| 165 | + pullRequestHeadSHA = pullRequest.head.sha |
| 166 | + pullRequestNumber = pullRequest.number |
| 167 | + break |
| 168 | + } |
| 169 | + } |
| 170 | + core.setOutput('number', pullRequestNumber) |
| 171 | + core.setOutput('sha', pullRequestHeadSHA) |
| 172 | + if(pullRequestNumber === '') { |
| 173 | + core.info( |
| 174 | + `No pull request associated with git commit SHA: ${context.payload.workflow_run.head_commit.id}` |
| 175 | + ) |
| 176 | + } |
| 177 | + else{ |
| 178 | + core.info(`Found pull request ${pullRequestNumber}, with head sha: ${pullRequestHeadSHA}`) |
| 179 | + } |
| 180 | + |
| 181 | + - name: Find Comment |
| 182 | + uses: peter-evans/find-comment@v1 |
| 183 | + if: steps.find-pull-request.outputs.number != '' |
| 184 | + id: fc |
| 185 | + with: |
| 186 | + issue-number: '${{ steps.find-pull-request.outputs.number }}' |
| 187 | + comment-author: 'github-actions[bot]' |
| 188 | + body-includes: '${{ env.comment_message }}' |
| 189 | + |
| 190 | + - name: Create comment |
| 191 | + if: | |
| 192 | + github.event.workflow_run.conclusion != 'success' |
| 193 | + && steps.find-pull-request.outputs.number != '' |
| 194 | + && steps.fc.outputs.comment-id == '' |
| 195 | + uses: peter-evans/create-or-update-comment@v1 |
| 196 | + with: |
| 197 | + issue-number: ${{ steps.find-pull-request.outputs.number }} |
| 198 | + body: | |
| 199 | + ${{ env.comment_message }} |
| 200 | + 🚧 Deployment in progress for git commit SHA: ${{ steps.find-pull-request.outputs.sha }} |
| 201 | +
|
| 202 | + - name: Update comment |
| 203 | + if: | |
| 204 | + github.event.workflow_run.conclusion != 'success' |
| 205 | + && steps.find-pull-request.outputs.number != '' |
| 206 | + && steps.fc.outputs.comment-id != '' |
| 207 | + uses: peter-evans/create-or-update-comment@v1 |
| 208 | + with: |
| 209 | + comment-id: ${{ steps.fc.outputs.comment-id }} |
| 210 | + edit-mode: replace |
| 211 | + body: | |
| 212 | + ${{ env.comment_message }} |
| 213 | + 🚧 Deployment in progress for git commit SHA: ${{ steps.find-pull-request.outputs.sha }} |
| 214 | +
|
| 215 | + - name: Download Artifact site |
| 216 | + |
| 217 | + with: |
| 218 | + github_token: ${{ secrets.GITHUB_TOKEN }} |
| 219 | + workflow: ci.yaml |
| 220 | + run_id: ${{ github.event.workflow_run.id }} |
| 221 | + name: site-zip |
| 222 | + |
| 223 | + - name: Unzip site |
| 224 | + run: | |
| 225 | + rm -rf ./_build/html |
| 226 | + unzip site.zip |
| 227 | + rm -f site.zip |
| 228 | +
|
| 229 | + # Push the site's HTML to Netlify and get the preview URL |
| 230 | + - name: Deploy to Netlify |
| 231 | + id: netlify |
| 232 | + |
| 233 | + with: |
| 234 | + publish-dir: ./_build/html |
| 235 | + production-deploy: false |
| 236 | + github-token: ${{ secrets.GITHUB_TOKEN }} |
| 237 | + enable-commit-comment: false |
| 238 | + env: |
| 239 | + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} |
| 240 | + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} |
| 241 | + timeout-minutes: 5 |
| 242 | + |
| 243 | + - name: Update site Preview comment |
| 244 | + if: | |
| 245 | + github.event.workflow_run.conclusion == 'success' |
| 246 | + && steps.find-pull-request.outputs.number != '' |
| 247 | + && steps.fc.outputs.comment-id != '' |
| 248 | + uses: peter-evans/create-or-update-comment@v1 |
| 249 | + with: |
| 250 | + comment-id: ${{ steps.fc.outputs.comment-id }} |
| 251 | + edit-mode: replace |
| 252 | + body: | |
| 253 | + ${{ env.comment_message }} |
| 254 | +
|
| 255 | + 🔍 Git commit SHA: ${{ steps.find-pull-request.outputs.sha }} |
| 256 | + ✅ Deployment Preview URL: ${{ steps.netlify.outputs.deploy-url }} |
| 257 | +``` |
| 258 | +</details> |
| 259 | +
|
| 260 | +
|
| 261 | +
|
| 262 | +
|
| 263 | +## Step 5: Generate Personal Access Token |
| 264 | +
|
| 265 | +To interact with Netlify API from GitHub Actions we need to generate a personal access token. To generate a personal access token, head over to [https://app.netlify.com/user/applications#personal-access-tokens](https://app.netlify.com/user/applications#personal-access-tokens) and click on the `New access token` button. Save this token to somewhere safe. |
| 266 | + |
| 267 | +--- |
| 268 | + |
| 269 | +## Step 6: Create GitHub Action secrets |
| 270 | + |
| 271 | +Head over to the repository secrets page on GitHub: `https://github.com/ORG/REPOSITORY/settings/secrets/actions` and set the following secrets: |
| 272 | + |
| 273 | +- `NETFLIFY_AUTH_TOKEN`: The personal access token generated in Step 5. |
| 274 | +- `NETLIFY_SITE_ID`: The site ID generated in Step 2. This ID can be found on the site's settings page (this is the same thing as the `API ID` in the Netlify site settings). |
| 275 | + |
0 commit comments