From 175581bbf39a1c67f8f91c7b03cd806e303d9e99 Mon Sep 17 00:00:00 2001 From: mohamed-elkholy95 Date: Sun, 31 May 2026 19:21:50 -0400 Subject: [PATCH 1/3] ci(actions): update workflows for Node 24 --- .../workflows/changelog-entry-required.yml | 2 +- .github/workflows/ci-docs.yml | 8 ++-- .github/workflows/ci-pythinker-cli.yml | 30 +++++++------- .github/workflows/ci-pythinker-core.yml | 14 +++---- .github/workflows/ci-pythinker-host.yml | 6 +-- .github/workflows/ci-pythinker-sdk.yml | 14 +++---- .../dispatch-pythinker-home-sync.yml | 22 ++++++++-- .github/workflows/docs-pages.yml | 14 +++---- .github/workflows/homebrew-tap.yml | 10 ++--- .github/workflows/linux-installer.yml | 10 ++--- .github/workflows/pr-title-checker.yml | 33 +++++++++++++-- .github/workflows/release-pythinker-cli.yml | 40 +++++++++---------- .github/workflows/release-pythinker-core.yml | 10 ++--- .github/workflows/release-pythinker-host.yml | 10 ++--- .github/workflows/release-pythinker-sdk.yml | 10 ++--- .github/workflows/typos.yml | 2 +- .github/workflows/windows-installer.yml | 8 ++-- 17 files changed, 142 insertions(+), 101 deletions(-) diff --git a/.github/workflows/changelog-entry-required.yml b/.github/workflows/changelog-entry-required.yml index 6a6245f1..e3027ab2 100644 --- a/.github/workflows/changelog-entry-required.yml +++ b/.github/workflows/changelog-entry-required.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 # Read-only job (git show/diff on already-fetched history, no push); diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index 5ac55739..b6737317 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -25,15 +25,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: "20" + node-version: "24" - name: Cache docs node_modules - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: docs/node_modules key: ${{ runner.os }}-docs-node-modules-${{ hashFiles('docs/package.json') }} diff --git a/.github/workflows/ci-pythinker-cli.yml b/.github/workflows/ci-pythinker-cli.yml index 0c60bb52..e9eb229c 100644 --- a/.github/workflows/ci-pythinker-cli.yml +++ b/.github/workflows/ci-pythinker-cli.yml @@ -31,17 +31,17 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" enable-cache: true @@ -65,17 +65,17 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" enable-cache: true @@ -125,7 +125,7 @@ jobs: continue-on-error: ${{ matrix.experimental == true }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install GNU Make (Windows) if: runner.os == 'Windows' @@ -133,21 +133,21 @@ jobs: - name: Set up Python 3.13 id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.13" - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" enable-cache: true cache-dependency-glob: uv.lock - name: Set up Node.js (web build) - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: "20" + node-version: "24" cache: "npm" cache-dependency-path: web/package-lock.json @@ -190,7 +190,7 @@ jobs: # collide on the artifact name. The probe only needs the build to # succeed; we do not consume its binary. if: success() && !matrix.experimental - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: pythinker-${{ matrix.target }} path: ${{ matrix.binary_path }} @@ -202,12 +202,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true @@ -319,7 +319,7 @@ jobs: runs-on: ${{ matrix.runner }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install Nix uses: DeterminateSystems/nix-installer-action@main diff --git a/.github/workflows/ci-pythinker-core.yml b/.github/workflows/ci-pythinker-core.yml index b7bee136..60893e07 100644 --- a/.github/workflows/ci-pythinker-core.yml +++ b/.github/workflows/ci-pythinker-core.yml @@ -28,17 +28,17 @@ jobs: python-version: ["3.12", "3.13", "3.14"] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" enable-cache: true @@ -65,16 +65,16 @@ jobs: FOOTER_VERSION: ${{ github.ref_name }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" enable-cache: true @@ -91,7 +91,7 @@ jobs: -o packages/pythinker-core/docs - name: Upload docs preview - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: docs-preview path: packages/pythinker-core/docs diff --git a/.github/workflows/ci-pythinker-host.yml b/.github/workflows/ci-pythinker-host.yml index f479eada..232772a4 100644 --- a/.github/workflows/ci-pythinker-host.yml +++ b/.github/workflows/ci-pythinker-host.yml @@ -51,7 +51,7 @@ jobs: shell: bash steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install GNU Make (Windows) if: runner.os == 'Windows' @@ -60,13 +60,13 @@ jobs: - name: Set up Python ${{ matrix.python-version }} id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" enable-cache: true diff --git a/.github/workflows/ci-pythinker-sdk.yml b/.github/workflows/ci-pythinker-sdk.yml index 6de0c3aa..9da93c2f 100644 --- a/.github/workflows/ci-pythinker-sdk.yml +++ b/.github/workflows/ci-pythinker-sdk.yml @@ -28,17 +28,17 @@ jobs: python-version: ["3.12", "3.13", "3.14"] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" enable-cache: true @@ -65,16 +65,16 @@ jobs: FOOTER_VERSION: ${{ github.ref_name }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" enable-cache: true @@ -91,7 +91,7 @@ jobs: -o sdks/pythinker-sdk/docs - name: Upload docs preview - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: docs-preview path: sdks/pythinker-sdk/docs diff --git a/.github/workflows/dispatch-pythinker-home-sync.yml b/.github/workflows/dispatch-pythinker-home-sync.yml index a2ca32a9..e4b53bb8 100644 --- a/.github/workflows/dispatch-pythinker-home-sync.yml +++ b/.github/workflows/dispatch-pythinker-home-sync.yml @@ -26,21 +26,37 @@ jobs: DISPATCH_OWNER: TechMatrix-labs DISPATCH_REPO: pythinker-home steps: + - name: Check pythinker-home dispatch credentials + id: dispatch-credentials + env: + CLIENT_ID: ${{ secrets.PYTHINKER_RELEASE_BOT_CLIENT_ID }} + PRIVATE_KEY: ${{ secrets.PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY }} + run: | + set -euo pipefail + if [ -z "${CLIENT_ID:-}" ] || [ -z "${PRIVATE_KEY:-}" ]; then + echo "configured=false" >> "$GITHUB_OUTPUT" + echo "::notice::Skipping pythinker-home sync because PYTHINKER_RELEASE_BOT_CLIENT_ID or PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY is not configured." + exit 0 + fi + echo "configured=true" >> "$GITHUB_OUTPUT" + # Mint a short-lived installation token for the org-owned # pythinker-release-bot App (Contents: write on pythinker-home only). # Replaces a personal PAT: org-owned (survives member/org changes), # ~1h TTL, minted fresh each run, scoped to the single private site repo. - name: Mint GitHub App token for pythinker-home id: app-token - uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 + if: steps.dispatch-credentials.outputs.configured == 'true' + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: - app-id: ${{ secrets.PYTHINKER_RELEASE_BOT_APP_ID }} + client-id: ${{ secrets.PYTHINKER_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY }} owner: ${{ env.DISPATCH_OWNER }} repositories: ${{ env.DISPATCH_REPO }} permission-contents: write - name: Trigger pythinker-home sync + if: steps.dispatch-credentials.outputs.configured == 'true' env: DISPATCH_TOKEN: ${{ steps.app-token.outputs.token }} SOURCE_REPO: ${{ github.repository }} @@ -50,7 +66,7 @@ jobs: run: | set -euo pipefail if [ -z "${DISPATCH_TOKEN:-}" ]; then - echo "::error::No dispatch token: the pythinker-release-bot App token mint produced an empty value. Confirm PYTHINKER_RELEASE_BOT_APP_ID and PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY org secrets are set and the App is installed on ${DISPATCH_OWNER}/${DISPATCH_REPO} with Contents: Read and write." >&2 + echo "::error::No dispatch token: the pythinker-release-bot App token mint produced an empty value. Confirm PYTHINKER_RELEASE_BOT_CLIENT_ID and PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY org secrets are set and the App is installed on ${DISPATCH_OWNER}/${DISPATCH_REPO} with Contents: Read and write." >&2 exit 1 fi payload=$(jq -n \ diff --git a/.github/workflows/docs-pages.yml b/.github/workflows/docs-pages.yml index 096cf5d0..ae3a2d46 100644 --- a/.github/workflows/docs-pages.yml +++ b/.github/workflows/docs-pages.yml @@ -24,15 +24,15 @@ jobs: url: ${{ steps.deploy.outputs.page_url }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: "20" + node-version: "24" - name: Cache docs node_modules - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: docs/node_modules key: ${{ runner.os }}-docs-node-modules-${{ hashFiles('docs/package.json') }} @@ -41,7 +41,7 @@ jobs: - name: Configure GitHub Pages id: pages - uses: actions/configure-pages@v5 + uses: actions/configure-pages@v6 with: enablement: true @@ -72,10 +72,10 @@ jobs: run: touch docs/.vitepress/dist/.nojekyll - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@v5 with: path: docs/.vitepress/dist - name: Deploy to GitHub Pages id: deploy - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v5 diff --git a/.github/workflows/homebrew-tap.yml b/.github/workflows/homebrew-tap.yml index cc5d25a6..bc98a246 100644 --- a/.github/workflows/homebrew-tap.yml +++ b/.github/workflows/homebrew-tap.yml @@ -25,7 +25,7 @@ jobs: TAP_REPO: homebrew-pythinker steps: - name: Checkout source repo - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Resolve version id: ver @@ -45,7 +45,7 @@ jobs: echo "version=${version}" >> "$GITHUB_OUTPUT" - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.13" @@ -78,9 +78,9 @@ jobs: # other than the one this workflow runs in. - name: Mint GitHub App token for the tap repo id: app-token - uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: - app-id: ${{ secrets.HOMEBREW_TAP_APP_ID }} + client-id: ${{ secrets.HOMEBREW_TAP_CLIENT_ID }} private-key: ${{ secrets.HOMEBREW_TAP_APP_PRIVATE_KEY }} owner: ${{ env.TAP_OWNER }} repositories: ${{ env.TAP_REPO }} @@ -92,7 +92,7 @@ jobs: run: | set -euxo pipefail if [ -z "${TAP_TOKEN:-}" ]; then - echo "::error::No tap token available — the GitHub App token mint produced an empty value. Confirm the HOMEBREW_TAP_APP_ID and HOMEBREW_TAP_APP_PRIVATE_KEY secrets are set and the App is installed on ${TAP_OWNER}/${TAP_REPO} with Contents: Read and write, then re-run this workflow." >&2 + echo "::error::No tap token available — the GitHub App token mint produced an empty value. Confirm the HOMEBREW_TAP_CLIENT_ID and HOMEBREW_TAP_APP_PRIVATE_KEY secrets are set and the App is installed on ${TAP_OWNER}/${TAP_REPO} with Contents: Read and write, then re-run this workflow." >&2 exit 1 fi # We do NOT use actions/checkout for the tap repo because on the diff --git a/.github/workflows/linux-installer.yml b/.github/workflows/linux-installer.yml index cd89c47b..61c488d6 100644 --- a/.github/workflows/linux-installer.yml +++ b/.github/workflows/linux-installer.yml @@ -33,7 +33,7 @@ jobs: contents: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Resolve version id: ver @@ -54,13 +54,13 @@ jobs: - name: Set up QEMU (aarch64 only) if: matrix.qemu - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v4 with: platforms: arm64 - name: Set up Python if: '!matrix.qemu' - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.13" @@ -112,7 +112,7 @@ jobs: run: ls -la dist - name: Upload artifact (per-arch) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: pythinker-linux-${{ matrix.arch }}-${{ steps.ver.outputs.version }} path: | @@ -123,7 +123,7 @@ jobs: - name: Attach to Release (create-or-update) if: startsWith(github.ref, 'refs/tags/v') - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: tag_name: ${{ github.ref_name }} # Mark prerelease so this tag stays OUT of /releases/latest (which is diff --git a/.github/workflows/pr-title-checker.yml b/.github/workflows/pr-title-checker.yml index 7cb665cc..9b6013f1 100644 --- a/.github/workflows/pr-title-checker.yml +++ b/.github/workflows/pr-title-checker.yml @@ -4,12 +4,37 @@ on: pull_request: types: [opened, edited, synchronize, labeled] +permissions: + contents: read + issues: write + pull-requests: read + jobs: check: runs-on: ubuntu-latest name: pr-title-checker steps: - - uses: thehanimo/pr-title-checker@v1.4.3 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - configuration_path: ".github/pr-title-checker-config.json" + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Validate PR title + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + set -euo pipefail + regexp=$(jq -r '.CHECKS.regexp' .github/pr-title-checker-config.json) + label=$(jq -r '.LABEL.name' .github/pr-title-checker-config.json) + color=$(jq -r '.LABEL.color' .github/pr-title-checker-config.json) + failure=$(jq -r '.MESSAGES.failure' .github/pr-title-checker-config.json) + + if [[ "$PR_TITLE" =~ $regexp ]]; then + gh pr edit "$PR_NUMBER" --remove-label "$label" >/dev/null 2>&1 || true + exit 0 + fi + + gh label create "$label" --color "$color" --force >/dev/null 2>&1 || true + gh pr edit "$PR_NUMBER" --add-label "$label" >/dev/null 2>&1 || true + echo "::error::$failure" + exit 1 diff --git a/.github/workflows/release-pythinker-cli.yml b/.github/workflows/release-pythinker-cli.yml index 83655e68..78724aa7 100644 --- a/.github/workflows/release-pythinker-cli.yml +++ b/.github/workflows/release-pythinker-cli.yml @@ -20,7 +20,7 @@ jobs: version: ${{ steps.version.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Derive version from tag id: version @@ -41,7 +41,7 @@ jobs: echo "Derived release version: ${version}" - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true @@ -115,7 +115,7 @@ jobs: PYTHINKER_WEB_EXPECT_VERSION: ${{ needs.validate.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install GNU Make (Windows) if: runner.os == 'Windows' @@ -125,20 +125,20 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" - name: Set up Node.js (web build) - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: "20" + node-version: "24" cache: "npm" cache-dependency-path: web/package-lock.json @@ -496,7 +496,7 @@ jobs: f.write(f"name=pythinker-{ref}-{target}\n") - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ steps.artifact.outputs.name }} path: artifacts/* @@ -517,7 +517,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download all build artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: path: ./downloads merge-multiple: true @@ -538,7 +538,7 @@ jobs: ls -la - name: Create GitHub Release and upload assets - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: tag_name: ${{ github.ref_name }} name: ${{ github.ref_name }} @@ -582,23 +582,23 @@ jobs: PYTHINKER_WEB_EXPECT_VERSION: ${{ needs.validate.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" - name: Set up Node.js (web build) - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: "20" + node-version: "24" cache: "npm" cache-dependency-path: web/package-lock.json @@ -630,23 +630,23 @@ jobs: PYTHINKER_WEB_EXPECT_VERSION: ${{ needs.validate.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" - name: Set up Node.js (web build) - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: "20" + node-version: "24" cache: "npm" cache-dependency-path: web/package-lock.json diff --git a/.github/workflows/release-pythinker-core.yml b/.github/workflows/release-pythinker-core.yml index e28317ea..b527b955 100644 --- a/.github/workflows/release-pythinker-core.yml +++ b/.github/workflows/release-pythinker-core.yml @@ -18,10 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true @@ -43,16 +43,16 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" diff --git a/.github/workflows/release-pythinker-host.yml b/.github/workflows/release-pythinker-host.yml index 446cbfeb..3e3b6d1a 100644 --- a/.github/workflows/release-pythinker-host.yml +++ b/.github/workflows/release-pythinker-host.yml @@ -18,10 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true @@ -43,16 +43,16 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" diff --git a/.github/workflows/release-pythinker-sdk.yml b/.github/workflows/release-pythinker-sdk.yml index 0aea527b..085bff30 100644 --- a/.github/workflows/release-pythinker-sdk.yml +++ b/.github/workflows/release-pythinker-sdk.yml @@ -18,10 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true @@ -43,16 +43,16 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@v8.1.0 with: version: "0.8.5" diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index 821b84c8..327995a7 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions Repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Check spelling of the entire repository uses: crate-ci/typos@v1.38.1 diff --git a/.github/workflows/windows-installer.yml b/.github/workflows/windows-installer.yml index d67b5497..57c00bf1 100644 --- a/.github/workflows/windows-installer.yml +++ b/.github/workflows/windows-installer.yml @@ -23,7 +23,7 @@ jobs: contents: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Resolve version id: ver @@ -41,7 +41,7 @@ jobs: } - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.13" @@ -80,7 +80,7 @@ jobs: pwsh packages/windows-installer/build.ps1 -Version $env:BUILD_VERSION -Python $py - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: PythinkerSetup-${{ steps.ver.outputs.version }} path: | @@ -89,7 +89,7 @@ jobs: - name: Attach to Release (create-or-update) if: startsWith(github.ref, 'refs/tags/v') - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 with: tag_name: ${{ github.ref_name }} # All platform workflows race to create this Release on the same tag. From 6b7bd30bb9fb859319ad3152b70b999296615c4d Mon Sep 17 00:00:00 2001 From: mohamed-elkholy95 Date: Sun, 31 May 2026 19:21:50 -0400 Subject: [PATCH 2/3] ci(actions): update workflows for Node 24 --- .../workflows/changelog-entry-required.yml | 2 +- .github/workflows/ci-docs.yml | 8 +-- .github/workflows/ci-pythinker-cli.yml | 32 +++++----- .github/workflows/ci-pythinker-core.yml | 14 ++--- .github/workflows/ci-pythinker-host.yml | 6 +- .github/workflows/ci-pythinker-sdk.yml | 14 ++--- .../dispatch-pythinker-home-sync.yml | 49 +++++++++++++--- .github/workflows/docs-pages.yml | 14 ++--- .github/workflows/homebrew-tap.yml | 56 ++++++++++++++---- .github/workflows/linux-installer.yml | 10 ++-- .github/workflows/pr-title-checker.yml | 58 ++++++++++++++++++- .github/workflows/promote-release.yml | 55 ++++++++++++++++-- .github/workflows/release-pythinker-cli.yml | 46 +++++++-------- .github/workflows/release-pythinker-core.yml | 12 ++-- .github/workflows/release-pythinker-host.yml | 12 ++-- .github/workflows/release-pythinker-sdk.yml | 12 ++-- .github/workflows/translator.yml | 2 +- .github/workflows/typos.yml | 4 +- .github/workflows/windows-installer.yml | 8 +-- CHANGELOG.md | 1 + tests/test_release_update_pipeline.py | 5 +- 21 files changed, 296 insertions(+), 124 deletions(-) diff --git a/.github/workflows/changelog-entry-required.yml b/.github/workflows/changelog-entry-required.yml index 6a6245f1..aa644f81 100644 --- a/.github/workflows/changelog-entry-required.yml +++ b/.github/workflows/changelog-entry-required.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 with: fetch-depth: 0 # Read-only job (git show/diff on already-fetched history, no push); diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index 5ac55739..9d5f2e13 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -25,15 +25,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # pinned from v6.4.0 with: - node-version: "20" + node-version: "24" - name: Cache docs node_modules - uses: actions/cache@v4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # pinned from v5.0.5 with: path: docs/node_modules key: ${{ runner.os }}-docs-node-modules-${{ hashFiles('docs/package.json') }} diff --git a/.github/workflows/ci-pythinker-cli.yml b/.github/workflows/ci-pythinker-cli.yml index 0c60bb52..4c82a1e2 100644 --- a/.github/workflows/ci-pythinker-cli.yml +++ b/.github/workflows/ci-pythinker-cli.yml @@ -31,17 +31,17 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" enable-cache: true @@ -65,17 +65,17 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python ${{ matrix.python-version }} id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" enable-cache: true @@ -125,7 +125,7 @@ jobs: continue-on-error: ${{ matrix.experimental == true }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Install GNU Make (Windows) if: runner.os == 'Windows' @@ -133,21 +133,21 @@ jobs: - name: Set up Python 3.13 id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.13" - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" enable-cache: true cache-dependency-glob: uv.lock - name: Set up Node.js (web build) - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # pinned from v6.4.0 with: - node-version: "20" + node-version: "24" cache: "npm" cache-dependency-path: web/package-lock.json @@ -190,7 +190,7 @@ jobs: # collide on the artifact name. The probe only needs the build to # succeed; we do not consume its binary. if: success() && !matrix.experimental - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pinned from v7.0.1 with: name: pythinker-${{ matrix.target }} path: ${{ matrix.binary_path }} @@ -202,12 +202,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 with: fetch-depth: 0 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true @@ -319,10 +319,10 @@ jobs: runs-on: ${{ matrix.runner }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main + uses: DeterminateSystems/nix-installer-action@1d87d45818068401a10cf16bdc5f00b24994a83f # pinned from main - name: Run nix package run: nix run .#pythinker-code -- --version && nix run . -- --help diff --git a/.github/workflows/ci-pythinker-core.yml b/.github/workflows/ci-pythinker-core.yml index b7bee136..db96fe36 100644 --- a/.github/workflows/ci-pythinker-core.yml +++ b/.github/workflows/ci-pythinker-core.yml @@ -28,17 +28,17 @@ jobs: python-version: ["3.12", "3.13", "3.14"] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python ${{ matrix.python-version }} id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" enable-cache: true @@ -65,16 +65,16 @@ jobs: FOOTER_VERSION: ${{ github.ref_name }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" enable-cache: true @@ -91,7 +91,7 @@ jobs: -o packages/pythinker-core/docs - name: Upload docs preview - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pinned from v7.0.1 with: name: docs-preview path: packages/pythinker-core/docs diff --git a/.github/workflows/ci-pythinker-host.yml b/.github/workflows/ci-pythinker-host.yml index f479eada..b74c7133 100644 --- a/.github/workflows/ci-pythinker-host.yml +++ b/.github/workflows/ci-pythinker-host.yml @@ -51,7 +51,7 @@ jobs: shell: bash steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Install GNU Make (Windows) if: runner.os == 'Windows' @@ -60,13 +60,13 @@ jobs: - name: Set up Python ${{ matrix.python-version }} id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" enable-cache: true diff --git a/.github/workflows/ci-pythinker-sdk.yml b/.github/workflows/ci-pythinker-sdk.yml index 6de0c3aa..fea0aa64 100644 --- a/.github/workflows/ci-pythinker-sdk.yml +++ b/.github/workflows/ci-pythinker-sdk.yml @@ -28,17 +28,17 @@ jobs: python-version: ["3.12", "3.13", "3.14"] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python ${{ matrix.python-version }} id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" enable-cache: true @@ -65,16 +65,16 @@ jobs: FOOTER_VERSION: ${{ github.ref_name }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" enable-cache: true @@ -91,7 +91,7 @@ jobs: -o sdks/pythinker-sdk/docs - name: Upload docs preview - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pinned from v7.0.1 with: name: docs-preview path: sdks/pythinker-sdk/docs diff --git a/.github/workflows/dispatch-pythinker-home-sync.yml b/.github/workflows/dispatch-pythinker-home-sync.yml index a2ca32a9..9632666f 100644 --- a/.github/workflows/dispatch-pythinker-home-sync.yml +++ b/.github/workflows/dispatch-pythinker-home-sync.yml @@ -32,13 +32,48 @@ jobs: # ~1h TTL, minted fresh each run, scoped to the single private site repo. - name: Mint GitHub App token for pythinker-home id: app-token - uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 - with: - app-id: ${{ secrets.PYTHINKER_RELEASE_BOT_APP_ID }} - private-key: ${{ secrets.PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY }} - owner: ${{ env.DISPATCH_OWNER }} - repositories: ${{ env.DISPATCH_REPO }} - permission-contents: write + env: + APP_ID: ${{ secrets.PYTHINKER_RELEASE_BOT_APP_ID }} + APP_PRIVATE_KEY: ${{ secrets.PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY }} + DISPATCH_OWNER: ${{ env.DISPATCH_OWNER }} + DISPATCH_REPO: ${{ env.DISPATCH_REPO }} + run: | + set -euo pipefail + if [ -z "${APP_ID:-}" ] || [ -z "${APP_PRIVATE_KEY:-}" ]; then + echo "::error::Missing PYTHINKER_RELEASE_BOT_APP_ID or PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY. Configure the org-owned pythinker-release-bot App and install it on ${DISPATCH_OWNER}/${DISPATCH_REPO} with Contents: Read and write." >&2 + exit 1 + fi + + b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; } + key_file=$(mktemp) + trap 'rm -f "$key_file"' EXIT + printf '%s\n' "$APP_PRIVATE_KEY" > "$key_file" + chmod 600 "$key_file" + + now=$(date +%s) + header=$(printf '{"alg":"RS256","typ":"JWT"}' | b64url) + payload=$(jq -nc --argjson iat "$((now - 60))" --argjson exp "$((now + 540))" --arg iss "$APP_ID" '{iat:$iat,exp:$exp,iss:$iss}' | b64url) + unsigned="${header}.${payload}" + signature=$(printf '%s' "$unsigned" | openssl dgst -sha256 -sign "$key_file" | b64url) + jwt="${unsigned}.${signature}" + + installation_id=$(curl --fail-with-body -sS \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${jwt}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/${DISPATCH_OWNER}/${DISPATCH_REPO}/installation" \ + | jq -er '.id') + token=$(jq -nc --arg repo "$DISPATCH_REPO" '{repositories:[$repo],permissions:{contents:"write"}}' \ + | curl --fail-with-body -sS \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${jwt}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/app/installations/${installation_id}/access_tokens" \ + -d @- \ + | jq -er '.token') + echo "::add-mask::$token" + echo "token=$token" >> "$GITHUB_OUTPUT" - name: Trigger pythinker-home sync env: diff --git a/.github/workflows/docs-pages.yml b/.github/workflows/docs-pages.yml index 096cf5d0..b122201c 100644 --- a/.github/workflows/docs-pages.yml +++ b/.github/workflows/docs-pages.yml @@ -24,15 +24,15 @@ jobs: url: ${{ steps.deploy.outputs.page_url }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # pinned from v6.4.0 with: - node-version: "20" + node-version: "24" - name: Cache docs node_modules - uses: actions/cache@v4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # pinned from v5.0.5 with: path: docs/node_modules key: ${{ runner.os }}-docs-node-modules-${{ hashFiles('docs/package.json') }} @@ -41,7 +41,7 @@ jobs: - name: Configure GitHub Pages id: pages - uses: actions/configure-pages@v5 + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # pinned from v6.0.0 with: enablement: true @@ -72,10 +72,10 @@ jobs: run: touch docs/.vitepress/dist/.nojekyll - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # pinned from v5.0.0 with: path: docs/.vitepress/dist - name: Deploy to GitHub Pages id: deploy - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # pinned from v5.0.0 diff --git a/.github/workflows/homebrew-tap.yml b/.github/workflows/homebrew-tap.yml index cc5d25a6..94bc563e 100644 --- a/.github/workflows/homebrew-tap.yml +++ b/.github/workflows/homebrew-tap.yml @@ -25,7 +25,7 @@ jobs: TAP_REPO: homebrew-pythinker steps: - name: Checkout source repo - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Resolve version id: ver @@ -45,7 +45,7 @@ jobs: echo "version=${version}" >> "$GITHUB_OUTPUT" - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.13" @@ -78,21 +78,57 @@ jobs: # other than the one this workflow runs in. - name: Mint GitHub App token for the tap repo id: app-token - uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 - with: - app-id: ${{ secrets.HOMEBREW_TAP_APP_ID }} - private-key: ${{ secrets.HOMEBREW_TAP_APP_PRIVATE_KEY }} - owner: ${{ env.TAP_OWNER }} - repositories: ${{ env.TAP_REPO }} + env: + APP_ID: ${{ secrets.HOMEBREW_TAP_APP_ID }} + APP_PRIVATE_KEY: ${{ secrets.HOMEBREW_TAP_APP_PRIVATE_KEY }} + TAP_OWNER: ${{ env.TAP_OWNER }} + TAP_REPO: ${{ env.TAP_REPO }} + run: | + set -euo pipefail + if [ -z "${APP_ID:-}" ] || [ -z "${APP_PRIVATE_KEY:-}" ]; then + echo "::error::No tap GitHub App credentials available. Configure HOMEBREW_TAP_APP_ID and HOMEBREW_TAP_APP_PRIVATE_KEY, and install the App on ${TAP_OWNER}/${TAP_REPO} with Contents: Read and write." >&2 + exit 1 + fi + + b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; } + key_file=$(mktemp) + trap 'rm -f "$key_file"' EXIT + printf '%s\n' "$APP_PRIVATE_KEY" > "$key_file" + chmod 600 "$key_file" + + now=$(date +%s) + header=$(printf '{"alg":"RS256","typ":"JWT"}' | b64url) + payload=$(jq -nc --argjson iat "$((now - 60))" --argjson exp "$((now + 540))" --arg iss "$APP_ID" '{iat:$iat,exp:$exp,iss:$iss}' | b64url) + unsigned="${header}.${payload}" + signature=$(printf '%s' "$unsigned" | openssl dgst -sha256 -sign "$key_file" | b64url) + jwt="${unsigned}.${signature}" + + installation_id=$(curl --fail-with-body -sS \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${jwt}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/${TAP_OWNER}/${TAP_REPO}/installation" \ + | jq -er '.id') + token=$(jq -nc --arg repo "$TAP_REPO" '{repositories:[$repo],permissions:{contents:"write"}}' \ + | curl --fail-with-body -sS \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${jwt}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/app/installations/${installation_id}/access_tokens" \ + -d @- \ + | jq -er '.token') + echo "::add-mask::$token" + echo "token=$token" >> "$GITHUB_OUTPUT" - name: Sync formula into tap repo (handles empty repo on first run) env: PKG_VERSION: ${{ steps.ver.outputs.version }} TAP_TOKEN: ${{ steps.app-token.outputs.token }} run: | - set -euxo pipefail + set -euo pipefail if [ -z "${TAP_TOKEN:-}" ]; then - echo "::error::No tap token available — the GitHub App token mint produced an empty value. Confirm the HOMEBREW_TAP_APP_ID and HOMEBREW_TAP_APP_PRIVATE_KEY secrets are set and the App is installed on ${TAP_OWNER}/${TAP_REPO} with Contents: Read and write, then re-run this workflow." >&2 + echo "::error::No tap token available — the GitHub App token mint produced an empty value. Confirm HOMEBREW_TAP_APP_ID and HOMEBREW_TAP_APP_PRIVATE_KEY secrets are set and the App is installed on ${TAP_OWNER}/${TAP_REPO} with Contents: Read and write, then re-run this workflow." >&2 exit 1 fi # We do NOT use actions/checkout for the tap repo because on the diff --git a/.github/workflows/linux-installer.yml b/.github/workflows/linux-installer.yml index cd89c47b..7fffe247 100644 --- a/.github/workflows/linux-installer.yml +++ b/.github/workflows/linux-installer.yml @@ -33,7 +33,7 @@ jobs: contents: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Resolve version id: ver @@ -54,13 +54,13 @@ jobs: - name: Set up QEMU (aarch64 only) if: matrix.qemu - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # pinned from v4.1.0 with: platforms: arm64 - name: Set up Python if: '!matrix.qemu' - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.13" @@ -112,7 +112,7 @@ jobs: run: ls -la dist - name: Upload artifact (per-arch) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pinned from v7.0.1 with: name: pythinker-linux-${{ matrix.arch }}-${{ steps.ver.outputs.version }} path: | @@ -123,7 +123,7 @@ jobs: - name: Attach to Release (create-or-update) if: startsWith(github.ref, 'refs/tags/v') - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # pinned from v3.0.0 with: tag_name: ${{ github.ref_name }} # Mark prerelease so this tag stays OUT of /releases/latest (which is diff --git a/.github/workflows/pr-title-checker.yml b/.github/workflows/pr-title-checker.yml index 7cb665cc..c368908c 100644 --- a/.github/workflows/pr-title-checker.yml +++ b/.github/workflows/pr-title-checker.yml @@ -4,12 +4,64 @@ on: pull_request: types: [opened, edited, synchronize, labeled] +permissions: + contents: read # allow checkout of the repo config by default + pull-requests: read # allow PR metadata reads by default + jobs: check: runs-on: ubuntu-latest name: pr-title-checker + permissions: + contents: read # checkout .github/pr-title-checker-config.json + pull-requests: read # read PR title metadata from the event/CLI + issues: write # create/update the Invalid PR Title label on the PR issue steps: - - uses: thehanimo/pr-title-checker@v1.4.3 + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - configuration_path: ".github/pr-title-checker-config.json" + persist-credentials: false + + - name: Validate PR title + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + set -euo pipefail + + config=.github/pr-title-checker-config.json + if [ ! -f "$config" ]; then + echo "::error::PR title checker config is missing at $config." + exit 1 + fi + + read_config_value() { + local query=$1 + local name=$2 + local value + if ! value=$(jq -er "$query" "$config"); then + echo "::error::Failed to read $name from $config." + exit 1 + fi + if [ -z "$value" ] || [ "$value" = "null" ]; then + echo "::error::$name in $config must be non-empty." + exit 1 + fi + printf '%s' "$value" + } + + regexp=$(read_config_value '.CHECKS.regexp' 'CHECKS.regexp') + label=$(read_config_value '.LABEL.name' 'LABEL.name') + color=$(read_config_value '.LABEL.color' 'LABEL.color') + failure=$(read_config_value '.MESSAGES.failure' 'MESSAGES.failure') + + if [[ "$PR_TITLE" =~ $regexp ]]; then + gh pr edit "$PR_NUMBER" --remove-label "$label" >/dev/null 2>&1 || true + exit 0 + fi + + gh label create "$label" --color "$color" --force >/dev/null 2>&1 || true + gh pr edit "$PR_NUMBER" --add-label "$label" >/dev/null 2>&1 || true + echo "::error::$failure" + exit 1 diff --git a/.github/workflows/promote-release.yml b/.github/workflows/promote-release.yml index 8f0f333f..88f711d9 100644 --- a/.github/workflows/promote-release.yml +++ b/.github/workflows/promote-release.yml @@ -163,16 +163,63 @@ jobs: gh api -X PATCH "repos/$REPO/releases/$release_id" -F prerelease=false -f make_latest=true echo "Promoted $TAG: prerelease=false, make_latest=true (all platform assets present)." + - name: Mint GitHub App token for pythinker-home + id: app-token + env: + APP_ID: ${{ secrets.PYTHINKER_RELEASE_BOT_APP_ID }} + APP_PRIVATE_KEY: ${{ secrets.PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY }} + DISPATCH_OWNER: TechMatrix-labs + DISPATCH_REPO: pythinker-home + run: | + set -euo pipefail + if [ -z "${APP_ID:-}" ] || [ -z "${APP_PRIVATE_KEY:-}" ]; then + echo "::error::Missing PYTHINKER_RELEASE_BOT_APP_ID or PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY. Configure the org-owned pythinker-release-bot App and install it on ${DISPATCH_OWNER}/${DISPATCH_REPO} with Contents: Read and write." >&2 + exit 1 + fi + + b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; } + key_file=$(mktemp) + trap 'rm -f "$key_file"' EXIT + printf '%s\n' "$APP_PRIVATE_KEY" > "$key_file" + chmod 600 "$key_file" + + now=$(date +%s) + header=$(printf '{"alg":"RS256","typ":"JWT"}' | b64url) + payload=$(jq -nc --argjson iat "$((now - 60))" --argjson exp "$((now + 540))" --arg iss "$APP_ID" '{iat:$iat,exp:$exp,iss:$iss}' | b64url) + unsigned="${header}.${payload}" + signature=$(printf '%s' "$unsigned" | openssl dgst -sha256 -sign "$key_file" | b64url) + jwt="${unsigned}.${signature}" + + installation_id=$(curl --fail-with-body -sS \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${jwt}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/${DISPATCH_OWNER}/${DISPATCH_REPO}/installation" \ + | jq -er '.id') + token=$(jq -nc --arg repo "$DISPATCH_REPO" '{repositories:[$repo],permissions:{contents:"write"}}' \ + | curl --fail-with-body -sS \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${jwt}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/app/installations/${installation_id}/access_tokens" \ + -d @- \ + | jq -er '.token') + echo "::add-mask::$token" + echo "token=$token" >> "$GITHUB_OUTPUT" + - name: Trigger pythinker-home sync env: - DISPATCH_TOKEN: ${{ secrets.PYTHINKER_HOME_REPO_DISPATCH_TOKEN }} + DISPATCH_TOKEN: ${{ steps.app-token.outputs.token }} SOURCE_REPO: ${{ github.repository }} RELEASE_TAG: ${{ steps.tag.outputs.tag }} + DISPATCH_OWNER: TechMatrix-labs + DISPATCH_REPO: pythinker-home run: | set -euo pipefail if [ -z "${DISPATCH_TOKEN:-}" ]; then - echo "::notice::Skipping pythinker-home sync: PYTHINKER_HOME_REPO_DISPATCH_TOKEN is not configured" - exit 0 + echo "::error::No dispatch token: the pythinker-release-bot App token mint produced an empty value. Confirm PYTHINKER_RELEASE_BOT_APP_ID and PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY org secrets are set and the App is installed on ${DISPATCH_OWNER}/${DISPATCH_REPO} with Contents: Read and write." >&2 + exit 1 fi payload=$(jq -n \ --arg source_repo "$SOURCE_REPO" \ @@ -182,7 +229,7 @@ jobs: -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer $DISPATCH_TOKEN" \ - https://api.github.com/repos/TechMatrix-labs/pythinker-home/dispatches \ + "https://api.github.com/repos/${DISPATCH_OWNER}/${DISPATCH_REPO}/dispatches" \ -d "$payload" notify-failure: diff --git a/.github/workflows/release-pythinker-cli.yml b/.github/workflows/release-pythinker-cli.yml index 83655e68..2ed824b4 100644 --- a/.github/workflows/release-pythinker-cli.yml +++ b/.github/workflows/release-pythinker-cli.yml @@ -20,7 +20,7 @@ jobs: version: ${{ steps.version.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Derive version from tag id: version @@ -41,7 +41,7 @@ jobs: echo "Derived release version: ${version}" - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true @@ -115,30 +115,30 @@ jobs: PYTHINKER_WEB_EXPECT_VERSION: ${{ needs.validate.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Install GNU Make (Windows) if: runner.os == 'Windows' run: choco install make -y - name: Set up Rust - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # pinned from stable - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" - name: Set up Node.js (web build) - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # pinned from v6.4.0 with: - node-version: "20" + node-version: "24" cache: "npm" cache-dependency-path: web/package-lock.json @@ -496,7 +496,7 @@ jobs: f.write(f"name=pythinker-{ref}-{target}\n") - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pinned from v7.0.1 with: name: ${{ steps.artifact.outputs.name }} path: artifacts/* @@ -517,7 +517,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download all build artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pinned from v8.0.1 with: path: ./downloads merge-multiple: true @@ -538,7 +538,7 @@ jobs: ls -la - name: Create GitHub Release and upload assets - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # pinned from v3.0.0 with: tag_name: ${{ github.ref_name }} name: ${{ github.ref_name }} @@ -582,23 +582,23 @@ jobs: PYTHINKER_WEB_EXPECT_VERSION: ${{ needs.validate.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" - name: Set up Node.js (web build) - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # pinned from v6.4.0 with: - node-version: "20" + node-version: "24" cache: "npm" cache-dependency-path: web/package-lock.json @@ -606,7 +606,7 @@ jobs: run: make build-pythinker-code - name: Publish to TestPyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # pinned from release/v1 with: repository-url: https://test.pypi.org/legacy/ packages-dir: dist @@ -630,23 +630,23 @@ jobs: PYTHINKER_WEB_EXPECT_VERSION: ${{ needs.validate.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" - name: Set up Node.js (web build) - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # pinned from v6.4.0 with: - node-version: "20" + node-version: "24" cache: "npm" cache-dependency-path: web/package-lock.json @@ -654,7 +654,7 @@ jobs: run: make build-pythinker-code - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # pinned from release/v1 with: packages-dir: dist # Idempotent on re-runs: skip files already published (e.g. when the diff --git a/.github/workflows/release-pythinker-core.yml b/.github/workflows/release-pythinker-core.yml index e28317ea..035132e0 100644 --- a/.github/workflows/release-pythinker-core.yml +++ b/.github/workflows/release-pythinker-core.yml @@ -18,10 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true @@ -43,16 +43,16 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" @@ -60,7 +60,7 @@ jobs: run: make build-pythinker-core - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # pinned from release/v1 with: packages-dir: dist/pythinker-core diff --git a/.github/workflows/release-pythinker-host.yml b/.github/workflows/release-pythinker-host.yml index 446cbfeb..dd9bf925 100644 --- a/.github/workflows/release-pythinker-host.yml +++ b/.github/workflows/release-pythinker-host.yml @@ -18,10 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true @@ -43,16 +43,16 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" @@ -60,6 +60,6 @@ jobs: run: make build-pythinker-host - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # pinned from release/v1 with: packages-dir: dist/pythinker-host diff --git a/.github/workflows/release-pythinker-sdk.yml b/.github/workflows/release-pythinker-sdk.yml index 0aea527b..481a08c5 100644 --- a/.github/workflows/release-pythinker-sdk.yml +++ b/.github/workflows/release-pythinker-sdk.yml @@ -18,10 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true @@ -43,16 +43,16 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Set up Python 3.14 - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.14" allow-prereleases: true - name: Set up uv - uses: astral-sh/setup-uv@v1 + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # pinned from v8.1.0 with: version: "0.8.5" @@ -60,6 +60,6 @@ jobs: run: make build-pythinker-sdk - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # pinned from release/v1 with: packages-dir: dist/pythinker-sdk diff --git a/.github/workflows/translator.yml b/.github/workflows/translator.yml index 8b2f126d..e08676bd 100644 --- a/.github/workflows/translator.yml +++ b/.github/workflows/translator.yml @@ -21,7 +21,7 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: lizheming/github-translate-action@1.1.2 + - uses: lizheming/github-translate-action@c55aac477e98562d4faed9f77c54ab8306ae6ebf # pinned from 1.1.2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index 821b84c8..2a4683c1 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions Repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Check spelling of the entire repository - uses: crate-ci/typos@v1.38.1 + uses: crate-ci/typos@80c8a4945eec0f6d464eaf9e65ed98ef085283d1 # pinned from v1.38.1 diff --git a/.github/workflows/windows-installer.yml b/.github/workflows/windows-installer.yml index d67b5497..5fc6581b 100644 --- a/.github/workflows/windows-installer.yml +++ b/.github/workflows/windows-installer.yml @@ -23,7 +23,7 @@ jobs: contents: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pinned from v6.0.2 - name: Resolve version id: ver @@ -41,7 +41,7 @@ jobs: } - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pinned from v6.2.0 with: python-version: "3.13" @@ -80,7 +80,7 @@ jobs: pwsh packages/windows-installer/build.ps1 -Version $env:BUILD_VERSION -Python $py - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pinned from v7.0.1 with: name: PythinkerSetup-${{ steps.ver.outputs.version }} path: | @@ -89,7 +89,7 @@ jobs: - name: Attach to Release (create-or-update) if: startsWith(github.ref, 'refs/tags/v') - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # pinned from v3.0.0 with: tag_name: ${{ github.ref_name }} # All platform workflows race to create this Release on the same tag. diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0f1fc8..32ae8c04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ GitHub Releases page; `0.8.0` is the new starting line. ## Unreleased +- CI and release workflows now run on Node.js 24-backed GitHub Actions, pin action revisions to immutable commits, and preflight optional website/tap GitHub App credentials with clear errors or notices instead of opaque token failures. - Release pipeline: migrate the pythinker-home website-sync dispatch to the org-owned `pythinker-release-bot` GitHub App and fail loud on an empty token; retire the dead pythinker-core API-docs gh-pages publish step; add exponential backoff to the native install scripts and fix the Windows installer's release-pagination cliff. - **Redesigned startup welcome banner.** The banner now uses a cleaner footer-chip layout: the "What's new / Update available" chip sits on the panel's bottom border, the headline/strapline/help lines align beside the robot logo, and the info grid drops its vertical separator. The robot art and palette are unchanged. - **Terminal-aware rendering for minimal and CI terminals.** The shell UI adapts to the terminal — ASCII glyph fallbacks for `TERM=dumb` and legacy Windows code pages, reduced-motion mode (`PYTHINKER_REDUCED_MOTION`), and `NO_COLOR`/`CLICOLOR` support that strips color cleanly — so output stays readable in CI logs, SSH panes, and bare terminals. diff --git a/tests/test_release_update_pipeline.py b/tests/test_release_update_pipeline.py index 3a49d377..ed55fbf5 100644 --- a/tests/test_release_update_pipeline.py +++ b/tests/test_release_update_pipeline.py @@ -72,10 +72,11 @@ def test_site_dispatch_uses_scoped_github_app_token_and_fails_loud() -> None: workflow = (WORKFLOWS / "dispatch-pythinker-home-sync.yml").read_text() assert "PYTHINKER_HOME_REPO_DISPATCH_TOKEN" not in workflow - assert "actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349" in workflow - assert "permission-contents: write" in workflow + assert "actions/create-github-app-token" not in workflow + assert 'permissions:{contents:"write"}' in workflow assert "PYTHINKER_RELEASE_BOT_APP_ID" in workflow assert "PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY" in workflow + assert "Missing PYTHINKER_RELEASE_BOT_APP_ID" in workflow assert "exit 1" in workflow assert "Skipping pythinker-home sync" not in workflow From 755e806e1eddb504629f9a510a58809ca3751533 Mon Sep 17 00:00:00 2001 From: mohamed-elkholy95 Date: Sun, 31 May 2026 19:58:05 -0400 Subject: [PATCH 3/3] test(release): relax app token permission assertion --- tests/test_release_update_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_release_update_pipeline.py b/tests/test_release_update_pipeline.py index ed55fbf5..dc632b33 100644 --- a/tests/test_release_update_pipeline.py +++ b/tests/test_release_update_pipeline.py @@ -73,7 +73,7 @@ def test_site_dispatch_uses_scoped_github_app_token_and_fails_loud() -> None: assert "PYTHINKER_HOME_REPO_DISPATCH_TOKEN" not in workflow assert "actions/create-github-app-token" not in workflow - assert 'permissions:{contents:"write"}' in workflow + assert re.search(r"permissions\s*:\s*\{[^}]*contents\s*:\s*\"write\"", workflow) assert "PYTHINKER_RELEASE_BOT_APP_ID" in workflow assert "PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY" in workflow assert "Missing PYTHINKER_RELEASE_BOT_APP_ID" in workflow