Skip to content

tooling-pin-check

tooling-pin-check #15

# Detects when newer versions of the development tooling pinned outside any
# Dependabot-readable manifest are available, and raises a PR bumping them for
# evaluation.
#
# What it covers (and why Dependabot can't):
# - @playwright/mcp, pinned in BOTH .devcontainer/setup.sh and .mcp.json. These
# live in a shell script and an MCP config, not a package.json, so Dependabot's
# npm ecosystem never sees them. The two pins must move in lockstep or the
# installed browser and the MCP server drift apart.
# - dotnet-ef, installed via `dotnet tool install` in .devcontainer/setup.sh.
# Not a .csproj reference, so Dependabot's nuget ecosystem never sees it.
#
# See .github/scripts/check-tooling-pins.ps1 (detection: npm/NuGet registry
# lookups, no Docker) and .github/scripts/open-pin-pr.ps1 (the shared
# signed-commit PR opener, also used by apt-pin-check).
#
# Identity / token choice is identical to apt-pin-check: the PR is opened by the
# jim-automation GitHub App, not the default GITHUB_TOKEN. Two reasons:
# 1. `main` requires signed commits; commits created via the GitHub API (the
# GraphQL createCommitOnBranch mutation in open-pin-pr.ps1) are signed by
# GitHub, and an App installation token authorises them.
# 2. A PR opened with GITHUB_TOKEN does NOT trigger the required-check
# workflows, so it could never satisfy branch protection. App-authored
# events DO trigger them, so the bump PR runs CI and can merge.
# The App's credentials are reused from apt-pin-check (JIM_AUTOMATION_APP_ID /
# JIM_AUTOMATION_PRIVATE_KEY); the App is already scoped to Contents and Pull
# requests (read/write) on this repository, which is all this workflow needs.
name: tooling-pin-check
on:
schedule:
# Weekly, Mondays at 06:00 UTC. Dev tooling moves far slower than the daily
# Ubuntu archive the apt check watches, so a weekly poll is ample.
- cron: '0 6 * * 1'
workflow_dispatch:
permissions:
contents: write
pull-requests: write
concurrency:
group: tooling-pin-check
cancel-in-progress: true
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Detect and apply available tooling pin updates
id: check
shell: pwsh
run: |
./.github/scripts/check-tooling-pins.ps1 -Apply
# 2 means "updates applied" and 3 means "a pinned version is no longer
# published". Neither stops the run here: the bump PR is raised first,
# and the withdrawn pin is failed on at the end, so the run that
# reports the problem is also the run that proposes the fix.
if ($LASTEXITCODE -in @(2, 3)) { exit 0 }
exit $LASTEXITCODE
# Minted unconditionally: with no bump to propose the next step still has
# a stale bump PR to close deliberately.
- name: Mint GitHub App installation token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.JIM_AUTOMATION_APP_ID }}
private-key: ${{ secrets.JIM_AUTOMATION_PRIVATE_KEY }}
- name: Open, update or close the bump PR
shell: pwsh
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
$intro = @'
Newer versions of development tooling pinned outside any Dependabot-readable
manifest (.devcontainer/setup.sh, .mcp.json) are available upstream. Raised
for evaluation by the tooling-pin-check workflow. Where a tool is pinned in
more than one file, every location has been moved to the same version.
'@
# Close a stale bump PR only when detection actually reported nothing
# to propose. A clean tree for any other reason (a bump that failed to
# apply, say) leaves the PR alone.
$nothingToPropose = '${{ steps.check.outputs.has_updates }}' -ne 'true'
./.github/scripts/open-pin-pr.ps1 `
-BodyFile tooling-pin-pr-body.md `
-FilePattern '(^|/)(setup\.sh|\.mcp\.json)$' `
-Branch 'automation/tooling-pin-updates' `
-CommitHeadline 'chore(deps): bump pinned development tooling versions' `
-CommitBodyIntro $intro `
-Label 'dependencies' `
-CloseStalePr:$nothingToPropose
# Deliberately the last step, and deliberately a failure. A pinned version
# the registry no longer offers cannot be installed, so the devcontainer
# cannot be built from these pins, and asking only "is something newer
# available?" would have reported that pin as current. Same shape as the
# apt check's gate, for the same reason (#1374).
- name: Fail when a pinned tool version is no longer published
if: steps.check.outputs.unavailable == 'true'
shell: pwsh
run: |
$tools = '${{ steps.check.outputs.unavailable_tools }}'
Write-Host "::error title=Pinned tooling withdrawn upstream::The pinned version of $tools is no longer published. See the job log, and land the bump PR this run raised."
exit 1