diff --git a/.github/workflows/link-check.yml b/.github/workflows/link-check.yml new file mode 100644 index 00000000..223dac27 --- /dev/null +++ b/.github/workflows/link-check.yml @@ -0,0 +1,79 @@ +name: Link check + +# Builds the site the same way Netlify does and runs lychee over the rendered +# output. This is report-only: broken links are surfaced in the run's job +# summary but never fail the workflow (`fail: false` below), mirroring the +# previous advisory link check that used to run during the Netlify build. + +on: + pull_request: + push: + branches: [master] + workflow_dispatch: + +concurrency: + group: link-check-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + link-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Bulma SASS is imported from node_modules during the Hugo build, so the + # node deps must be installed first (Netlify does this automatically when + # it detects package.json; Actions does not). + - uses: actions/setup-node@v4 + with: + node-version-file: .node-version + - run: npm ci + + # pull_external.py (run by `make production-build`) needs these deps. + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + - run: pip install -r requirements.txt + + # Hugo extended is required to compile SASS via Hugo Pipes (toCSS). + - uses: peaceiris/actions-hugo@v3 + with: + hugo-version: 0.163.3 + extended: true + + # Build the production site into ./public. This also pulls in external + # content. GITHUB_TOKEN authenticates pull_external.py's GitHub releases + # API calls: without a token it skips release generation entirely, which + # would otherwise show up as false broken links in the report. + - run: make production-build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Persist lychee's on-disk result cache across runs to speed up the + # (network-bound) external link checks. + - uses: actions/cache@v4 + with: + path: .lycheecache + key: lychee-${{ github.run_id }} + restore-keys: lychee- + + - name: Check links + uses: lycheeverse/lychee-action@v2 + with: + # --root-dir resolves root-relative links against the built ./public + # tree (the site is built with baseURL "/"). letsencrypt.org is + # excluded because it blocks automated requests. 403/429 are accepted + # so that bot-blocking or rate-limited external hosts don't read as + # broken links. + args: >- + --no-progress + --root-dir "${{ github.workspace }}/public" + --exclude 'letsencrypt\.org' + --cache --max-cache-age 1d + --accept '100..=103,200..=299,403,429' + public + token: ${{ secrets.GITHUB_TOKEN }} + fail: false diff --git a/Dockerfile.linkchecker b/Dockerfile.linkchecker deleted file mode 100644 index e3085e7e..00000000 --- a/Dockerfile.linkchecker +++ /dev/null @@ -1,16 +0,0 @@ -FROM docker.io/library/python:3.9-alpine - -ENV HOME=/tmp -ENV PIP_NO_CACHE_DIR=off - -COPY requirements.txt ./ - -RUN pip install -r requirements.txt - -# Create linkchecker plugin directory with proper permissions -RUN mkdir -p /tmp/.local/share/linkchecker/plugins && \ - chmod -R 755 /tmp/.local/share/linkchecker - -ADD linkcheckerrc . - -ENTRYPOINT [ "linkchecker" ] diff --git a/Makefile b/Makefile index 3eee29e6..4ab02dd5 100644 --- a/Makefile +++ b/Makefile @@ -21,12 +21,12 @@ serve-with-releases: --buildFuture \ --disableFastRender -production-build: ci-check-links +production-build: pull-external-content hugo \ --gc \ --ignoreCache -preview-build: ci-check-links +preview-build: pull-external-content hugo \ --gc \ --ignoreCache \ @@ -53,21 +53,3 @@ docker-serve-with-releases: docker-build pull-external-content: python3 ./pull_external.py - -ci-check-links: pull-external-content - echo "Running Hugo server..." && \ - hugo server -p 1212 & \ - sleep 2 && \ - echo "Running links checker..." && \ - linkchecker -f linkcheckerrc http://localhost:1212; \ - echo "Stopping Hugo server..." && \ - pkill hugo || true - -check-links: - linkchecker -f linkcheckerrc http://localhost:1313 - -docker-check-links-build: - $(CONTAINER_RUNTIME) build -f Dockerfile.linkchecker -t linkchecker . - -docker-check-links: docker-check-links-build - $(CONTAINER_RUNTIME) run --rm -it -u $(shell id -u):$(shell id -g) --net host linkchecker -f linkcheckerrc http://localhost:1313 diff --git a/README.md b/README.md index c42a327a..ae261402 100644 --- a/README.md +++ b/README.md @@ -70,21 +70,9 @@ The website is now available at [`http://localhost:1313`](http://localhost:1313) It is common that URLs you are pointing to get deprecated or moved somewhere else over time, leading to broken links on our website. -In order to avoid this, there is a tool that lets you check whether there are broken links in the whole website or not. +Link checking runs automatically in CI via the [Link check](.github/workflows/link-check.yml) GitHub Actions workflow, on every pull request and on pushes to `master`. It builds the site and runs [lychee](https://github.com/lycheeverse/lychee) over the rendered output. -First, make sure you are serving the website locally using the `-with-releases` form of the script (`make docker-serve-with-releases` or `make serve-with-releases`), and that it is accessible at `http://localhost:1313`, then run the following command: - -```shell -make docker-check-links # if you are using Docker to serve the website -``` - -or - -```shell -make check-links # if you are using a local toolchain to serve the website -``` - -The tool will crawl your local website and report if there's any broken link on it. If there's any, and you can't create a PR to fix the link right away, please [file an issue on GitHub](https://github.com/spiffe/spiffe.io/issues/new) +The check is **report-only** — it never fails the build. Results are published to the workflow run's job summary, so look there for any broken links. If you find one and can't create a PR to fix it right away, please [file an issue on GitHub](https://github.com/spiffe/spiffe.io/issues/new). ## Publishing the site diff --git a/linkcheckerrc b/linkcheckerrc deleted file mode 100644 index 579cdb26..00000000 --- a/linkcheckerrc +++ /dev/null @@ -1,6 +0,0 @@ -[filtering] -checkextern=1 -ignore=letsencrypt\.org - -[output] -status=0 diff --git a/requirements.txt b/requirements.txt index b267bef9..f79e63e5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,3 @@ requests==2.32.4 beautifulsoup4==4.15.0 watchdog==4.0.2 toml==0.10.2 -linkchecker==10.3.0