From a73ac5516c56cbb1e760012ab6c411fd16912cce Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 25 Aug 2026 08:14:29 +0000 Subject: [PATCH] Unfreeze the linter pin, and add the workflow that keeps it moving `npm ci` reads package-lock.json, and the lock here sat at @abap2ui5/linter 0.2.2 while two releases went by. The range made that permanent rather than accidental: `^0.2.2` means `>=0.2.2 <0.3.0`, so 0.3.0 could not arrive even through a fresh install, and nothing in this repository was ever going to move it. The gate stayed green the whole time and said less every release without saying so. Moved to 0.3.0 and verified before committing: `npx abap2ui5lint` over the full corpus, no findings. The render runtime rides along deliberately - the two are ONE release with one version (the linter's metadata snapshot is generated from exactly the @openui5 version pinned over there), so bumping one alone is the drift that splitting them was allowed on condition of avoiding. The bump workflow is the part that matters more than the number. It is samples-controls' one, adapted to this repository's own gate: weekly, tracking `latest` rather than the declared range, running the linter over the corpus BEFORE the PR exists so a rule regression fails the bump instead of landing on main. Scheduled after samples-controls' so the three corpora move in a known order. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01E8iuqE8QFQXpb1LzHQ3Ym5 --- .github/workflows/bump-linter.yaml | 86 ++++++++++++++++++++++++++++++ package-lock.json | 18 +++---- package.json | 4 +- 3 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/bump-linter.yaml diff --git a/.github/workflows/bump-linter.yaml b/.github/workflows/bump-linter.yaml new file mode 100644 index 0000000..5a114d2 --- /dev/null +++ b/.github/workflows/bump-linter.yaml @@ -0,0 +1,86 @@ +# The linter comes from npm as `@abap2ui5/linter`, and package-lock.json is +# what actually decides which version the gate runs: `npm ci` reads the lock, +# so a new release reaches this corpus only when the lock moves. Nothing moved +# it here for two releases - the lock sat at 0.2.2 while the range said +# `^0.2.2`, which cannot reach 0.3.x at all, so the corpus was frozen on a +# linter two releases old and its green check said less every week without +# saying so. This workflow moves it weekly and opens a PR. +# +# It tracks `latest` rather than staying inside the declared range, because the +# range is the thing being maintained here: a linter release that adds rules is +# additive for the linter and breaking for a corpus, so a range that pins the +# corpus out of new rules is the failure, not the protection. The gate runs +# before the PR exists, which is what makes that safe - a rule regression over +# the corpus fails this workflow instead of landing on main. +# +# The render runtime rides along deliberately: the two are ONE release with one +# version (the linter's metadata snapshot is generated from exactly the +# @openui5 version pinned over there), so bumping one alone is the drift the +# split was allowed on condition of avoiding. +name: bump-linter + +on: + schedule: + - cron: '47 6 * * 1' # Mondays 06:47 UTC - after samples and samples-controls + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + bump-linter: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: '22' + + - name: Move @abap2ui5/linter to the latest published version + id: pin + run: | + set -euo pipefail + # Resolved first and checked, because `npm view` prints nothing and + # still exits 0 when a package has no `latest` dist-tag - installing + # `@abap2ui5/linter@` would then resolve to whatever npm felt like. + VERSION=$(npm view @abap2ui5/linter version) + test -n "$VERSION" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + # Writes the range in package.json AND the exact version in the lock. + # Both matter: the range is what a fresh install reads, the lock is + # what `npm ci` reads, and the gate below runs on the lock. + npm install --save-dev "@abap2ui5/linter@$VERSION" "@abap2ui5/render-runtime@$VERSION" + # package.json alone is not the signal: a release inside the declared + # range moves only package-lock.json, and that is exactly the bump this + # corpus needs to see. + if git diff --quiet package.json package-lock.json; then + echo "changed=false" >> "$GITHUB_OUTPUT" + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + # the gate that consumes the linter - a rule regression over the corpus + # surfaces here, in the PR run, not on main + - if: steps.pin.outputs.changed == 'true' + run: npx playwright install --with-deps chromium + - if: steps.pin.outputs.changed == 'true' + run: npm run check:abap2ui5 + + # the badges are written by the run above; they belong to the gate's own + # workflow, not to this one + - if: steps.pin.outputs.changed == 'true' + run: git checkout -- .github/badges/ || true + + - if: steps.pin.outputs.changed == 'true' + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 + with: + branch: bump-linter + title: 'chore: bump @abap2ui5/linter' + commit-message: 'chore: bump @abap2ui5/linter to ${{ steps.pin.outputs.version }}' + body: | + Weekly move of `@abap2ui5/linter` and `@abap2ui5/render-runtime` to + the latest version on npm (${{ steps.pin.outputs.version }}). The + linter gate ran over the full corpus in the workflow that opened + this PR. diff --git a/package-lock.json b/package-lock.json index 25d2f44..6ab0921 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,8 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "@abap2ui5/linter": "^0.2.2", - "@abap2ui5/render-runtime": "^0.2.2", + "@abap2ui5/linter": "^0.3.0", + "@abap2ui5/render-runtime": "^0.3.0", "@abaplint/cli": "^2.120.23" }, "engines": { @@ -18,9 +18,9 @@ } }, "node_modules/@abap2ui5/linter": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@abap2ui5/linter/-/linter-0.2.2.tgz", - "integrity": "sha512-WegxIRN5M5gH13Ye5Mo13fbpjAZ183J0ei1iArCfEiKUPAGqHot20NnckpNnXHX+YPHCkehA+Z0QapXjaLK1Tw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@abap2ui5/linter/-/linter-0.3.0.tgz", + "integrity": "sha512-Z02eNr8Q1TbdEf7/EHbB0aUQmyZi/KvjMi89+H08AFwvJN5ZEPmIHfdge+cwgxqzS28CtUdDmWERsnnQblIz5w==", "dev": true, "license": "MIT", "workspaces": [ @@ -33,7 +33,7 @@ "node": ">=22" }, "peerDependencies": { - "@abap2ui5/render-runtime": "^0.1.0 || ^0.2.0" + "@abap2ui5/render-runtime": "^0.1.0 || ^0.2.0 || ^0.3.0" }, "peerDependenciesMeta": { "@abap2ui5/render-runtime": { @@ -42,9 +42,9 @@ } }, "node_modules/@abap2ui5/render-runtime": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@abap2ui5/render-runtime/-/render-runtime-0.2.2.tgz", - "integrity": "sha512-6DTHLxaIUoFb1I7qPLqjFFBtLNbgOE7cFpAlWKRBLzM/x+3mmm6JG5uIAGJaS3AFmFMV/J9coAxCXez1hqL7Tw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@abap2ui5/render-runtime/-/render-runtime-0.3.0.tgz", + "integrity": "sha512-xXv3dJuD1qk5GS/u7p9V7g/Yf1wKu1qUj/ya1rSqeXKgvZ1AbaQGi0gJ7zukAjin+eNkAtXLira4kDFukEIhqw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 305d7f1..58708fc 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,8 @@ }, "homepage": "https://github.com/abap2UI5/samples-stack#readme", "devDependencies": { - "@abap2ui5/linter": "^0.2.2", - "@abap2ui5/render-runtime": "^0.2.2", + "@abap2ui5/linter": "^0.3.0", + "@abap2ui5/render-runtime": "^0.3.0", "@abaplint/cli": "^2.120.23" }, "engines": {