4
0

link-checker.yml 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. name: Link Checker
  2. on:
  3. push:
  4. branches: [ edge ]
  5. pull_request:
  6. branches: [ edge ]
  7. schedule:
  8. - cron: '30 12 1 * *'
  9. workflow_dispatch:
  10. permissions:
  11. contents: read
  12. concurrency:
  13. group: link-checker-${{ github.ref }}
  14. cancel-in-progress: false
  15. jobs:
  16. linkChecker:
  17. name: linkChecker
  18. runs-on: ubuntu-26.04
  19. steps:
  20. - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
  21. with:
  22. persist-credentials: false
  23. fetch-depth: 0
  24. # Check local links across the repository first to catch broken links in
  25. # files that are not part of the PR's changed files.
  26. - name: Check local links (offline run)
  27. if: github.event_name == 'pull_request'
  28. uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
  29. with:
  30. fail: true
  31. failIfEmpty: false
  32. args: >
  33. --offline
  34. .
  35. - name: Get changed files
  36. if: github.event_name == 'pull_request'
  37. env:
  38. BASE_SHA: ${{ github.event.pull_request.base.sha }}
  39. HEAD_SHA: ${{ github.event.pull_request.head.sha }}
  40. run: |
  41. git diff --name-only --diff-filter=ACMR \
  42. "$BASE_SHA" \
  43. "$HEAD_SHA" \
  44. > changed-files.txt
  45. # Lychee does not apply `extensions` from the config to files passed via `--files-from`.
  46. # Filter the changed files so only allowed file types are checked.
  47. python3 <<'PY'
  48. import pathlib
  49. import tomllib
  50. with open("lychee.toml", "rb") as fp:
  51. config = tomllib.load(fp)
  52. extensions = {e.lstrip(".").lower() for e in config["extensions"]}
  53. files = pathlib.Path("changed-files.txt").read_text().splitlines()
  54. files = [
  55. f for f in files
  56. if (
  57. pathlib.PurePath(f).suffix.lstrip(".").lower() in extensions
  58. or (
  59. not pathlib.PurePath(f).suffix
  60. and pathlib.PurePath(f).name.startswith(".")
  61. and pathlib.PurePath(f).name.lstrip(".").lower() in extensions
  62. )
  63. or (
  64. not pathlib.PurePath(f).suffix
  65. and not pathlib.PurePath(f).name.startswith(".")
  66. and config.get("default_extension") in extensions
  67. )
  68. )
  69. ]
  70. pathlib.Path("changed-files.txt").write_text(
  71. "\n".join(files) + ("\n" if files else "")
  72. )
  73. PY
  74. - name: Restore lychee cache
  75. id: restore-cache
  76. uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
  77. with:
  78. path: .lycheecache
  79. key: cache-lychee-${{ github.sha }}
  80. restore-keys: cache-lychee-
  81. - name: Run lychee
  82. uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
  83. with:
  84. # PAT with read-only permissions used to avoid GitHub rate limits (allows 5,000 requests per hour)
  85. # Won't be available to forks in pull requests due to restrictions, so falls back to default
  86. # GITHUB_TOKEN with 1,000 requests per hour instead.
  87. token: ${{ secrets.LYCHEE_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
  88. fail: true
  89. failIfEmpty: false # Avoid failing in PRs with no links in changed files (`true` is the default)
  90. # Config is loaded from lychee.toml
  91. args: >
  92. ${{ github.event_name == 'pull_request' && '--files-from changed-files.txt' || '.' }}
  93. - name: Save lychee cache
  94. uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
  95. if: always()
  96. with:
  97. path: .lycheecache
  98. key: ${{ steps.restore-cache.outputs.cache-primary-key }}