diff --git a/.github/workflows/bump_prisma.yml b/.github/workflows/bump_prisma.yml new file mode 100644 index 0000000000..661b6419ad --- /dev/null +++ b/.github/workflows/bump_prisma.yml @@ -0,0 +1,114 @@ +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: + 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 }} + 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_OUTPUT" + - uses: actions/checkout@v4 + with: + ref: ${{ steps.validate.outputs.ref }} + persist-credentials: false + - 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: 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 + 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..758dda697d 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,13 @@ on: # - cron: '*/5 * * * *' workflow_dispatch: +concurrency: + group: check-for-prisma-update + cancel-in-progress: false + +permissions: + contents: read + env: ENVIRONMENT: ${{ secrets.ENVIRONMENT }} PRISMA_TELEMETRY_INFORMATION: 'language-tools check_for_prisma_update.yml' @@ -24,13 +31,15 @@ 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 + ref: main + persist-credentials: false - name: Install pnpm uses: pnpm/action-setup@v4 - name: Use Node.js @@ -40,39 +49,37 @@ 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: + ref: main + 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 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 - - - name: Release insider (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 - 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) - if: steps.check_update.outputs.patch-dev_version - env: - PATCH_DEV_VERSION: ${{ steps.check_update.outputs.patch-dev_version }} + git push origin HEAD:main + - 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 @@ -80,4 +87,20 @@ 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" + echo "branch=$BRANCH" >> "$GITHUB_OUTPUT" + - name: Bump main (Prisma dev) + if: needs.check.outputs.dev_version + env: + 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: needs.check.outputs.latest_version && !needs.check.outputs.dev_version + env: + 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: needs.check.outputs.patch_dev_version + env: + 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 4cbcb11658..ab1e025e70 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" @@ -293,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: @@ -313,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: @@ -322,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: @@ -342,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 2af4cd9184..b276007622 100644 --- a/docs/ci-cd.md +++ b/docs/ci-cd.md @@ -3,30 +3,34 @@ ## 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). + +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 -| 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 +54,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`, `stable` or an `x.y.x` patch branch; `plan` -rejects any other `ref`. +Releases only run from `main` or an `x.y.x` patch branch; `plan` rejects any +other `ref`. -### Channels and branches +### Channels -| 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` | +| Channel | Extension name | Tag | LS npm dist-tag | +| ------- | ---------------- | --------------- | --------------- | +| insider | `prisma-insider` | `insider/x.y.z` | `dev` | +| stable | `prisma` | `x.y.z` | `latest` | -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). +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. -### Prisma CLI update automation +To patch an older version, dispatch `release.yml` with an `x.y.x` branch as +`ref`. + +## Prisma CLI dependency updates + +[`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. + +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/packages/vscode/CONTRIBUTING.md b/packages/vscode/CONTRIBUTING.md index 59289474d1..1a248ac53b 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,13 @@ 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` +- 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 +[check-workflow]: ../../.github/workflows/check_for_prisma_update.yml ## Dependencies 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] })