From 8c7af1338212484eff348a9a50c8b680d686a3a3 Mon Sep 17 00:00:00 2001 From: Steven McClankerton Date: Thu, 3 Sep 2026 11:27:19 +0000 Subject: [PATCH 1/3] Move Prisma CLI bumps out of the release workflow and release from main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit release.yml no longer writes to the repository. The prisma_version input, the dependency-bump commit and the stable branch reset are gone, so the plan job drops contents: write and the bot token and checks out with persist-credentials: false. Only the release job holds write access now, to create the tag and GitHub release. Dependency updates move to bump_prisma.yml: a manual dispatch that pins the Prisma CLI dependencies and pushes one commit. A bump on main then triggers an insider release through the existing push trigger, and a stable release is a separate dispatch. check_for_prisma_update.yml dispatches the bump workflow instead of the release workflow. Both channels now release from main. The stable branch was only there to hold GA Prisma pins while main tracked dev, and the channel does not otherwise affect dependencies — it selects the extension identity and the npm dist-tag. Removing it also removes the case where a stable release shipped a branch that was behind main. The pin-rewriting logic moves from update_package_json_files.mjs into bump_prisma_dependencies.mjs as a pure function with tests; update_package_json_files.mjs keeps only the build-time name and version stamping. The version planner loses the 'auto' bump, which derived the stable bump from the Prisma CLI version that is no longer an input. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01YJFVnTXe5iAtFHpARAg4ZU --- .github/workflows/bump_prisma.yml | 87 +++++++++++++++++++ .github/workflows/check_for_prisma_update.yml | 27 +++--- .github/workflows/release.yml | 63 ++++---------- docs/ci-cd.md | 82 +++++++++-------- .../bump-prisma-dependencies.test.mjs | 48 ++++++++++ .../__tests__/next-extension-version.test.mjs | 48 +++------- scripts/bump_prisma_dependencies.mjs | 52 +++++++++++ scripts/next_extension_version.mjs | 43 ++------- scripts/update_package_json_files.mjs | 51 ++--------- 9 files changed, 291 insertions(+), 210 deletions(-) create mode 100644 .github/workflows/bump_prisma.yml create mode 100644 scripts/__tests__/bump-prisma-dependencies.test.mjs create mode 100644 scripts/bump_prisma_dependencies.mjs diff --git a/.github/workflows/bump_prisma.yml b/.github/workflows/bump_prisma.yml new file mode 100644 index 0000000000..6b55a7fb75 --- /dev/null +++ b/.github/workflows/bump_prisma.yml @@ -0,0 +1,87 @@ +name: Bump Prisma CLI +run-name: "Bump Prisma CLI to ${{ inputs.prisma_version }} on ${{ inputs.ref || 'main' }}" + +# Updates the Prisma CLI dependencies and pushes the change to the branch. +# +# Publishing is a separate workflow. A bump pushed to main triggers an insider +# release through release.yml's push trigger; a stable release is always a +# manual dispatch of release.yml. + +on: + workflow_dispatch: + inputs: + prisma_version: + description: 'Prisma CLI version to pin the dependencies to (e.g. 7.9.0)' + required: true + ref: + description: 'Branch to bump. Defaults to main. Use an x.y.x branch to patch an older version.' + required: false + +concurrency: + group: bump-prisma + cancel-in-progress: false + +permissions: + contents: read + +env: + ENVIRONMENT: ${{ secrets.ENVIRONMENT }} + PRISMA_TELEMETRY_INFORMATION: 'language-tools bump_prisma.yml' + +jobs: + bump: + name: Bump Prisma CLI dependencies + if: github.repository == 'prisma/language-tools' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Validate inputs + env: + PRISMA_VERSION: ${{ inputs.prisma_version }} + INPUT_REF: ${{ inputs.ref }} + run: | + if ! echo "$PRISMA_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then + echo "'$PRISMA_VERSION' is not a Prisma CLI version." >&2 + exit 1 + fi + REF="${INPUT_REF:-main}" + case "$REF" in + main) ;; + *) + if ! echo "$REF" | grep -Eq '^[0-9]+\.[0-9]+\.x$'; then + echo "Refusing to bump '$REF'. Bumps run on main or an x.y.x patch branch." >&2 + exit 1 + fi + ;; + esac + echo "REF=$REF" >> "$GITHUB_ENV" + - uses: actions/checkout@v4 + with: + ref: ${{ env.REF }} + token: ${{ secrets.PRISMA_BOT_TOKEN }} + - name: Install pnpm + uses: pnpm/action-setup@v4 + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'pnpm' + - name: Install Dependencies + run: pnpm install + - name: Bump Prisma CLI dependencies + env: + PRISMA_VERSION: ${{ inputs.prisma_version }} + run: node scripts/bump_prisma_dependencies.mjs "$PRISMA_VERSION" + - name: Update the lockfile + run: pnpm install --no-frozen-lockfile + - name: Commit and push + env: + PRISMA_VERSION: ${{ inputs.prisma_version }} + run: | + if git diff --quiet; then + echo "Dependencies are already pinned to $PRISMA_VERSION, nothing to commit." + exit 0 + fi + sh scripts/set_git_credentials.sh + git commit -am "bump Prisma CLI to $PRISMA_VERSION" + git push origin "HEAD:$REF" diff --git a/.github/workflows/check_for_prisma_update.yml b/.github/workflows/check_for_prisma_update.yml index 66a94e620d..8994ecb6df 100644 --- a/.github/workflows/check_for_prisma_update.yml +++ b/.github/workflows/check_for_prisma_update.yml @@ -1,11 +1,11 @@ name: Check for Prisma CLI update -# Polls npm for new Prisma CLI versions and starts the Release workflow -# (release.yml) for every channel that has a new version: +# Polls npm for new Prisma CLI versions and starts the Bump Prisma CLI +# workflow (bump_prisma.yml) for every channel that has a new version: # -# - dev -> insider release from main -# - latest -> stable release from the stable branch -# - patch-dev -> insider release from the x.y.x patch branch +# - dev, latest -> bump main; the push to main publishes an insider release, +# and a stable release is a manual dispatch of release.yml +# - patch-dev -> bump the x.y.x patch branch, then release from it on: # Scheduled trigger disabled: ORM iteration is paused; CLI-update polling @@ -14,6 +14,9 @@ on: # - cron: '*/5 * * * *' workflow_dispatch: +permissions: + contents: read + env: ENVIRONMENT: ${{ secrets.ENVIRONMENT }} PRISMA_TELEMETRY_INFORMATION: 'language-tools check_for_prisma_update.yml' @@ -59,17 +62,17 @@ jobs: git commit -am "[skip ci] record new Prisma CLI versions" git push - - name: Release insider (Prisma dev) + - name: Bump main (Prisma dev) if: steps.check_update.outputs.dev_version env: DEV_VERSION: ${{ steps.check_update.outputs.dev_version }} - run: gh workflow run release.yml --ref main -f channel=insider -f prisma_version="$DEV_VERSION" - - name: Release stable (Prisma latest) - if: steps.check_update.outputs.latest_version + run: gh workflow run bump_prisma.yml --ref main -f prisma_version="$DEV_VERSION" + - name: Bump main (Prisma latest) + if: steps.check_update.outputs.latest_version && !steps.check_update.outputs.dev_version env: LATEST_VERSION: ${{ steps.check_update.outputs.latest_version }} - run: gh workflow run release.yml --ref main -f channel=stable -f prisma_version="$LATEST_VERSION" - - name: Release insider from patch branch (Prisma patch-dev) + run: gh workflow run bump_prisma.yml --ref main -f prisma_version="$LATEST_VERSION" + - name: Bump the patch branch (Prisma patch-dev) if: steps.check_update.outputs.patch-dev_version env: PATCH_DEV_VERSION: ${{ steps.check_update.outputs.patch-dev_version }} @@ -80,4 +83,4 @@ jobs: git branch "$BRANCH" "$(cat scripts/versions/tested_extension_stable)" git push origin "$BRANCH" fi - gh workflow run release.yml --ref main -f channel=insider -f ref="$BRANCH" -f prisma_version="$PATCH_DEV_VERSION" + gh workflow run bump_prisma.yml --ref main -f prisma_version="$PATCH_DEV_VERSION" -f ref="$BRANCH" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4cbcb11658..254a13fe76 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,19 +1,17 @@ name: Release -run-name: "Release ${{ github.event_name == 'push' && 'insider (push to main)' || format('{0}{1}', inputs.channel, inputs.prisma_version != '' && format(' — Prisma CLI {0}', inputs.prisma_version) || '') }}" +run-name: "Release ${{ github.event_name == 'push' && 'insider (push to main)' || format('{0} from {1}', inputs.channel, inputs.ref || 'main') }}" # The single publishing pipeline for both the insider and the stable extension. # # - A push to main publishes an insider release. -# - A manual dispatch publishes an insider or stable release, optionally -# bumping the Prisma CLI dependencies first (`prisma_version`), optionally -# from another branch (`ref`, e.g. an x.y.x patch branch). -# - check_for_prisma_update.yml dispatches this workflow when a new Prisma CLI -# version is published to npm. +# - A manual dispatch publishes an insider or stable release, optionally from +# an x.y.x patch branch (`ref`). # -# The next extension version is derived from the git release tags (`x.y.z` for -# stable, `insider/x.y.z` for insider), so a release only creates a commit when -# it actually changes dependencies (`prisma_version` given). All other jobs -# check out the exact commit resolved by the `plan` job. +# This workflow never writes to the repository. The next extension version is +# derived from the git release tags (`x.y.z` for stable, `insider/x.y.z` for +# insider), and Prisma CLI dependency updates are a separate workflow +# (bump_prisma.yml) that commits to main. Only the `release` job holds write +# access, to create the tag and GitHub release. on: push: @@ -32,21 +30,17 @@ on: - stable default: insider ref: - description: 'Branch to release from. Defaults to main for insider and stable for stable. Use an x.y.x branch to patch an older version.' + description: 'Branch to release from. Defaults to main. Use an x.y.x branch to patch an older version.' required: false bump: - description: "Extension version bump (stable only; 'auto' derives it from the Prisma CLI version)" + description: 'Extension version bump (stable only; insider is always a patch)' required: false type: choice options: - - auto - patch - minor - major - default: auto - prisma_version: - description: 'Bump the Prisma CLI dependencies to this version before releasing (creates one commit on the release branch)' - required: false + default: patch concurrency: group: release @@ -66,8 +60,6 @@ jobs: if: github.repository == 'prisma/language-tools' runs-on: ubuntu-latest timeout-minutes: 10 - permissions: - contents: write outputs: channel: ${{ steps.params.outputs.channel }} ref: ${{ steps.params.outputs.ref }} @@ -91,15 +83,12 @@ jobs: REF="$PUSH_SHA" else CHANNEL="$INPUT_CHANNEL" - REF="$INPUT_REF" - if [ -z "$REF" ]; then - if [ "$CHANNEL" = "stable" ]; then REF=stable; else REF=main; fi - fi + REF="${INPUT_REF:-main}" case "$REF" in - main | stable) ;; + main) ;; *) if ! echo "$REF" | grep -Eq '^[0-9]+\.[0-9]+\.x$'; then - echo "Refusing to release from '$REF'. Releases run from main, stable or an x.y.x patch branch." >&2 + echo "Refusing to release from '$REF'. Releases run from main or an x.y.x patch branch." >&2 exit 1 fi ;; @@ -113,7 +102,7 @@ jobs: with: ref: ${{ steps.params.outputs.ref }} fetch-depth: 0 # all branches and tags: the next version is derived from release tags - token: ${{ secrets.PRISMA_BOT_TOKEN }} + persist-credentials: false - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js @@ -127,26 +116,8 @@ jobs: id: version env: CHANNEL: ${{ steps.params.outputs.channel }} - BUMP: ${{ inputs.bump || 'auto' }} - PRISMA_VERSION: ${{ inputs.prisma_version }} - run: node scripts/next_extension_version.mjs "$CHANNEL" "$BUMP" "$PRISMA_VERSION" - - name: Reset stable branch to main (new Prisma minor/major) - if: steps.params.outputs.channel == 'stable' && inputs.prisma_version != '' && steps.version.outputs.release_type != 'patch' - run: | - git checkout -B stable origin/main - git push --force origin stable - - name: Bump Prisma dependencies - if: inputs.prisma_version != '' - env: - NPM_CHANNEL: ${{ steps.version.outputs.npm_channel }} - VERSION: ${{ steps.version.outputs.version }} - PRISMA_VERSION: ${{ inputs.prisma_version }} - RELEASE_REF: ${{ steps.params.outputs.ref }} - run: | - node scripts/update_package_json_files.mjs "$NPM_CHANNEL" "$VERSION" "$PRISMA_VERSION" - sh scripts/set_git_credentials.sh - git commit -am "[skip ci] bump Prisma CLI to $PRISMA_VERSION and extension to $VERSION" - git push origin "HEAD:$RELEASE_REF" + BUMP: ${{ inputs.bump || 'patch' }} + run: node scripts/next_extension_version.mjs "$CHANNEL" "$BUMP" - name: Resolve release commit id: sha run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" diff --git a/docs/ci-cd.md b/docs/ci-cd.md index 2af4cd9184..08daae93b6 100644 --- a/docs/ci-cd.md +++ b/docs/ci-cd.md @@ -3,30 +3,32 @@ ## Publishing pipeline All publishing — insider **and** stable — happens in a single workflow: -[`release.yml`](../.github/workflows/release.yml). There are no chained -workflows and no version-bump commits: the next extension version is derived -from the git release tags (`x.y.z` for stable, `insider/x.y.z` for insider, -one shared monotonic counter). The only commit a release can create is a real -dependency bump when a new Prisma CLI version is passed in. +[`release.yml`](../.github/workflows/release.yml). It **never writes to the +repository**. The next extension version is derived from the git release tags +(`x.y.z` for stable, `insider/x.y.z` for insider, one shared monotonic +counter), so releasing creates no bot commits. Prisma CLI dependency updates +are a separate workflow, [`bump_prisma.yml`](../.github/workflows/bump_prisma.yml). + +Everything is released from `main`. Both channels ship the same code and the +same Prisma CLI pins; the channel only decides the extension identity +(`prisma` vs `prisma-insider`) and the Language Server npm dist-tag. ### Triggers -| Trigger | Result | -| ---------------------------------------------- | ------------------------------------------------------------------------- | -| Push to `main` | Insider release | -| Manual `workflow_dispatch` | Insider or stable release, optional Prisma CLI bump, optional branch | -| `check_for_prisma_update.yml` (cron, disabled) | Dispatches `release.yml` when a new Prisma CLI version is released on npm | +| Trigger | Result | +| -------------------------- | ------------------------------------------------ | +| Push to `main` | Insider release | +| Manual `workflow_dispatch` | Insider or stable release, optional patch branch | ### Jobs ```mermaid graph TD PUSH(Push to main) --> PLAN - MANUAL(Manual dispatch: channel, bump, prisma_version) --> PLAN - CRON(check_for_prisma_update.yml cron) --> PLAN + MANUAL(Manual dispatch: channel, bump, ref) --> PLAN subgraph release.yml - PLAN[plan: resolve channel + branch, derive next version from git tags,
optionally commit Prisma CLI dependency bump] + PLAN[plan: resolve channel + branch,
derive next version from git tags] PLAN --> TEST[test: build, typecheck, LS unit tests, E2E tests
on ubuntu / macos / windows] TEST --> LS[publish-language-server:
npm publish with dist-tag dev or latest] TEST --> PKG[package: build vsix, upload artifact] @@ -50,37 +52,49 @@ graph TD ### Permissions -The workflow default is `contents: read`. Write access is granted per job: -`plan` (pushes the dependency-bump commit and can reset `stable`), `release` -(creates the tag and GitHub release) and `publish-language-server` -(`id-token: write` for npm Trusted Publishers). Every checkout except `plan`'s -sets `persist-credentials: false`, so build and test steps never see a git -credential. +The workflow default is `contents: read`. Only two jobs are granted more: +`release` (`contents: write`, to create the tag and GitHub release) and +`publish-language-server` (`id-token: write`, for npm Trusted Publishers). +Every checkout sets `persist-credentials: false`, so no job has a git +credential in its config while running dependency code. + +Releases only run from `main` or an `x.y.x` patch branch; `plan` rejects any +other `ref`. + +### Channels + +| Channel | Extension name | Tag | LS npm dist-tag | +| ------- | ---------------- | --------------- | --------------- | +| insider | `prisma-insider` | `insider/x.y.z` | `dev` | +| stable | `prisma` | `x.y.z` | `latest` | -Releases only run from `main`, `stable` or an `x.y.x` patch branch; `plan` -rejects any other `ref`. +An insider release is always a patch bump. A stable release takes the `bump` +input (`patch`, `minor` or `major`, defaulting to `patch`). Both channels draw +from the same version counter, so a stable release picks up from the highest +tag either channel has reached. -### Channels and branches +To patch an older version, dispatch `release.yml` with an `x.y.x` branch as +`ref`. -| Channel | Branch | Extension name | LS npm dist-tag | -| ------- | --------------- | ---------------- | --------------- | -| insider | `main` | `prisma-insider` | `dev` | -| stable | `stable` | `prisma` | `latest` | -| insider | `x.y.x` patches | `prisma-insider` | `dev` | +## Prisma CLI dependency updates -The `stable` branch pins the Prisma CLI `latest` dependencies while `main` -tracks `dev`. When a stable release ships a new Prisma minor or major, the -`plan` job resets `stable` to `main`. Patch releases for older versions are -made by dispatching `release.yml` with an `x.y.x` branch as `ref` -(channel `insider` for a `patch-dev` CLI, `stable` for the final patch). +[`bump_prisma.yml`](../.github/workflows/bump_prisma.yml) is the only workflow +that changes dependency pins. Dispatch it with a `prisma_version` (and +optionally a `ref` for a patch branch). It runs +`scripts/bump_prisma_dependencies.mjs`, which rewrites `@prisma/config`, +`@prisma/prisma-schema-wasm`, `@prisma/schema-files-loader`, +`prisma.enginesVersion` and `prisma.cliVersion` in +`packages/language-server/package.json`, refreshes the lockfile, and pushes one +commit. -### Prisma CLI update automation +That push to `main` triggers an insider release through `release.yml`. A stable +release on the new pins is a separate manual dispatch. [`check_for_prisma_update.yml`](../.github/workflows/check_for_prisma_update.yml) (cron, currently disabled — dispatch manually) compares the npm versions of `prisma@dev`, `prisma@latest` and `prisma@patch-dev` against `scripts/versions/prisma_*`, records new versions there, and dispatches -`release.yml` for each channel that changed. +`bump_prisma.yml` for each channel that changed. ## Other workflows diff --git a/scripts/__tests__/bump-prisma-dependencies.test.mjs b/scripts/__tests__/bump-prisma-dependencies.test.mjs new file mode 100644 index 0000000000..09dae73595 --- /dev/null +++ b/scripts/__tests__/bump-prisma-dependencies.test.mjs @@ -0,0 +1,48 @@ +import { describe, it, expect } from 'vitest' +import { applyPrismaVersion } from '../bump_prisma_dependencies.mjs' + +const PACKAGE_JSON = { + name: '@prisma/language-server', + prisma: { enginesVersion: 'oldsha', cliVersion: '7.8.0' }, + dependencies: { + '@prisma/config': '7.8.0', + '@prisma/prisma-schema-wasm': '7.8.0-6.oldsha', + '@prisma/schema-files-loader': '7.8.0', + 'vscode-languageserver': '9.0.1', + }, +} + +describe('applyPrismaVersion', () => { + const bumped = applyPrismaVersion({ + packageJson: PACKAGE_JSON, + prismaVersion: '7.9.0', + engineVersion: '7.9.0-23.9b816b3aa13cc270074f172f30d6eda8a8ce867d', + }) + + it('pins every Prisma dependency to the new CLI version', () => { + expect(bumped.dependencies['@prisma/config']).toEqual('7.9.0') + expect(bumped.dependencies['@prisma/schema-files-loader']).toEqual('7.9.0') + expect(bumped.dependencies['@prisma/prisma-schema-wasm']).toEqual( + '7.9.0-23.9b816b3aa13cc270074f172f30d6eda8a8ce867d', + ) + }) + + it('records the CLI version and the engine sha', () => { + expect(bumped.prisma.cliVersion).toEqual('7.9.0') + expect(bumped.prisma.enginesVersion).toEqual('9b816b3aa13cc270074f172f30d6eda8a8ce867d') + }) + + it('leaves unrelated dependencies alone', () => { + expect(bumped.dependencies['vscode-languageserver']).toEqual('9.0.1') + }) + + it('does not mutate the input', () => { + expect(PACKAGE_JSON.prisma.cliVersion).toEqual('7.8.0') + }) + + it('throws when the engine version carries no sha', () => { + expect(() => + applyPrismaVersion({ packageJson: PACKAGE_JSON, prismaVersion: '7.9.0', engineVersion: '7.9.0' }), + ).toThrow() + }) +}) diff --git a/scripts/__tests__/next-extension-version.test.mjs b/scripts/__tests__/next-extension-version.test.mjs index 04395060b6..e807873210 100644 --- a/scripts/__tests__/next-extension-version.test.mjs +++ b/scripts/__tests__/next-extension-version.test.mjs @@ -27,27 +27,17 @@ describe('latestReleasedVersion', () => { describe('releaseType', () => { it('insider releases are always a patch', () => { - expect(releaseType({ channel: 'insider', bump: 'auto', prismaVersion: '7.9.0-dev.4' })).toEqual('patch') + expect(releaseType({ channel: 'insider', bump: 'major' })).toEqual('patch') }) - it('stable release for a Prisma CLI patch', () => { - expect(releaseType({ channel: 'stable', bump: 'auto', prismaVersion: '7.8.1' })).toEqual('patch') + it('stable releases use the requested bump', () => { + expect(releaseType({ channel: 'stable', bump: 'patch' })).toEqual('patch') + expect(releaseType({ channel: 'stable', bump: 'minor' })).toEqual('minor') + expect(releaseType({ channel: 'stable', bump: 'major' })).toEqual('major') }) - it('stable release for a Prisma CLI minor', () => { - expect(releaseType({ channel: 'stable', bump: 'auto', prismaVersion: '7.9.0' })).toEqual('minor') - }) - - it('stable release for a Prisma CLI major', () => { - expect(releaseType({ channel: 'stable', bump: 'auto', prismaVersion: '8.0.0' })).toEqual('major') - }) - - it('stable extension-only release defaults to a patch', () => { - expect(releaseType({ channel: 'stable', bump: 'auto' })).toEqual('patch') - }) - - it('an explicit bump wins over the Prisma CLI version', () => { - expect(releaseType({ channel: 'stable', bump: 'minor', prismaVersion: '7.8.1' })).toEqual('minor') + it('stable defaults to a patch', () => { + expect(releaseType({ channel: 'stable' })).toEqual('patch') }) it('throws on an unknown channel', () => { @@ -58,28 +48,14 @@ describe('releaseType', () => { expect(() => releaseType({ channel: 'stable', bump: 'mega' })).toThrow() }) - it('throws on a Prisma CLI version that is not a semantic version', () => { - expect(() => releaseType({ channel: 'stable', bump: 'auto', prismaVersion: 'invalid.0.0' })).toThrow( - /Invalid Prisma CLI version/, - ) - }) - - it('throws on a Prisma CLI prerelease for a stable release', () => { - expect(() => releaseType({ channel: 'stable', bump: 'auto', prismaVersion: '7.9.0-dev.4' })).toThrow(/prerelease/) - }) - - it('validates the Prisma CLI version even when the bump is explicit', () => { - expect(() => releaseType({ channel: 'stable', bump: 'minor', prismaVersion: 'invalid.0.0' })).toThrow() - }) - - it('does not validate the Prisma CLI version on the insider channel', () => { - expect(releaseType({ channel: 'insider', bump: 'auto', prismaVersion: 'anything' })).toEqual('patch') + it('throws on the removed auto bump', () => { + expect(() => releaseType({ channel: 'stable', bump: 'auto' })).toThrow() }) }) describe('planRelease', () => { it('plans an insider release', () => { - expect(planRelease({ channel: 'insider', bump: 'auto', prismaVersion: '7.9.0-dev.4', tags: TAGS })).toEqual({ + expect(planRelease({ channel: 'insider', bump: 'patch', tags: TAGS })).toEqual({ version: '31.12.1', release_type: 'patch', tag_name: 'insider/31.12.1', @@ -89,8 +65,8 @@ describe('planRelease', () => { }) }) - it('plans a stable release for a Prisma CLI minor', () => { - expect(planRelease({ channel: 'stable', bump: 'auto', prismaVersion: '7.9.0', tags: TAGS })).toEqual({ + it('plans a stable minor release', () => { + expect(planRelease({ channel: 'stable', bump: 'minor', tags: TAGS })).toEqual({ version: '31.13.0', release_type: 'minor', tag_name: '31.13.0', diff --git a/scripts/bump_prisma_dependencies.mjs b/scripts/bump_prisma_dependencies.mjs new file mode 100644 index 0000000000..97ca1faa37 --- /dev/null +++ b/scripts/bump_prisma_dependencies.mjs @@ -0,0 +1,52 @@ +import execa from 'execa' +import path from 'path' +import { fileURLToPath } from 'url' +import { argv } from 'process' +import { writeJsonToPackageJson, getPackageJsonContent } from './util.mjs' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + +export async function enginesVersionFor(prismaVersion) { + const { stdout } = await execa('pnpm', ['show', `@prisma/engines@${prismaVersion}`, 'dependencies', '--json']) + const engineVersion = JSON.parse(stdout)['@prisma/engines-version'] + if (typeof engineVersion !== 'string') { + throw new Error(`@prisma/engines@${prismaVersion} does not declare an @prisma/engines-version dependency.`) + } + return engineVersion +} + +export function applyPrismaVersion({ packageJson, prismaVersion, engineVersion }) { + const engineSha = engineVersion.split('.')[3] + if (!engineSha) { + throw new Error(`Could not read an engine sha out of '${engineVersion}'.`) + } + return { + ...packageJson, + prisma: { ...packageJson.prisma, enginesVersion: engineSha, cliVersion: prismaVersion }, + dependencies: { + ...packageJson.dependencies, + '@prisma/config': prismaVersion, + '@prisma/prisma-schema-wasm': engineVersion, + '@prisma/schema-files-loader': prismaVersion, + }, + } +} + +if (fileURLToPath(import.meta.url) === argv[1]) { + const [prismaVersion] = argv.slice(2) + if (!prismaVersion) { + throw new Error('Expected a Prisma CLI version, for example: node scripts/bump_prisma_dependencies.mjs 7.9.0') + } + const packageJsonPath = path.join(__dirname, '../packages/language-server/package.json') + const engineVersion = await enginesVersionFor(prismaVersion) + console.log({ prismaVersion, engineVersion }) + writeJsonToPackageJson({ + content: applyPrismaVersion({ + packageJson: getPackageJsonContent({ path: packageJsonPath }), + prismaVersion, + engineVersion, + }), + path: packageJsonPath, + }) +} diff --git a/scripts/next_extension_version.mjs b/scripts/next_extension_version.mjs index 0284f31234..b886cc71b9 100644 --- a/scripts/next_extension_version.mjs +++ b/scripts/next_extension_version.mjs @@ -4,7 +4,7 @@ import { execSync } from 'child_process' import { fileURLToPath } from 'url' import { argv } from 'process' -const BUMPS = ['auto', 'patch', 'minor', 'major'] +const BUMPS = ['patch', 'minor', 'major'] // The extension version is a single monotonic counter shared by both channels. // It is derived from the release tags (`x.y.z` for stable, `insider/x.y.z` for @@ -22,20 +22,7 @@ export function latestReleasedVersion({ tags }) { return versions[0] } -function parseStablePrismaVersion(prismaVersion) { - const parsed = semVer.parse(prismaVersion) - if (parsed === null) { - throw new Error(`Invalid Prisma CLI version '${prismaVersion}'. Expected a semantic version such as 7.9.0.`) - } - if (parsed.prerelease.length > 0) { - throw new Error( - `Prisma CLI version '${prismaVersion}' is a prerelease and can not be released on the stable channel.`, - ) - } - return parsed -} - -export function releaseType({ channel, bump = 'auto', prismaVersion = '' }) { +export function releaseType({ channel, bump = 'patch' }) { if (channel === 'insider') { return 'patch' } @@ -45,28 +32,12 @@ export function releaseType({ channel, bump = 'auto', prismaVersion = '' }) { if (!BUMPS.includes(bump)) { throw new Error(`Unknown bump '${bump}'. Expected one of: ${BUMPS.join(', ')}.`) } - - const prisma = prismaVersion === '' ? null : parseStablePrismaVersion(prismaVersion) - - if (bump !== 'auto') { - return bump - } - // 'auto' on stable mirrors the Prisma CLI release this extension ships: - // x.0.0 -> major, x.y.0 -> minor, everything else (or no CLI bump) -> patch - if (prisma !== null) { - if (prisma.minor === 0 && prisma.patch === 0) { - return 'major' - } - if (prisma.patch === 0) { - return 'minor' - } - } - return 'patch' + return bump } -export function planRelease({ channel, bump, prismaVersion, tags }) { +export function planRelease({ channel, bump, tags }) { const currentVersion = latestReleasedVersion({ tags }) - const type = releaseType({ channel, bump, prismaVersion }) + const type = releaseType({ channel, bump }) const version = semVer.inc(currentVersion, type) const stable = channel === 'stable' @@ -84,10 +55,10 @@ export function planRelease({ channel, bump, prismaVersion, tags }) { // Only run top-level code if this file is being executed directly (not imported) if (fileURLToPath(import.meta.url) === argv[1]) { - const [channel, bump = 'auto', prismaVersion = ''] = process.argv.slice(2) + const [channel, bump = 'patch'] = process.argv.slice(2) const tags = execSync('git tag --list', { encoding: 'utf-8' }).split('\n') - const plan = planRelease({ channel, bump, prismaVersion, tags }) + const plan = planRelease({ channel, bump, tags }) console.log(plan) for (const [key, value] of Object.entries(plan)) { core.setOutput(key, value) diff --git a/scripts/update_package_json_files.mjs b/scripts/update_package_json_files.mjs index 75afeb9819..3702ab5773 100644 --- a/scripts/update_package_json_files.mjs +++ b/scripts/update_package_json_files.mjs @@ -17,7 +17,7 @@ function bumpVersionInVSCodeRepo({ version, name, displayName, description, prev writeJsonToPackageJson({ content: content, path: vscodePackageJsonPath }) } -async function bumpVersionsInRepo({ channel, newExtensionVersion, newPrismaVersion = '' }) { +async function bumpVersionsInRepo({ channel, newExtensionVersion }) { const languageServerPackageJsonPath = path.join(__dirname, '../packages/language-server/package.json') const rootPackageJsonPath = path.join(__dirname, '../package.json') @@ -43,36 +43,6 @@ async function bumpVersionsInRepo({ channel, newExtensionVersion, newPrismaVersi }) } - // update dependency and engines versions in packages/language-server/package.json - if (newPrismaVersion !== '') { - // Find the version needed for `@prisma/prisma-schema-wasm` - // Let's look into the `package.json` of the `@prisma/engines` package - // and get the version of `@prisma/engines-version` it uses - const { stdout } = await execa('pnpm', ['show', `@prisma/engines@${newPrismaVersion}`, 'dependencies', '--json']) - console.debug(stdout) - const npmInfoOutput = JSON.parse(stdout) - const engineVersion = npmInfoOutput['@prisma/engines-version'] // 2.26.0-23.9b816b3aa13cc270074f172f30d6eda8a8ce867d - console.debug({ engineVersion }) - const engineSha = engineVersion.split('.')[3] - console.debug({ engineSha }) - - const languageServerPackageJson = getPackageJsonContent({ - path: languageServerPackageJsonPath, - }) - // update engines sha - languageServerPackageJson['prisma']['enginesVersion'] = engineSha - // update engines version - languageServerPackageJson['dependencies']['@prisma/config'] = newPrismaVersion - languageServerPackageJson['dependencies']['@prisma/prisma-schema-wasm'] = engineVersion - languageServerPackageJson['dependencies']['@prisma/schema-files-loader'] = newPrismaVersion - // update CLI version - languageServerPackageJson['prisma']['cliVersion'] = newPrismaVersion - writeJsonToPackageJson({ - content: languageServerPackageJson, - path: languageServerPackageJsonPath, - }) - } - // update version in root package.json const rootPackageJson = getPackageJsonContent({ path: rootPackageJsonPath }) rootPackageJson['version'] = newExtensionVersion @@ -95,19 +65,8 @@ async function bumpVersionsInRepo({ channel, newExtensionVersion, newPrismaVersi export { bumpVersionsInRepo } const args = process.argv.slice(2) -if (args.length === 3) { - console.log('Bumping Prisma CLI version, extension and Language Server version in repo.') - await bumpVersionsInRepo({ - channel: args[0], - newExtensionVersion: args[1], - newPrismaVersion: args[2], - }) -} else if (args.length === 2) { - console.log('Bumping extension and Language Server version in repo.') - await bumpVersionsInRepo({ - channel: args[0], - newExtensionVersion: args[1], - }) -} else { - throw new Error(`Expected 2 or 3 arguments, but received ${args.length}.`) +if (args.length !== 2) { + throw new Error(`Expected 2 arguments (channel, version), but received ${args.length}.`) } +console.log('Bumping extension and Language Server version in repo.') +await bumpVersionsInRepo({ channel: args[0], newExtensionVersion: args[1] }) From cb86caa2edeb35b72c914329cf20991e8dc7099f Mon Sep 17 00:00:00 2001 From: Steven McClankerton Date: Thu, 3 Sep 2026 12:22:40 +0000 Subject: [PATCH 2/3] Keep bot credentials out of every job that installs dependencies check_for_prisma_update.yml passed PRISMA_BOT_TOKEN to pnpm install through a job-level GH_TOKEN, and its checkout persisted the token before the install ran. It is now two jobs: check installs dependencies with no credential and outputs the versions, record holds the token, installs nothing, and only writes the version files, pushes, and dispatches the bumps. setup_branch.mjs uses Node built-ins only, so it runs there without an install. bump_prisma.yml had the same shape and is split the same way: pin resolves the dependency versions and uploads the manifests, push applies them and commits. The marketplace tokens in release.yml move from job env to the publishing steps, so they are no longer in scope during pnpm install. Docs follow the workflow contract: architecture.md and CONTRIBUTING.md now point at bump_prisma.yml for dependency updates rather than release.yml, CONTRIBUTING.md drops the claim that releases happen automatically on a Prisma release and the removed auto bump, and ci-cd.md states that only patch releases use an x.y.x ref since ref otherwise defaults to main. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01YJFVnTXe5iAtFHpARAg4ZU --- .github/workflows/bump_prisma.yml | 43 ++++++++++--- .github/workflows/check_for_prisma_update.yml | 64 +++++++++++-------- .github/workflows/release.yml | 6 +- docs/architecture.md | 10 +-- docs/ci-cd.md | 8 ++- packages/vscode/CONTRIBUTING.md | 18 ++++-- 6 files changed, 100 insertions(+), 49 deletions(-) diff --git a/.github/workflows/bump_prisma.yml b/.github/workflows/bump_prisma.yml index 6b55a7fb75..661b6419ad 100644 --- a/.github/workflows/bump_prisma.yml +++ b/.github/workflows/bump_prisma.yml @@ -29,13 +29,16 @@ env: PRISMA_TELEMETRY_INFORMATION: 'language-tools bump_prisma.yml' jobs: - bump: - name: Bump Prisma CLI dependencies + pin: + name: Pin the Prisma CLI dependencies if: github.repository == 'prisma/language-tools' runs-on: ubuntu-latest timeout-minutes: 10 + outputs: + ref: ${{ steps.validate.outputs.ref }} steps: - name: Validate inputs + id: validate env: PRISMA_VERSION: ${{ inputs.prisma_version }} INPUT_REF: ${{ inputs.ref }} @@ -54,11 +57,11 @@ jobs: fi ;; esac - echo "REF=$REF" >> "$GITHUB_ENV" + echo "ref=$REF" >> "$GITHUB_OUTPUT" - uses: actions/checkout@v4 with: - ref: ${{ env.REF }} - token: ${{ secrets.PRISMA_BOT_TOKEN }} + ref: ${{ steps.validate.outputs.ref }} + persist-credentials: false - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js @@ -68,15 +71,39 @@ jobs: cache: 'pnpm' - name: Install Dependencies run: pnpm install - - name: Bump Prisma CLI dependencies + - name: Pin the Prisma CLI dependencies env: PRISMA_VERSION: ${{ inputs.prisma_version }} run: node scripts/bump_prisma_dependencies.mjs "$PRISMA_VERSION" - name: Update the lockfile run: pnpm install --no-frozen-lockfile + - name: Upload the pinned manifests + uses: actions/upload-artifact@v4 + with: + name: pinned-manifests + path: | + packages/language-server/package.json + pnpm-lock.yaml + if-no-files-found: error + + push: + name: Commit and push the bump + needs: [pin] + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + REF: ${{ needs.pin.outputs.ref }} + PRISMA_VERSION: ${{ inputs.prisma_version }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.pin.outputs.ref }} + token: ${{ secrets.PRISMA_BOT_TOKEN }} + - name: Download the pinned manifests + uses: actions/download-artifact@v4 + with: + name: pinned-manifests - name: Commit and push - env: - PRISMA_VERSION: ${{ inputs.prisma_version }} run: | if git diff --quiet; then echo "Dependencies are already pinned to $PRISMA_VERSION, nothing to commit." diff --git a/.github/workflows/check_for_prisma_update.yml b/.github/workflows/check_for_prisma_update.yml index 8994ecb6df..ef21ccb59a 100644 --- a/.github/workflows/check_for_prisma_update.yml +++ b/.github/workflows/check_for_prisma_update.yml @@ -27,13 +27,14 @@ jobs: if: github.repository == 'prisma/language-tools' runs-on: ubuntu-latest timeout-minutes: 7 - env: - GH_TOKEN: ${{ secrets.PRISMA_BOT_TOKEN }} + outputs: + dev_version: ${{ steps.check_update.outputs.dev_version }} + latest_version: ${{ steps.check_update.outputs.latest_version }} + patch_dev_version: ${{ steps.check_update.outputs.patch-dev_version }} steps: - uses: actions/checkout@v4 with: - token: ${{ secrets.PRISMA_BOT_TOKEN }} - fetch-depth: 0 # patch branches are created from release tags + persist-credentials: false - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js @@ -43,17 +44,26 @@ jobs: cache: 'pnpm' - name: Install Dependencies run: pnpm install - - name: Check for Prisma CLI update id: check_update run: node scripts/check_for_update.mjs + record: + name: Record versions and start the bumps + needs: [check] + if: needs.check.outputs.dev_version || needs.check.outputs.latest_version || needs.check.outputs.patch_dev_version + runs-on: ubuntu-latest + timeout-minutes: 7 + env: + DEV_VERSION: ${{ needs.check.outputs.dev_version }} + LATEST_VERSION: ${{ needs.check.outputs.latest_version }} + PATCH_DEV_VERSION: ${{ needs.check.outputs.patch_dev_version }} + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.PRISMA_BOT_TOKEN }} + fetch-depth: 0 # patch branches are created from release tags - name: Record new versions - if: steps.check_update.outputs.dev_version || steps.check_update.outputs.latest_version || steps.check_update.outputs.patch-dev_version - env: - DEV_VERSION: ${{ steps.check_update.outputs.dev_version }} - LATEST_VERSION: ${{ steps.check_update.outputs.latest_version }} - PATCH_DEV_VERSION: ${{ steps.check_update.outputs.patch-dev_version }} run: | sh scripts/set_git_credentials.sh if [ -n "$DEV_VERSION" ]; then echo "$DEV_VERSION" > scripts/versions/prisma_dev; fi @@ -61,26 +71,30 @@ jobs: if [ -n "$PATCH_DEV_VERSION" ]; then echo "$PATCH_DEV_VERSION" > scripts/versions/prisma_patch-dev; fi git commit -am "[skip ci] record new Prisma CLI versions" git push - + - name: Create the patch branch if it is new + id: patch_branch + if: needs.check.outputs.patch_dev_version + run: | + BRANCH=$(node scripts/setup_branch.mjs patch-dev) + if [ -z "$(git ls-remote --heads origin "$BRANCH")" ]; then + # New patch branch: base it on the last marketplace-tested stable release + git branch "$BRANCH" "$(cat scripts/versions/tested_extension_stable)" + git push origin "$BRANCH" + fi + echo "branch=$BRANCH" >> "$GITHUB_OUTPUT" - name: Bump main (Prisma dev) - if: steps.check_update.outputs.dev_version + if: needs.check.outputs.dev_version env: - DEV_VERSION: ${{ steps.check_update.outputs.dev_version }} + GH_TOKEN: ${{ secrets.PRISMA_BOT_TOKEN }} run: gh workflow run bump_prisma.yml --ref main -f prisma_version="$DEV_VERSION" - name: Bump main (Prisma latest) - if: steps.check_update.outputs.latest_version && !steps.check_update.outputs.dev_version + if: needs.check.outputs.latest_version && !needs.check.outputs.dev_version env: - LATEST_VERSION: ${{ steps.check_update.outputs.latest_version }} + GH_TOKEN: ${{ secrets.PRISMA_BOT_TOKEN }} run: gh workflow run bump_prisma.yml --ref main -f prisma_version="$LATEST_VERSION" - name: Bump the patch branch (Prisma patch-dev) - if: steps.check_update.outputs.patch-dev_version + if: needs.check.outputs.patch_dev_version env: - PATCH_DEV_VERSION: ${{ steps.check_update.outputs.patch-dev_version }} - run: | - BRANCH=$(node scripts/setup_branch.mjs patch-dev) - if [ -z "$(git ls-remote --heads origin "$BRANCH")" ]; then - # New patch branch: base it on the last marketplace-tested stable release - git branch "$BRANCH" "$(cat scripts/versions/tested_extension_stable)" - git push origin "$BRANCH" - fi - gh workflow run bump_prisma.yml --ref main -f prisma_version="$PATCH_DEV_VERSION" -f ref="$BRANCH" + GH_TOKEN: ${{ secrets.PRISMA_BOT_TOKEN }} + BRANCH: ${{ steps.patch_branch.outputs.branch }} + run: gh workflow run bump_prisma.yml --ref main -f prisma_version="$PATCH_DEV_VERSION" -f ref="$BRANCH" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 254a13fe76..ab1e025e70 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -264,7 +264,6 @@ jobs: timeout-minutes: 10 env: ASSET_FILE: ${{ needs.plan.outputs.asset_name }}-${{ needs.plan.outputs.version }}.vsix - VSCE_PAT: ${{ secrets.AZURE_DEVOPS_PERSONAL_ACCESS_TOKEN }} steps: - uses: actions/checkout@v4 with: @@ -284,6 +283,8 @@ jobs: with: name: vsix - name: Publish vsix to marketplace + env: + VSCE_PAT: ${{ secrets.AZURE_DEVOPS_PERSONAL_ACCESS_TOKEN }} run: cd packages/vscode && npx vsce publish --packagePath "$GITHUB_WORKSPACE/$ASSET_FILE" publish-open-vsx: @@ -293,7 +294,6 @@ jobs: timeout-minutes: 10 env: ASSET_FILE: ${{ needs.plan.outputs.asset_name }}-${{ needs.plan.outputs.version }}.vsix - OVSX_PAT: ${{ secrets.OPEN_VSX_ACCESS_TOKEN }} steps: - uses: actions/checkout@v4 with: @@ -313,4 +313,6 @@ jobs: with: name: vsix - name: Publish vsix to open-vsx.org + env: + OVSX_PAT: ${{ secrets.OPEN_VSX_ACCESS_TOKEN }} run: cd packages/vscode && npx ovsx --debug publish "$GITHUB_WORKSPACE/$ASSET_FILE" diff --git a/docs/architecture.md b/docs/architecture.md index a0dd696b33..8691d86942 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -69,10 +69,12 @@ assets (`pglite.data`, `pglite.wasm`) are copied separately ⁴ Kept separate to support runtime switching between Prisma 6 and latest language servers via the `prisma.pinToPrisma6` setting -> **Note:** These dependencies are updated via CI by -> `.github/workflows/check_for_prisma_update.yml`, which checks npm for new -> Prisma CLI releases and dispatches `release.yml`. Its cron schedule is -> currently disabled; dispatch it manually. See [CI/CD](ci-cd.md). +> **Note:** These dependencies are updated by +> `.github/workflows/bump_prisma.yml`, which pins them to a given Prisma CLI +> version and pushes the change. `check_for_prisma_update.yml` dispatches it +> when npm has a newer CLI, but its cron schedule is currently disabled, so +> both are manual dispatches today. `release.yml` only publishes; it never +> changes dependencies. See [CI/CD](ci-cd.md). ## File Organization diff --git a/docs/ci-cd.md b/docs/ci-cd.md index 08daae93b6..b276007622 100644 --- a/docs/ci-cd.md +++ b/docs/ci-cd.md @@ -9,9 +9,11 @@ repository**. The next extension version is derived from the git release tags counter), so releasing creates no bot commits. Prisma CLI dependency updates are a separate workflow, [`bump_prisma.yml`](../.github/workflows/bump_prisma.yml). -Everything is released from `main`. Both channels ship the same code and the -same Prisma CLI pins; the channel only decides the extension identity -(`prisma` vs `prisma-insider`) and the Language Server npm dist-tag. +Standard releases, insider and stable alike, are cut from `main`. Both channels +ship the same code and the same Prisma CLI pins; the channel only decides the +extension identity (`prisma` vs `prisma-insider`) and the Language Server npm +dist-tag. Patch releases for an older version are cut from the `x.y.x` branch +passed as `ref`, which must be given explicitly — `ref` defaults to `main`. ### Triggers diff --git a/packages/vscode/CONTRIBUTING.md b/packages/vscode/CONTRIBUTING.md index 59289474d1..4cf397c57d 100644 --- a/packages/vscode/CONTRIBUTING.md +++ b/packages/vscode/CONTRIBUTING.md @@ -82,15 +82,17 @@ The extension is automatically published via GitHub Actions using an [pat-docs]: https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token -### Automatic Publishing +### Prisma CLI updates -Upon any Prisma `dev` release a new insiders release of the extension is automatically performed. +[`Check for Prisma CLI update`][check-workflow] polls npm and dispatches +[`Bump Prisma CLI`][bump-workflow] for each channel that has a new version. Its +cron schedule is currently disabled, so it has to be dispatched manually — as +does `Bump Prisma CLI` itself if you want to pin a specific version. -Upon any Prisma `latest` release a new stable release of the extension is automatically performed. +A bump pushed to `main` triggers an insider release. A stable release on the new +pins is always a separate manual dispatch. -### Manual Publishing (Extension-Only Release) - -For releases that don't coincide with a Prisma ORM release: +### Publishing **Insider release:** @@ -101,9 +103,11 @@ For releases that don't coincide with a Prisma ORM release: **Stable release:** - Manually dispatch [`Release`][release-workflow] with channel `stable` -- Select the bump: `auto`, `patch`, `minor` or `major` +- Select the bump: `patch`, `minor` or `major` [release-workflow]: ../../.github/workflows/release.yml +[bump-workflow]: ../../.github/workflows/bump_prisma.yml +[check-workflow]: ../../.github/workflows/check_for_prisma_update.yml ## Dependencies From 30b96b463f5f7a28828e92d34434b49f8bbe971a Mon Sep 17 00:00:00 2001 From: Steven McClankerton Date: Thu, 3 Sep 2026 12:38:41 +0000 Subject: [PATCH 3/3] Pin the update checker to main and serialize its runs The checker reads the version markers from whatever ref it is dispatched on and the record job commits them back to that ref, while the bumps are always dispatched against main. A run from a non-main ref therefore left main's markers untouched and the same update was detected again on the next run. Both checkouts are now pinned to main and the push is explicit. Two concurrent runs could also read the same markers and both reach git push, where the second fails on a non-fast-forward and skips the bump dispatches that follow it. The workflow now serializes on its own concurrency group. CONTRIBUTING.md records that a stable release for an older version needs that x.y.x branch passed as ref, since ref otherwise defaults to main. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01YJFVnTXe5iAtFHpARAg4ZU --- .github/workflows/check_for_prisma_update.yml | 8 +++++++- packages/vscode/CONTRIBUTING.md | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check_for_prisma_update.yml b/.github/workflows/check_for_prisma_update.yml index ef21ccb59a..758dda697d 100644 --- a/.github/workflows/check_for_prisma_update.yml +++ b/.github/workflows/check_for_prisma_update.yml @@ -14,6 +14,10 @@ on: # - cron: '*/5 * * * *' workflow_dispatch: +concurrency: + group: check-for-prisma-update + cancel-in-progress: false + permissions: contents: read @@ -34,6 +38,7 @@ jobs: steps: - uses: actions/checkout@v4 with: + ref: main persist-credentials: false - name: Install pnpm uses: pnpm/action-setup@v4 @@ -61,6 +66,7 @@ jobs: steps: - uses: actions/checkout@v4 with: + ref: main token: ${{ secrets.PRISMA_BOT_TOKEN }} fetch-depth: 0 # patch branches are created from release tags - name: Record new versions @@ -70,7 +76,7 @@ jobs: if [ -n "$LATEST_VERSION" ]; then echo "$LATEST_VERSION" > scripts/versions/prisma_latest; fi if [ -n "$PATCH_DEV_VERSION" ]; then echo "$PATCH_DEV_VERSION" > scripts/versions/prisma_patch-dev; fi git commit -am "[skip ci] record new Prisma CLI versions" - git push + git push origin HEAD:main - name: Create the patch branch if it is new id: patch_branch if: needs.check.outputs.patch_dev_version diff --git a/packages/vscode/CONTRIBUTING.md b/packages/vscode/CONTRIBUTING.md index 4cf397c57d..1a248ac53b 100644 --- a/packages/vscode/CONTRIBUTING.md +++ b/packages/vscode/CONTRIBUTING.md @@ -104,6 +104,8 @@ pins is always a separate manual dispatch. - Manually dispatch [`Release`][release-workflow] with channel `stable` - Select the bump: `patch`, `minor` or `major` +- To patch an older version, pass that `x.y.x` branch as `ref`. Without it the + release is cut from `main`. [release-workflow]: ../../.github/workflows/release.yml [bump-workflow]: ../../.github/workflows/bump_prisma.yml