From 31bbfeed07006fcc7d8a6e7767ee652f017139c6 Mon Sep 17 00:00:00 2001 From: Stefano Verna Date: Mon, 31 Aug 2026 11:55:51 +0200 Subject: [PATCH 1/3] Release with the shared toolchain instead of a local copy toolchain/publish.mjs here was the most evolved of four 88-97% identical copies of the same script - the only one with the resume fix - and @datocms/release-toolchain is a port of exactly this file, so the code that releases this repo is the code that has been releasing it. What is left behind is toolchain/release.mjs: the oclif README regeneration, which has to happen between the version bump and the release commit, passed as the shared script's one hook. The scripts are renamed publish -> release, publish-next -> release:next, because 'publish' is a name npm runs itself during 'npm publish'. Claude-Session: https://claude.ai/code/session_01XaYAhzmiJwysZeq1XC5xrQ --- .changeset/README.md | 6 +- CLAUDE.md | 10 +- README.md | 12 +- package-lock.json | 28 +++- package.json | 6 +- toolchain/publish.mjs | 298 ------------------------------------------ toolchain/release.mjs | 31 +++++ 7 files changed, 79 insertions(+), 312 deletions(-) delete mode 100755 toolchain/publish.mjs create mode 100644 toolchain/release.mjs diff --git a/.changeset/README.md b/.changeset/README.md index 94efc33..cd2b799 100644 --- a/.changeset/README.md +++ b/.changeset/README.md @@ -6,7 +6,7 @@ Whenever you change something worth mentioning in a release, run `npx changeset` and answer the two prompts (which packages, and whether it's a patch/minor/major). That writes a small markdown file here, which you commit along with your changes. -At release time `npm run publish` consumes every pending file: it computes the +At release time `npm run release` consumes every pending file: it computes the resulting versions, updates the `package.json`s and the `CHANGELOG.md`s, and deletes the files. @@ -38,7 +38,7 @@ README point at that tag. ## Prereleases -`npm run publish-next` publishes under the `next` dist-tag, leaving `latest` +`npm run release:next` publishes under the `next` dist-tag, leaving `latest` untouched. It works in two modes: - **as-is** — the pending changesets produce a normal version (say `4.1.0`) @@ -51,5 +51,5 @@ untouched. It works in two modes: Either way the GitHub release is marked as a prerelease, so it never becomes the repository's "Latest release". -`npm run publish` refuses to run while `.changeset/pre.json` exists, so a +`npm run release` refuses to run while `.changeset/pre.json` exists, so a forgotten pre mode can't quietly turn a real release into a prerelease. diff --git a/CLAUDE.md b/CLAUDE.md index 8478995..42ec1c1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,14 +50,16 @@ npm run test # Run every package's tests via Turborepo # Releasing npx changeset # Describe a change, in the PR that makes it -npm run publish # Build, test, version, publish, tag, release notes -npm run publish-next # The same, under the `next` dist-tag +npm run release # Build, test, version, publish, tag, release notes +npm run release:next # The same, under the `next` dist-tag ``` Changes worth mentioning in a release need a changeset committed alongside them (`npx changeset`); see `.changeset/README.md`. Note that `changeset version` runs no npm lifecycle hooks, so anything that used to hang off one — the -`oclif readme` regeneration, in particular — lives in `toolchain/publish.mjs`. +`oclif readme` regeneration, in particular — lives in `toolchain/release.mjs`, +which is this repo's `beforeCommit` hook into the shared +[`@datocms/release-toolchain`](https://github.com/datocms/release-toolchain). ### Individual Package Commands @@ -78,7 +80,7 @@ npm run prepack # Build + generate oclif manifest - The WordPress and Contentful import suites talk to live APIs and create real DatoCMS projects, which they delete afterwards. They need a `.env` at the root (see `.env.sample`) and, for WordPress, `docker compose up` in its package. - `npm test` runs them, and so does `npm run publish` — a release cannot be cut + `npm test` runs them, and so does `npm run release` — a release cannot be cut without that setup. Each prerequisite is checked in a `before` hook that says what is missing and how to fix it, so a misconfiguration fails as itself rather than as a 401 halfway through an import diff --git a/README.md b/README.md index 968d1a6..ea93061 100644 --- a/README.md +++ b/README.md @@ -62,21 +62,27 @@ already had. patch/minor/major, then writes a small markdown file under `.changeset/` which you commit. `patch` is for bug fixes only; new API surface is `minor`. See [`.changeset/README.md`](.changeset/README.md). -2. **Release.** From an up-to-date, clean `main`, run `npm run publish`. +2. **Release.** From an up-to-date, clean `main`, run `npm run release`. It builds and tests first, then applies the pending changesets (bumping the versions and writing the `CHANGELOG.md`s), regenerates the oclif command reference in the READMEs of the packages that moved, publishes to npm, and only then tags each of them `name@X.Y.Z`, pushes, and publishes one GitHub release per tag — its notes are the changelog entries changesets just wrote. -If a release is interrupted, **do not undo anything**: run `npm run publish` +If a release is interrupted, **do not undo anything**: run `npm run release` again. It detects that some package is still missing from the registry and resumes the publish instead of starting a new release. -`npm run publish-next` does the same under the `next` dist-tag, leaving +`npm run release:next` does the same under the `next` dist-tag, leaving `latest` untouched; its GitHub releases are marked as prereleases, so they don't become the repository's "Latest release" either. +The script is [`@datocms/release-toolchain`](https://github.com/datocms/release-toolchain), +shared with every other DatoCMS repository and pinned here by tag; +`toolchain/release.mjs` is the twenty lines that are only true here, where the +oclif command reference has to be regenerated between the version bump and the +release commit. + Releases up to v4.0.29 carried a single `vX.Y.Z` tag covering the whole repo. Those tags stay where they are; new ones are per package, which is also what the source links in the generated command reference now point at. diff --git a/package-lock.json b/package-lock.json index e8166ed..5490ba7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@biomejs/biome": "1.6.4", "@changesets/cli": "^3.0.1", "@datocms/dashboard-client": "^6.1.0", - "@manypkg/get-packages": "^3.1.0", + "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.0.0", "@oclif/test": "^4", "@types/chai": "^4", "@types/mocha": "^10", @@ -1551,6 +1551,24 @@ "async-scheduler": "^1.4.4" } }, + "node_modules/@datocms/release-toolchain": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/datocms/release-toolchain.git#fe9848cc749b162ebcf14198029eb8bb384790ea", + "dev": true, + "license": "MIT", + "dependencies": { + "@manypkg/get-packages": "^3.1.0" + }, + "bin": { + "release-toolchain": "src/bin.mjs" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@changesets/cli": ">=3" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.28.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", @@ -14854,6 +14872,14 @@ } } }, + "@datocms/release-toolchain": { + "version": "git+ssh://git@github.com/datocms/release-toolchain.git#fe9848cc749b162ebcf14198029eb8bb384790ea", + "dev": true, + "from": "@datocms/release-toolchain@github:datocms/release-toolchain#v1.0.0", + "requires": { + "@manypkg/get-packages": "^3.1.0" + } + }, "@esbuild/aix-ppc64": { "version": "0.28.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", diff --git a/package.json b/package.json index 6069922..7d7fe10 100644 --- a/package.json +++ b/package.json @@ -11,14 +11,14 @@ "build": "turbo run build", "test": "turbo run test", "changeset": "changeset", - "publish": "node toolchain/publish.mjs", - "publish-next": "node toolchain/publish.mjs --tag next" + "release": "node toolchain/release.mjs", + "release:next": "node toolchain/release.mjs --tag next" }, "devDependencies": { "@biomejs/biome": "1.6.4", "@changesets/cli": "^3.0.1", + "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.0.0", "@datocms/dashboard-client": "^6.1.0", - "@manypkg/get-packages": "^3.1.0", "@oclif/test": "^4", "@types/chai": "^4", "@types/mocha": "^10", diff --git a/toolchain/publish.mjs b/toolchain/publish.mjs deleted file mode 100755 index 07f7788..0000000 --- a/toolchain/publish.mjs +++ /dev/null @@ -1,298 +0,0 @@ -#!/usr/bin/env node -// -// Releases the datocms CLI, its legacy alias and the two import plugins. -// -// The order of the steps is the whole point: everything that can fail (network, -// tests, credentials) runs BEFORE anything irreversible, and the irreversible -// steps go npm first, git second. `changeset publish` does both halves in that -// order by itself — it publishes, then tags only the packages npm accepted — so -// a tag can never outlive a failed publish. -// -// There is deliberately no rollback, because every step is idempotent: the -// publish skips versions already on the registry, the tagging skips tags that -// already exist, and each GitHub release skips itself. A release that dies -// halfway through is resumed by running this again. -// -// It is JavaScript rather than bash because under `set -e` the exit status of -// whatever a loop last evaluated becomes the loop's exit status, and this script -// twice sat one non-matching last package away from dying between `npm publish` -// and `git push`. - -import { execFileSync } from 'node:child_process'; -import { existsSync, readFileSync, readdirSync, rmSync } from 'node:fs'; -import { tmpdir } from 'node:os'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { getPackages } from '@manypkg/get-packages'; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -process.chdir(ROOT); - -// Normal releases happen here. Prereleases are routinely cut from a feature -// branch, so --tag only asks that the branch be clean and pushed. -const RELEASE_BRANCH = 'main'; - -/** A refusal we wrote ourselves, as opposed to a step that failed. */ -class Aborted extends Error {} - -const fail = (message) => { - throw new Aborted(message); -}; -const step = (message) => console.log(`\n\x1b[1m==> ${message}\x1b[0m`); - -/** Runs a step the human is watching, and throws if it fails. */ -const run = (file, args, options = {}) => - execFileSync(file, args, { stdio: 'inherit', ...options }); - -/** Runs a command for its output, and throws if it fails. */ -const capture = (file, args) => - execFileSync(file, args, { - encoding: 'utf8', - stdio: ['ignore', 'pipe', 'pipe'], - }).trim(); - -/** - * Exit status as a question, for the commands whose failure is an answer rather - * than an error: "am I logged in?", "does this release already exist?". - */ -const succeeds = (file, args) => { - try { - execFileSync(file, args, { stdio: 'ignore' }); - return true; - } catch { - return false; - } -}; - -const pendingChangesets = () => - readdirSync('.changeset').filter( - (entry) => entry.endsWith('.md') && entry !== 'README.md', - ); - -/** - * What this release covers, as `{ kind, name, version }` entries: `publish` for - * a version not yet on the registry, `tag-only` for one that got there before a - * previous run died. Asked of changesets rather than reconstructed here — it is - * the same plan `changeset publish` is about to execute, registry lookups - * included, so the two cannot disagree about what is being released. - */ -const publishPlan = () => { - const file = path.join(tmpdir(), `publish-plan-${process.pid}.json`); - try { - // Captured, not shown: `changeset publish` prints the same registry - // summary again a moment later. - capture('npx', ['changeset', 'publish-plan', '--output', file]); - return JSON.parse(readFileSync(file, 'utf8')).plan.flat(); - } finally { - rmSync(file, { force: true }); - } -}; - -/** - * The section of a package's CHANGELOG for one version, without its "## x.y.z" - * heading — changesets has already written exactly the prose we want. - */ -const changelogSection = (dir, version) => { - const file = path.join(dir, 'CHANGELOG.md'); - // A package released for the first time has no CHANGELOG.md yet. - if (!existsSync(file)) return ''; - const [, section = ''] = readFileSync(file, 'utf8').split( - `\n## ${version}\n`, - ); - return section.split('\n## ')[0].trim(); -}; - -const main = async () => { - const { packages } = await getPackages(ROOT); - const dirOf = new Map( - packages.map((pkg) => [pkg.packageJson.name, pkg.relativeDir]), - ); - - // The only flag: `--tag next` publishes under that npm dist-tag instead of - // `latest`, and marks the GitHub releases as prereleases. - const [flag, distTag = ''] = process.argv.slice(2); - if (flag && flag !== '--tag') fail(`unknown option: ${flag}`); - if (flag && !distTag) fail('--tag needs a value.'); - - // ------------------------------------------------------------------------- - // Preflight: no mutations, just refuse to start from a state we can't finish. - // ------------------------------------------------------------------------- - step('Preflight'); - - const branch = capture('git', ['rev-parse', '--abbrev-ref', 'HEAD']); - - if (!distTag) { - if (branch !== RELEASE_BRANCH) { - fail( - `you are not on ${RELEASE_BRANCH}. Use --tag to publish a prerelease from a branch.`, - ); - } - if (existsSync('.changeset/pre.json')) { - fail( - 'the repo is in changesets pre mode (.changeset/pre.json).\n' + - " Run 'npx changeset pre exit' before cutting a real release.", - ); - } - } - - if (capture('git', ['status', '--porcelain'])) { - fail('working tree is dirty. Commit or stash first.'); - } - - run('git', ['fetch', '--quiet', 'origin', branch]); - // Being *ahead* of origin is not a problem here, it's the normal resume - // state: the release commit is made locally and pushed only once npm has - // accepted the packages, so a run that died in between leaves exactly that. - // What we can't work with is the other direction — commits on origin we - // don't have, which we'd release without. - if ( - !succeeds('git', [ - 'merge-base', - '--is-ancestor', - `origin/${branch}`, - 'HEAD', - ]) - ) { - fail( - `origin/${branch} has commits ${branch} doesn't. Pull (and rerun) first.`, - ); - } - - if (!succeeds('npm', ['whoami'])) - fail("you are not logged in to npm. Run 'npm login'."); - if (!succeeds('gh', ['auth', 'status'])) { - fail( - "the GitHub CLI is missing or logged out, so the release notes can't be published.", - ); - } - - const npmUser = capture('npm', ['whoami']); - console.log(`on ${branch}, in sync with origin, npm user: ${npmUser}`); - - // ------------------------------------------------------------------------- - // Everything that can fail. Nothing has been mutated yet, so a network - // timeout here costs you nothing but the rerun. - // - // Skipped when there are no changesets to apply, which is what a resumed - // release looks like: the versions were bumped and committed by the run that - // died, and the plan below picks up whatever it didn't finish. - // ------------------------------------------------------------------------- - const bumping = pendingChangesets().length > 0; - - if (bumping) { - step('Building'); - run('npm', ['run', 'build']); - - step('Testing'); - run('npm', ['test']); - - // ----------------------------------------------------------------------- - // Mutations, local only. Still nothing pushed, still nothing published. - // ----------------------------------------------------------------------- - step('Applying pending changesets'); - run('npx', ['changeset', 'version']); - - step('Refreshing the lockfile'); - run('npm', ['install', '--package-lock-only']); - } - - step('Reading the publish plan'); - const plan = publishPlan(); - for (const { kind, name, version } of plan) { - console.log( - ` ${name}@${version}${kind === 'tag-only' ? ' (already on npm)' : ''}`, - ); - } - if (plan.length === 0) { - fail( - 'there is nothing to release: every package is already published and tagged.\n' + - " Describe your changes with 'npx changeset' first.", - ); - } - - if (bumping) { - // `oclif readme` rewrites each command's docs and the source links under - // them, which are templated with the package's own version. Lerna used to - // trigger this through npm's `version` lifecycle hook; `changeset version` - // runs no lifecycle hooks at all, which is why it is spelled out here. - // - // Only for the packages this release tags: the links point at - // `name@version`, so regenerating a package that isn't moving would write - // links to a tag that will never exist. Its README keeps the links from its - // own last release, which do resolve, until it moves again. - step('Regenerating the oclif READMEs'); - for (const { name } of plan) { - const pkg = packages.find((entry) => entry.packageJson.name === name); - if (!pkg?.packageJson.oclif?.commands) continue; - console.log(` ${name}`); - run('npx', ['oclif', 'readme'], { cwd: pkg.dir }); - } - - step('Committing the release'); - // `release: v4.0.30` when the release lands everything on one version, - // which is the usual outcome in a linked group, and the explicit list when - // only part of the group moves and the versions stay apart. - const tags = plan.map((entry) => `${entry.name}@${entry.version}`); - const versions = new Set(plan.map((entry) => entry.version)); - const subject = - versions.size === 1 - ? `release: v${[...versions][0]}` - : `release: ${tags.join(', ')}`; - run('git', ['add', '-A']); - run('git', ['commit', '-m', subject]); - } - - // ------------------------------------------------------------------------- - // The irreversible step: npm, then one annotated `name@version` tag for each - // package npm accepted. - // ------------------------------------------------------------------------- - step('Publishing to npm and tagging'); - run('npx', ['changeset', 'publish', ...(distTag ? ['--tag', distTag] : [])]); - - step('Pushing to GitHub'); - run('git', ['push', '--follow-tags', 'origin', branch]); - - // ------------------------------------------------------------------------- - // The release notes: one GitHub release per tag, its body the CHANGELOG - // section changesets just wrote. Last, because it's the only step a human can - // redo by hand from the changelog if it goes wrong. - // ------------------------------------------------------------------------- - step('Publishing the release notes'); - for (const { name, version } of plan) { - const tag = `${name}@${version}`; - if (succeeds('gh', ['release', 'view', tag])) { - console.log(`${tag}: the release already exists, leaving it alone`); - continue; - } - // A prerelease must not become the repo's "Latest release": that's reserved - // for whatever is on the `latest` dist-tag. Decided per package, not once - // for the run, so one prerelease version can't mark the others. - const prerelease = distTag || version.includes('-') ? ['--prerelease'] : []; - const notes = - changelogSection(dirOf.get(name), version) || `Released \`${tag}\`.`; - // --verify-tag: refuse to invent a release for a tag the push didn't carry. - const args = ['--title', tag, '--verify-tag', '--notes-file', '-']; - run('gh', ['release', 'create', tag, ...args, ...prerelease], { - input: notes, - stdio: ['pipe', 'inherit', 'inherit'], - }); - } - - console.log('\n\x1b[32mReleased\x1b[0m'); -}; - -try { - await main(); -} catch (error) { - // A step that failed has already said what it had to say on stderr; all we - // add is which one, and the fact that nothing after it ran. - const summary = [String(error.message).split('\n')[0], error.stderr] - .filter(Boolean) - .join('\n'); - const detail = - error instanceof Aborted - ? error.message - : `${summary}\n The step above printed the details.`; - console.error(`\n\x1b[31mAborted: ${detail}\x1b[0m`); - process.exit(1); -} diff --git a/toolchain/release.mjs b/toolchain/release.mjs new file mode 100644 index 0000000..66380e6 --- /dev/null +++ b/toolchain/release.mjs @@ -0,0 +1,31 @@ +#!/usr/bin/env node +// +// The shared release script, plus the one thing that is only true here. + +import { release, reportFailure, run, step } from '@datocms/release-toolchain'; + +try { + await release({ + // `oclif readme` rewrites each command's docs and the source links under + // them, which are templated with the package's own version. Lerna used to + // trigger this through npm's `version` lifecycle hook; `changeset version` + // runs no lifecycle hooks at all, which is why it is spelled out here. + // + // Only for the packages this release tags: the links point at + // `name@version`, so regenerating a package that isn't moving would write + // links to a tag that will never exist. Its README keeps the links from its + // own last release, which do resolve, until it moves again. + beforeCommit: ({ packages, plan }) => { + step('Regenerating the oclif READMEs'); + for (const { name } of plan) { + const pkg = packages.find((entry) => entry.packageJson.name === name); + if (!pkg?.packageJson.oclif?.commands) continue; + console.log(` ${name}`); + run('npx', ['oclif', 'readme'], { cwd: pkg.dir }); + } + }, + }); +} catch (error) { + reportFailure(error); + process.exit(1); +} From 784b4391e86f4efedcabe91d07c9de201529d14c Mon Sep 17 00:00:00 2001 From: Stefano Verna Date: Mon, 31 Aug 2026 12:25:48 +0200 Subject: [PATCH 2/3] Pin release-toolchain v1.1.0 Rehearsing the resume against a real registry and a real GitHub repo turned up a bug that every copy of the old script had: killed between 'changeset publish' and 'git push', the next run reads an empty plan - the packages are on the registry and their tags are local, which is all changesets looks at - and aborts with 'there is nothing to release', leaving the commit unpushed and no GitHub release. v1.1.0 finishes that release. Claude-Session: https://claude.ai/code/session_01XaYAhzmiJwysZeq1XC5xrQ --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5490ba7..3364221 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@biomejs/biome": "1.6.4", "@changesets/cli": "^3.0.1", "@datocms/dashboard-client": "^6.1.0", - "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.0.0", + "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.1.0", "@oclif/test": "^4", "@types/chai": "^4", "@types/mocha": "^10", @@ -14875,7 +14875,7 @@ "@datocms/release-toolchain": { "version": "git+ssh://git@github.com/datocms/release-toolchain.git#fe9848cc749b162ebcf14198029eb8bb384790ea", "dev": true, - "from": "@datocms/release-toolchain@github:datocms/release-toolchain#v1.0.0", + "from": "@datocms/release-toolchain@github:datocms/release-toolchain#v1.1.0", "requires": { "@manypkg/get-packages": "^3.1.0" } diff --git a/package.json b/package.json index 7d7fe10..e6dd5f8 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "devDependencies": { "@biomejs/biome": "1.6.4", "@changesets/cli": "^3.0.1", - "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.0.0", + "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.1.0", "@datocms/dashboard-client": "^6.1.0", "@oclif/test": "^4", "@types/chai": "^4", From 4cac116dd655fa1aa7a5ba73deab0ea6457bb8cf Mon Sep 17 00:00:00 2001 From: Stefano Verna Date: Mon, 31 Aug 2026 12:34:52 +0200 Subject: [PATCH 3/3] Pin release-toolchain v1.2.0 v1.2.0 adds a guard a package runs from prepublishOnly to refuse a hand-typed 'npm publish'. This repo does not use it: the root package.json is private, so the same slip publishes nothing. The seven single-package repos carry it, where 'npm publish' at the repo root does reach npm. The lockfile is the substantive part of this commit. Changing the spec alone left the previous SHA resolved, so 'npm ci' kept installing v1.0.0 while package.json claimed otherwise. Claude-Session: https://claude.ai/code/session_01XaYAhzmiJwysZeq1XC5xrQ --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3364221..951350e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@biomejs/biome": "1.6.4", "@changesets/cli": "^3.0.1", "@datocms/dashboard-client": "^6.1.0", - "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.1.0", + "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.2.0", "@oclif/test": "^4", "@types/chai": "^4", "@types/mocha": "^10", @@ -1552,8 +1552,8 @@ } }, "node_modules/@datocms/release-toolchain": { - "version": "1.0.0", - "resolved": "git+ssh://git@github.com/datocms/release-toolchain.git#fe9848cc749b162ebcf14198029eb8bb384790ea", + "version": "1.2.0", + "resolved": "git+ssh://git@github.com/datocms/release-toolchain.git#5fbd5d5aa750b8ce833a05bc26aa86a6400c4d0d", "dev": true, "license": "MIT", "dependencies": { @@ -14873,9 +14873,9 @@ } }, "@datocms/release-toolchain": { - "version": "git+ssh://git@github.com/datocms/release-toolchain.git#fe9848cc749b162ebcf14198029eb8bb384790ea", + "version": "git+ssh://git@github.com/datocms/release-toolchain.git#5fbd5d5aa750b8ce833a05bc26aa86a6400c4d0d", "dev": true, - "from": "@datocms/release-toolchain@github:datocms/release-toolchain#v1.1.0", + "from": "@datocms/release-toolchain@github:datocms/release-toolchain#v1.2.0", "requires": { "@manypkg/get-packages": "^3.1.0" } diff --git a/package.json b/package.json index e6dd5f8..2d24212 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,8 @@ "devDependencies": { "@biomejs/biome": "1.6.4", "@changesets/cli": "^3.0.1", - "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.1.0", "@datocms/dashboard-client": "^6.1.0", + "@datocms/release-toolchain": "github:datocms/release-toolchain#v1.2.0", "@oclif/test": "^4", "@types/chai": "^4", "@types/mocha": "^10",