|
| 1 | +name: 'Run Hugo/Pagefind and deploy to GitHub Pages' |
| 2 | +description: 'Runs Hugo and Pagefind and then deploys the result to GitHub Pages.' |
| 3 | +# This composite Action requires the following things in the calling workflow: |
| 4 | +# |
| 5 | +# permissions: |
| 6 | +# contents: write # to push changes (if any) |
| 7 | +# pages: write # to deploy to GitHub Pages |
| 8 | +# id-token: write # to verify that the deployment source is legit |
| 9 | +# environment: |
| 10 | +# name: github-pages |
| 11 | +# url: ${{ steps.<id-of-deployment-step>.outputs.url }} |
| 12 | +inputs: |
| 13 | + github-token: |
| 14 | + description: The GitHub token used to create an authenticated client |
| 15 | + default: ${{ github.token }} |
| 16 | + required: true |
| 17 | +outputs: |
| 18 | + url: |
| 19 | + description: The URL to which the site was deployed |
| 20 | + value: ${{ steps.deploy.outputs.page_url }} |
| 21 | +runs: |
| 22 | + using: "composite" |
| 23 | + steps: |
| 24 | + - name: push changes (if needed) |
| 25 | + shell: bash |
| 26 | + run: | |
| 27 | + test "$(git rev-parse HEAD)" = "$(git rev-parse refs/remotes/origin/${{ github.ref_name }})" || |
| 28 | + git push origin HEAD:${{ github.ref }} |
| 29 | +
|
| 30 | + - name: un-sparse worktree to prepare for deployment |
| 31 | + shell: bash |
| 32 | + run: git sparse-checkout disable |
| 33 | + |
| 34 | + - name: setup GitHub Pages |
| 35 | + id: pages |
| 36 | + uses: actions/configure-pages@v5 |
| 37 | + |
| 38 | + - name: configure Hugo and Pagefind version |
| 39 | + shell: bash |
| 40 | + run: | |
| 41 | + set -x && |
| 42 | + echo "HUGO_VERSION=$(sed -n 's/^ *hugo_version: *//p' <hugo.yml)" >>$GITHUB_ENV |
| 43 | + echo "PAGEFIND_VERSION=$(sed -n 's/^ *pagefind_version: *//p' <hugo.yml)" >>$GITHUB_ENV |
| 44 | +
|
| 45 | + - name: install Hugo ${{ env.HUGO_VERSION }} |
| 46 | + shell: bash |
| 47 | + run: | |
| 48 | + set -x && |
| 49 | + curl -Lo /tmp/hugo.deb https://github.com/gohugoio/hugo/releases/download/v$HUGO_VERSION/hugo_extended_${HUGO_VERSION}_linux-amd64.deb && |
| 50 | + sudo dpkg -i /tmp/hugo.deb |
| 51 | +
|
| 52 | + - name: run Hugo to build the pages |
| 53 | + env: |
| 54 | + HUGO_RELATIVEURLS: false |
| 55 | + shell: bash |
| 56 | + run: hugo config && hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/" |
| 57 | + |
| 58 | + - name: run Pagefind ${{ env.PAGEFIND_VERSION }} to build the search index |
| 59 | + shell: bash |
| 60 | + run: npx -y pagefind@${{ env.PAGEFIND_VERSION }} --site public |
| 61 | + |
| 62 | + - name: upload GitHub Pages artifact |
| 63 | + uses: actions/upload-pages-artifact@v3 |
| 64 | + with: |
| 65 | + path: ./public |
| 66 | + |
| 67 | + - name: deploy |
| 68 | + id: deploy |
| 69 | + uses: actions/deploy-pages@v4 |
| 70 | + |
| 71 | + - name: construct `--remap` option for lychee |
| 72 | + id: remap |
| 73 | + shell: bash |
| 74 | + run: | |
| 75 | + base_url='${{ steps.pages.outputs.base_url }}' |
| 76 | + echo "result=$(echo "$base_url" | |
| 77 | + sed 's|^\(.*\)\(/git-scm\.com\)$|(\1)?\2(.*)|') file://$PWD/public\$2" \ |
| 78 | + >>$GITHUB_OUTPUT |
| 79 | +
|
| 80 | + - name: check for broken links |
| 81 | + id: lychee |
| 82 | + uses: lycheeverse/lychee-action@d4128702eae98bbc5ecf74df0165a8156c80920a # until an official version is out that includes https://github.com/lycheeverse/lychee/pull/1422 |
| 83 | + with: |
| 84 | + lycheeVersion: nightly # until an official version includes https://github.com/lycheeverse/lychee/pull/1422 |
| 85 | + args: >- |
| 86 | + --offline |
| 87 | + --fallback-extensions html |
| 88 | + --base '${{ steps.pages.outputs.base_url }}' |
| 89 | + --remap '${{ steps.remap.outputs.result }}' |
| 90 | + --exclude file:///path/to/repo.git/ |
| 91 | + --exclude file:///caminho/para/o/reposit%C3%B3rio.git/ |
| 92 | + --exclude file:///ruta/a/repositorio.git/ |
| 93 | + --exclude file:///sl%C3%B3%C3%B0/til/hirsla.git/ |
| 94 | + --exclude file:///Pfad/zum/Repo.git/ |
| 95 | + --exclude file:///chemin/du/d%C3%A9p%C3%B4t.git/ |
| 96 | + --exclude file:///srv/git/project.git |
| 97 | + public/ |
| 98 | + output: lychee.md |
| 99 | + jobSummary: true |
| 100 | + fail: false |
| 101 | + failIfEmpty: false # needed because its default overrides `fail = false` |
| 102 | + |
| 103 | + - name: ${{ env.lychee_exit_code != '0' && 'maybe close' || 'open or update' }} link checker issue |
| 104 | + uses: actions/github-script@v7 |
| 105 | + with: |
| 106 | + github-token: ${{ inputs.github-token }} |
| 107 | + script: | |
| 108 | + const fs = await import('fs') |
| 109 | + // GitHub issues can only have 64k characters in their body |
| 110 | + const body = (s => { |
| 111 | + if (s.length < 65535) return s |
| 112 | + return s.replace(/^([^]{0,65000}\n)[^]*\n(.+)\n?$/, '$1\n[...]\n\n$2') |
| 113 | + })(await fs.promises.readFile('lychee.md', 'utf8')) |
| 114 | +
|
| 115 | + const issues = await (async () => { |
| 116 | + const req = { owner: context.repo.owner, repo: context.repo.repo } |
| 117 | + const q = `"Link+Checker+Report"+in:title+is:issue+label:linkchecker+is:open+repo:${req.owner}/${req.repo}` |
| 118 | + try { |
| 119 | + return await github.rest.search.issuesAndPullRequests({ ...req, q, sort: 'created', per_page: 1 }) |
| 120 | + } catch (e) { |
| 121 | + console.log(`Warning: ${e}; sleeping for 30 seconds and falling back to calling listForRepo()`) |
| 122 | + await new Promise(r => setTimeout(r, 30000)) |
| 123 | +
|
| 124 | + const issues = await github.rest.issues.listForRepo({...req, state: 'open', per_page: 100}) |
| 125 | + return { |
| 126 | + data: { |
| 127 | + items: issues.data.filter( |
| 128 | + e => e.title === 'Link Checker Report' |
| 129 | + && e.labels.filter(l => l.name === 'linkchecker').length > 0 |
| 130 | + ) |
| 131 | + } |
| 132 | + } |
| 133 | + } |
| 134 | + })() |
| 135 | +
|
| 136 | + if (issues.data.items.length === 0) { |
| 137 | + if (process.env.lychee_exit_code !== '0') { |
| 138 | + await github.rest.issues.create({ ...req, title: 'Link Checker Report', body, labels: ['linkchecker'] }) |
| 139 | + } |
| 140 | + } else { |
| 141 | + req.issue_number = issues.data.items[0].number |
| 142 | + await github.rest.issues.createComment({ ...req, body }) |
| 143 | + if (process.env.lychee_exit_code === '0') { |
| 144 | + await github.rest.issues.update({ ...req, state: 'closed' }) |
| 145 | + } |
| 146 | + } |
0 commit comments