Repository navigation
Bump Tool Versions #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: Bump Tool Versions | |
| on: | |
| schedule: | |
| - cron: "17 3 * * 1" # weekly (Mon) UTC | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| bump: | |
| name: Bump versions.env | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Compute latest versions | |
| id: latest | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| python - <<'PY' | |
| import json | |
| import os | |
| import time | |
| import urllib.error | |
| import urllib.request | |
| token = os.environ["GH_TOKEN"] | |
| timeout_seconds = 12 | |
| max_retries = 4 | |
| def latest_tag(repo: str) -> str: | |
| url = f"https://api.github.com/repos/{repo}/releases/latest" | |
| headers = { | |
| "Authorization": f"Bearer {token}", | |
| "X-GitHub-Api-Version": "2022-11-28", | |
| "Accept": "application/vnd.github+json", | |
| "User-Agent": "bump-versions-workflow", | |
| } | |
| for attempt in range(1, max_retries + 1): | |
| req = urllib.request.Request(url, headers=headers) | |
| try: | |
| with urllib.request.urlopen(req, timeout=timeout_seconds) as resp: | |
| data = json.load(resp) | |
| tag = data.get("tag_name") | |
| if not tag: | |
| raise RuntimeError(f"Missing tag_name in GitHub response for {repo}") | |
| return tag | |
| except urllib.error.HTTPError as exc: | |
| retryable = exc.code in (403, 429, 500, 502, 503, 504) | |
| if retryable and attempt < max_retries: | |
| time.sleep(2 ** (attempt - 1)) | |
| continue | |
| raise RuntimeError( | |
| f"Failed to fetch latest release for {repo}: HTTP {exc.code}" | |
| ) from exc | |
| except (urllib.error.URLError, TimeoutError) as exc: | |
| if attempt < max_retries: | |
| time.sleep(2 ** (attempt - 1)) | |
| continue | |
| raise RuntimeError( | |
| f"Failed to fetch latest release for {repo}: {exc}" | |
| ) from exc | |
| raise RuntimeError(f"Failed to fetch latest release for {repo} after retries") | |
| def latest_npm_version(package_name: str) -> str: | |
| url = f"https://registry.npmjs.org/{package_name}/latest" | |
| for attempt in range(1, max_retries + 1): | |
| try: | |
| with urllib.request.urlopen(url, timeout=timeout_seconds) as resp: | |
| data = json.load(resp) | |
| version = data.get("version") | |
| if not version: | |
| raise RuntimeError(f"Missing version in npm response for {package_name}") | |
| return version | |
| except urllib.error.HTTPError as exc: | |
| retryable = exc.code in (429, 500, 502, 503, 504) | |
| if retryable and attempt < max_retries: | |
| time.sleep(2 ** (attempt - 1)) | |
| continue | |
| raise RuntimeError( | |
| f"Failed to fetch latest npm version for {package_name}: HTTP {exc.code}" | |
| ) from exc | |
| except (urllib.error.URLError, TimeoutError) as exc: | |
| if attempt < max_retries: | |
| time.sleep(2 ** (attempt - 1)) | |
| continue | |
| raise RuntimeError( | |
| f"Failed to fetch latest npm version for {package_name}: {exc}" | |
| ) from exc | |
| raise RuntimeError(f"Failed to fetch latest npm version for {package_name} after retries") | |
| versions = { | |
| "zola": latest_tag("getzola/zola").lstrip("v"), | |
| "tailwind": latest_tag("tailwindlabs/tailwindcss").lstrip("v"), | |
| "daisyui": latest_tag("saadeghi/daisyui").lstrip("v"), | |
| "katex": latest_tag("KaTeX/KaTeX").lstrip("v"), | |
| "fa": latest_tag("FortAwesome/Font-Awesome").lstrip("v"), | |
| "terser": latest_npm_version("terser"), | |
| "esbuild": latest_npm_version("esbuild"), | |
| "pnpm": latest_npm_version("pnpm"), | |
| "eslint": latest_npm_version("eslint"), | |
| "stylelint": latest_npm_version("stylelint"), | |
| } | |
| out_path = os.environ["GITHUB_OUTPUT"] | |
| with open(out_path, "a", encoding="utf-8") as f: | |
| for k, v in versions.items(): | |
| f.write(f"{k}={v}\n") | |
| PY | |
| - name: Update versions.env | |
| run: | | |
| set -euo pipefail | |
| file="versions.env" | |
| sed -i -E "s/^ZOLA_VERSION=.*/ZOLA_VERSION=${{ steps.latest.outputs.zola }}/" "$file" | |
| sed -i -E "s/^TAILWIND_VERSION=.*/TAILWIND_VERSION=${{ steps.latest.outputs.tailwind }}/" "$file" | |
| sed -i -E "s/^DAISYUI_VERSION=.*/DAISYUI_VERSION=${{ steps.latest.outputs.daisyui }}/" "$file" | |
| sed -i -E "s/^FA_VERSION=.*/FA_VERSION=${{ steps.latest.outputs.fa }}/" "$file" | |
| sed -i -E "s/^KATEX_VERSION=.*/KATEX_VERSION=${{ steps.latest.outputs.katex }}/" "$file" | |
| sed -i -E "s/^TERSER_VERSION=.*/TERSER_VERSION=${{ steps.latest.outputs.terser }}/" "$file" | |
| sed -i -E "s/^ESBUILD_VERSION=.*/ESBUILD_VERSION=${{ steps.latest.outputs.esbuild }}/" "$file" | |
| sed -i -E "s/^PNPM_VERSION=.*/PNPM_VERSION=${{ steps.latest.outputs.pnpm }}/" "$file" | |
| sed -i -E "s/^ESLINT_VERSION=.*/ESLINT_VERSION=${{ steps.latest.outputs.eslint }}/" "$file" | |
| sed -i -E "s/^STYLELINT_VERSION=.*/STYLELINT_VERSION=${{ steps.latest.outputs.stylelint }}/" "$file" | |
| echo "Updated versions.env:" | |
| cat "$file" | |
| - name: Import GPG Key | |
| uses: crazy-max/ghaction-import-gpg@v7 | |
| with: | |
| gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} | |
| passphrase: ${{ secrets.GPG_PASSPHRASE }} | |
| git_user_signingkey: true | |
| git_commit_gpgsign: true | |
| - name: Create pull request | |
| uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8 | |
| with: | |
| commit-message: "chore: bump tool versions" | |
| title: "chore: bump tool versions" | |
| body: | | |
| Automated weekly bump of tool versions in `versions.env`. | |
| - Zola: ${{ steps.latest.outputs.zola }} | |
| - Tailwind: ${{ steps.latest.outputs.tailwind }} | |
| - DaisyUI: ${{ steps.latest.outputs.daisyui }} | |
| - Font Awesome: ${{ steps.latest.outputs.fa }} | |
| - KaTeX: ${{ steps.latest.outputs.katex }} | |
| - Terser: ${{ steps.latest.outputs.terser }} | |
| - esbuild: ${{ steps.latest.outputs.esbuild }} | |
| - pnpm: ${{ steps.latest.outputs.pnpm }} | |
| - ESLint: ${{ steps.latest.outputs.eslint }} | |
| - Stylelint: ${{ steps.latest.outputs.stylelint }} | |
| branch: chore/bump-tool-versions | |
| delete-branch: true | |
| labels: | | |
| dependencies | |
| automation |