From 6542983f9a22f0e035dd76dec1a4a77b50a9b6c3 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 27 Jun 2023 22:28:59 +0200 Subject: [PATCH 01/13] bump @sveltejs/vite-plugin-svelte --- code/frameworks/svelte-vite/package.json | 2 +- code/yarn.lock | 28 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index ba48aa2d4a29..7b01248aa738 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -50,7 +50,7 @@ "@storybook/builder-vite": "7.1.0-alpha.40", "@storybook/node-logger": "7.1.0-alpha.40", "@storybook/svelte": "7.1.0-alpha.40", - "@sveltejs/vite-plugin-svelte": "^2.4.1", + "@sveltejs/vite-plugin-svelte": "^2.4.2", "magic-string": "^0.30.0", "sveltedoc-parser": "^4.2.1", "ts-dedent": "^2.2.0" diff --git a/code/yarn.lock b/code/yarn.lock index 01eb0a5af5fa..298af341549d 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -7321,7 +7321,7 @@ __metadata: "@storybook/builder-vite": 7.1.0-alpha.40 "@storybook/node-logger": 7.1.0-alpha.40 "@storybook/svelte": 7.1.0-alpha.40 - "@sveltejs/vite-plugin-svelte": ^2.4.1 + "@sveltejs/vite-plugin-svelte": ^2.4.2 "@types/node": ^16.0.0 magic-string: ^0.30.0 svelte: ^4.0.0 @@ -7667,34 +7667,34 @@ __metadata: languageName: node linkType: hard -"@sveltejs/vite-plugin-svelte-inspector@npm:^1.0.2": - version: 1.0.2 - resolution: "@sveltejs/vite-plugin-svelte-inspector@npm:1.0.2" +"@sveltejs/vite-plugin-svelte-inspector@npm:^1.0.3": + version: 1.0.3 + resolution: "@sveltejs/vite-plugin-svelte-inspector@npm:1.0.3" dependencies: debug: ^4.3.4 peerDependencies: "@sveltejs/vite-plugin-svelte": ^2.2.0 - svelte: ^3.54.0 || ^4.0.0-next.0 + svelte: ^3.54.0 || ^4.0.0 vite: ^4.0.0 - checksum: b94d8e6f9fcca6ff5a3c1a07c6bcc3e952410845adbd8f69ec0afc9b7b8c1823b20d92cc90ce00cf38c69d1b5bcbe2a05a54941e30d171b8b3df5ea9782b1c32 + checksum: a64f9a8742cde3f601f6480b56128df8cab553043deab1f96884e34f153ca5020233348ce7ba624900d26b0da4324fef82f4b6a3deec33f9eca7f5938c33c1d7 languageName: node linkType: hard -"@sveltejs/vite-plugin-svelte@npm:^2.4.1": - version: 2.4.1 - resolution: "@sveltejs/vite-plugin-svelte@npm:2.4.1" +"@sveltejs/vite-plugin-svelte@npm:^2.4.2": + version: 2.4.2 + resolution: "@sveltejs/vite-plugin-svelte@npm:2.4.2" dependencies: - "@sveltejs/vite-plugin-svelte-inspector": ^1.0.2 + "@sveltejs/vite-plugin-svelte-inspector": ^1.0.3 debug: ^4.3.4 deepmerge: ^4.3.1 kleur: ^4.1.5 magic-string: ^0.30.0 - svelte-hmr: ^0.15.1 + svelte-hmr: ^0.15.2 vitefu: ^0.2.4 peerDependencies: - svelte: ^3.54.0 || ^4.0.0-next.0 + svelte: ^3.54.0 || ^4.0.0 vite: ^4.0.0 - checksum: c5799b9cef9725ca906f8e21f042ac9e5a7023596442eb2fa82b4c9169fa999e2a16b3ef096e8439d09b22acd253ffcbc30a38823807705f213683cf0c771b96 + checksum: 303401055cb4f31407a51e8adaabf9a68dbc9977fa1cf0a9353baadecd4fd0d67ccfc881e29160907d6a3a738a25e6feab9dd638099ff4ced4909f612616850b languageName: node linkType: hard @@ -28671,7 +28671,7 @@ __metadata: languageName: node linkType: hard -"svelte-hmr@npm:^0.15.1": +"svelte-hmr@npm:^0.15.2": version: 0.15.2 resolution: "svelte-hmr@npm:0.15.2" peerDependencies: From 1cd27de116eecbc7c15d1836b20b82413c46dabb Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Thu, 6 Jul 2023 14:08:27 +0200 Subject: [PATCH 02/13] add defer options --- .github/workflows/prepare-patch-release.yml | 2 +- .github/workflows/prepare-prerelease.yml | 2 +- .github/workflows/publish.yml | 2 + scripts/release/version.ts | 42 +++++++++++++++++---- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/.github/workflows/prepare-patch-release.yml b/.github/workflows/prepare-patch-release.yml index 20a4e24d023e..f3e98370d286 100644 --- a/.github/workflows/prepare-patch-release.yml +++ b/.github/workflows/prepare-patch-release.yml @@ -88,7 +88,7 @@ jobs: git config --global user.email 'github-actions[bot]@users.noreply.github.com' yarn release:pick-patches - - name: Bump version + - name: Bump version # TODO: defer id: bump-version if: steps.unreleased-changes.outputs.has-changes-to-release == 'true' run: | diff --git a/.github/workflows/prepare-prerelease.yml b/.github/workflows/prepare-prerelease.yml index bf387d464ccf..28691325bb0c 100644 --- a/.github/workflows/prepare-prerelease.yml +++ b/.github/workflows/prepare-prerelease.yml @@ -107,7 +107,7 @@ jobs: gh run cancel ${{ github.run_id }} gh run watch ${{ github.run_id }} - - name: Bump version + - name: Bump version # TODO: defer id: bump-version run: | yarn release:version --release-type ${{ inputs.release-type || 'prerelease' }} ${{ inputs.pre-id && format('{0} {1}', '--pre-id', inputs.pre-id) || '' }} --verbose diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5dd070b1fe1b..b4c69eba7e86 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -53,6 +53,8 @@ jobs: run: | yarn install + # TODO: apply deferred version + - name: Get current version id: version run: yarn release:get-current-version diff --git a/scripts/release/version.ts b/scripts/release/version.ts index 03f608567392..c477be9bf367 100644 --- a/scripts/release/version.ts +++ b/scripts/release/version.ts @@ -22,8 +22,16 @@ program '-E, --exact ', 'Use exact version instead of calculating from current version, eg. "7.2.0-canary.123". Can not be combined with --release-type or --pre-id' ) + .option( + '-D, --deferred', + 'Do not bump versions everywhere, instead set it in code/package.json#deferredNextVersion' + ) + .option('-A, --apply', 'Apply a deferred version bump') .option('-V, --verbose', 'Enable verbose logging', false); +/** + * @see tocbot docs {@link https://tscanlin.github.io/tocbot/#usage} + */ const optionsSchema = z .object({ releaseType: z @@ -36,12 +44,29 @@ const optionsSchema = z .refine((version) => (version ? semver.valid(version) !== null : true), { message: '--exact version has to be a valid semver string', }), + deferred: z.boolean().optional(), + apply: z.boolean().optional(), verbose: z.boolean().optional(), }) .superRefine((schema, ctx) => { // manual union validation because zod + commander is not great in this case const hasExact = 'exact' in schema && schema.exact; const hasReleaseType = 'releaseType' in schema && schema.releaseType; + const hasDeferred = 'deferred' in schema && schema.deferred; + const hasApply = 'apply' in schema && schema.apply; + if (hasDeferred && hasApply) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: '--deferred cannot be combined with --apply', + }); + } + if (hasApply && (hasExact || hasReleaseType)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: + '--apply cannot be combined with --exact or --release-type, as it will always read from code/package.json#deferredNextVersion', + }); + } if ((hasExact && hasReleaseType) || (!hasExact && !hasReleaseType)) { ctx.addIssue({ code: z.ZodIssueCode.custom, @@ -63,11 +88,16 @@ type BaseOptions = { verbose: boolean }; type BumpOptions = BaseOptions & { releaseType: semver.ReleaseType; preId?: string; + deferred?: boolean; }; type ExactOptions = BaseOptions & { exact: semver.ReleaseType; + deferred?: boolean; }; -type Options = BumpOptions | ExactOptions; +type ApplyOptions = BaseOptions & { + apply: boolean; +}; +type Options = BumpOptions | ExactOptions | ApplyOptions; const CODE_DIR_PATH = path.join(__dirname, '..', '..', 'code'); const CODE_PACKAGE_JSON_PATH = path.join(CODE_DIR_PATH, 'package.json'); @@ -94,12 +124,6 @@ const bumpCodeVersion = async (nextVersion: string) => { console.log(`✅ Bumped version of ${chalk.cyan('code')}'s package.json`); }; -const bumpAllPackageVersions = async (nextVersion: string, verbose?: boolean) => { - console.log(`🤜 Bumping version of ${chalk.cyan('all packages')}...`); - - console.log(`✅ Bumped version of ${chalk.cyan('all packages')}`); -}; - const bumpVersionSources = async (currentVersion: string, nextVersion: string) => { const filesToUpdate = [ path.join(CODE_DIR_PATH, 'lib', 'manager-api', 'src', 'version.ts'), @@ -194,6 +218,8 @@ export const run = async (options: unknown) => { } const { verbose } = options; + // TODO: if apply, set next version from deferred and removed deferred version + console.log(`🚛 Finding Storybook packages...`); const [packages, currentVersion] = await Promise.all([getWorkspaces(), getCurrentVersion()]); @@ -232,6 +258,8 @@ export const run = async (options: unknown) => { ); } + // TODO: if deferred, just bump in code package.json + console.log(`⏭ Bumping all packages to ${chalk.blue(nextVersion)}...`); await bumpCodeVersion(nextVersion); From 9b3303b7c39a9accc68ab6c65073dd7bb5027d07 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 10 Jul 2023 23:03:00 +0200 Subject: [PATCH 03/13] add tests for --deferred and --apply failures --- scripts/release/__tests__/version.test.ts | 62 +++++++++++++++++++++++ scripts/release/version.ts | 3 -- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/scripts/release/__tests__/version.test.ts b/scripts/release/__tests__/version.test.ts index c33c5fc31b8b..48defd818333 100644 --- a/scripts/release/__tests__/version.test.ts +++ b/scripts/release/__tests__/version.test.ts @@ -132,6 +132,68 @@ describe('Version', () => { `); }); + it('should throw when apply is combined with releaseType', async () => { + fsExtra.__setMockFiles({ + [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }), + [MANAGER_API_VERSION_PATH]: `export const version = "1.0.0";`, + [VERSIONS_PATH]: `export default { "@storybook/addon-a11y": "1.0.0" };`, + }); + + await expect(version({ apply: true, releaseType: 'prerelease' })).rejects + .toThrowErrorMatchingInlineSnapshot(` + "[ + { + "code": "custom", + "message": "--apply cannot be combined with --exact or --release-type, as it will always read from code/package.json#deferredNextVersion", + "path": [] + } + ]" + `); + }); + + it('should throw when apply is combined with exact', async () => { + fsExtra.__setMockFiles({ + [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }), + [MANAGER_API_VERSION_PATH]: `export const version = "1.0.0";`, + [VERSIONS_PATH]: `export default { "@storybook/addon-a11y": "1.0.0" };`, + }); + + await expect(version({ apply: true, exact: '1.0.0' })).rejects + .toThrowErrorMatchingInlineSnapshot(` + "[ + { + "code": "custom", + "message": "--apply cannot be combined with --exact or --release-type, as it will always read from code/package.json#deferredNextVersion", + "path": [] + } + ]" + `); + }); + + it('should throw when apply is combined with deferred', async () => { + fsExtra.__setMockFiles({ + [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }), + [MANAGER_API_VERSION_PATH]: `export const version = "1.0.0";`, + [VERSIONS_PATH]: `export default { "@storybook/addon-a11y": "1.0.0" };`, + }); + + await expect(version({ apply: true, deferred: true })).rejects + .toThrowErrorMatchingInlineSnapshot(` + "[ + { + "code": "custom", + "message": "--deferred cannot be combined with --apply", + "path": [] + }, + { + "code": "custom", + "message": "Combining --exact with --release-type is invalid, but having one of them is required", + "path": [] + } + ]" + `); + }); + it.each([ // prettier-ignore { releaseType: 'major', currentVersion: '1.1.1', expectedVersion: '2.0.0' }, diff --git a/scripts/release/version.ts b/scripts/release/version.ts index c477be9bf367..8acd840efc17 100644 --- a/scripts/release/version.ts +++ b/scripts/release/version.ts @@ -29,9 +29,6 @@ program .option('-A, --apply', 'Apply a deferred version bump') .option('-V, --verbose', 'Enable verbose logging', false); -/** - * @see tocbot docs {@link https://tscanlin.github.io/tocbot/#usage} - */ const optionsSchema = z .object({ releaseType: z From 63073b4959be756e3ced175c28268a18a63f6175 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 10 Jul 2023 23:15:10 +0200 Subject: [PATCH 04/13] add deferred logic and tests --- scripts/release/__tests__/version.test.ts | 17 ++++++++++ scripts/release/version.ts | 40 ++++++++++++++++------- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/scripts/release/__tests__/version.test.ts b/scripts/release/__tests__/version.test.ts index 48defd818333..9acfe4dd98f5 100644 --- a/scripts/release/__tests__/version.test.ts +++ b/scripts/release/__tests__/version.test.ts @@ -293,4 +293,21 @@ describe('Version', () => { }); } ); + + it('should only set version in "deferredNextVersion" when using --deferred', async () => { + fsExtra.__setMockFiles({ + [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }), + }); + + await version({ releaseType: 'premajor', preId: 'beta', deferred: true }); + + expect(fsExtra.writeJson).toHaveBeenCalledTimes(1); + expect(fsExtra.writeJson).toHaveBeenCalledWith( + CODE_PACKAGE_JSON_PATH, + { version: '1.0.0', deferredNextVersion: '2.0.0-beta.0' }, + { spaces: 2 } + ); + expect(fsExtra.writeFile).not.toHaveBeenCalled(); + expect(execaCommand).not.toHaveBeenCalled(); + }); }); diff --git a/scripts/release/version.ts b/scripts/release/version.ts index 8acd840efc17..eae40296ed92 100644 --- a/scripts/release/version.ts +++ b/scripts/release/version.ts @@ -209,6 +209,20 @@ const bumpAllPackageJsons = async ({ console.log(`✅ Bumped peer dependency versions in ${chalk.cyan('all packages')}`); }; +const bumpDeferred = async (nextVersion: string) => { + console.log( + `⏳ Setting a ${chalk.cyan( + 'deferred' + )} version bump with code/package.json#deferredNextVersion = ${chalk.yellow(nextVersion)}...` + ); + const codePkgJson = await readJson(CODE_PACKAGE_JSON_PATH); + + codePkgJson.deferredNextVersion = nextVersion; + await writeJson(CODE_PACKAGE_JSON_PATH, codePkgJson, { spaces: 2 }); + + console.log(`✅ Set a ${chalk.cyan('deferred')} version bump. Not bumping any packages.`); +}; + export const run = async (options: unknown) => { if (!validateOptions(options)) { return; @@ -255,20 +269,22 @@ export const run = async (options: unknown) => { ); } - // TODO: if deferred, just bump in code package.json - - console.log(`⏭ Bumping all packages to ${chalk.blue(nextVersion)}...`); + if ('deferred' in options && options.deferred) { + await bumpDeferred(nextVersion); + } else { + console.log(`⏭ Bumping all packages to ${chalk.blue(nextVersion)}...`); - await bumpCodeVersion(nextVersion); - await bumpVersionSources(currentVersion, nextVersion); - await bumpAllPackageJsons({ packages, currentVersion, nextVersion, verbose }); + await bumpCodeVersion(nextVersion); + await bumpVersionSources(currentVersion, nextVersion); + await bumpAllPackageJsons({ packages, currentVersion, nextVersion, verbose }); - console.log(`⬆️ Updating lock file with ${chalk.blue('yarn install --mode=update-lockfile')}`); - await execaCommand(`yarn install --mode=update-lockfile`, { - cwd: path.join(CODE_DIR_PATH), - stdio: verbose ? 'inherit' : undefined, - }); - console.log(`✅ Updated lock file with ${chalk.blue('yarn install --mode=update-lockfile')}`); + console.log(`⬆️ Updating lock file with ${chalk.blue('yarn install --mode=update-lockfile')}`); + await execaCommand(`yarn install --mode=update-lockfile`, { + cwd: path.join(CODE_DIR_PATH), + stdio: verbose ? 'inherit' : undefined, + }); + console.log(`✅ Updated lock file with ${chalk.blue('yarn install --mode=update-lockfile')}`); + } if (process.env.GITHUB_ACTIONS === 'true') { setOutput('current-version', currentVersion); From fa2612b6d8e422056417e49df04a0a8b46f72db7 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 10 Jul 2023 23:54:05 +0200 Subject: [PATCH 05/13] add apply logic and tests --- code/__mocks__/fs-extra.js | 4 +++ scripts/release/__tests__/version.test.ts | 33 +++++++++++++----- scripts/release/version.ts | 42 +++++++++++++++++++---- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/code/__mocks__/fs-extra.js b/code/__mocks__/fs-extra.js index a29315078944..7e18c3ead80d 100644 --- a/code/__mocks__/fs-extra.js +++ b/code/__mocks__/fs-extra.js @@ -20,6 +20,9 @@ const readJsonSync = (filePath = '') => JSON.parse(mockFiles[filePath]); const lstatSync = (filePath) => ({ isFile: () => !!mockFiles[filePath], }); +const writeJson = jest.fn((filePath, json, { spaces } = {}) => { + mockFiles[filePath] = JSON.stringify(json, null, spaces); +}); // eslint-disable-next-line no-underscore-dangle fs.__setMockFiles = __setMockFiles; @@ -29,5 +32,6 @@ fs.readJson = readJson; fs.readJsonSync = readJsonSync; fs.existsSync = existsSync; fs.lstatSync = lstatSync; +fs.writeJson = writeJson; module.exports = fs; diff --git a/scripts/release/__tests__/version.test.ts b/scripts/release/__tests__/version.test.ts index 9acfe4dd98f5..6c483599dc8c 100644 --- a/scripts/release/__tests__/version.test.ts +++ b/scripts/release/__tests__/version.test.ts @@ -184,11 +184,6 @@ describe('Version', () => { "code": "custom", "message": "--deferred cannot be combined with --apply", "path": [] - }, - { - "code": "custom", - "message": "Combining --exact with --release-type is invalid, but having one of them is required", - "path": [] } ]" `); @@ -221,11 +216,21 @@ describe('Version', () => { { releaseType: 'patch', currentVersion: '1.1.1-rc.10', expectedVersion: '1.1.1' }, // prettier-ignore { exact: '4.2.0-canary.69', currentVersion: '1.1.1-rc.10', expectedVersion: '4.2.0-canary.69' }, + // prettier-ignore + { apply: true, currentVersion: '1.0.0', deferredNextVersion: '1.2.0', expectedVersion: '1.2.0' }, ])( - 'bump with type: "$releaseType", pre id "$preId" or exact "$exact", from: $currentVersion, to: $expectedVersion', - async ({ releaseType, preId, exact, currentVersion, expectedVersion }) => { + 'bump with type: "$releaseType", pre id "$preId" or exact "$exact" or apply $apply, from: $currentVersion, to: $expectedVersion', + async ({ + releaseType, + preId, + exact, + apply, + currentVersion, + expectedVersion, + deferredNextVersion, + }) => { fsExtra.__setMockFiles({ - [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: currentVersion }), + [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: currentVersion, deferredNextVersion }), [MANAGER_API_VERSION_PATH]: `export const version = "${currentVersion}";`, [VERSIONS_PATH]: `export default { "@storybook/addon-a11y": "${currentVersion}" };`, [A11Y_PACKAGE_JSON_PATH]: JSON.stringify({ @@ -247,7 +252,17 @@ describe('Version', () => { [VERSIONS_PATH]: `export default { "@storybook/addon-a11y": "${currentVersion}" };`, }); - await version({ releaseType, preId, exact }); + await version({ releaseType, preId, exact, apply }); + expect(fsExtra.writeJson).toHaveBeenCalledTimes(apply ? 3 : 2); + if (apply) { + // eslint-disable-next-line jest/no-conditional-expect -- guarded against problems with the assertion above + expect(fsExtra.writeJson).toHaveBeenCalledWith( + CODE_PACKAGE_JSON_PATH, + // this call is the write that removes the "deferredNextVersion" property + { version: currentVersion }, + { spaces: 2 } + ); + } expect(fsExtra.writeJson).toHaveBeenCalledWith( CODE_PACKAGE_JSON_PATH, diff --git a/scripts/release/version.ts b/scripts/release/version.ts index eae40296ed92..adddb0535920 100644 --- a/scripts/release/version.ts +++ b/scripts/release/version.ts @@ -64,7 +64,7 @@ const optionsSchema = z '--apply cannot be combined with --exact or --release-type, as it will always read from code/package.json#deferredNextVersion', }); } - if ((hasExact && hasReleaseType) || (!hasExact && !hasReleaseType)) { + if (!hasApply && ((hasExact && hasReleaseType) || (!hasExact && !hasReleaseType))) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: @@ -211,9 +211,9 @@ const bumpAllPackageJsons = async ({ const bumpDeferred = async (nextVersion: string) => { console.log( - `⏳ Setting a ${chalk.cyan( - 'deferred' - )} version bump with code/package.json#deferredNextVersion = ${chalk.yellow(nextVersion)}...` + `⏳ Setting a ${chalk.cyan('deferred')} version bump with ${chalk.blue( + 'code/package.json#deferredNextVersion' + )} = ${chalk.yellow(nextVersion)}...` ); const codePkgJson = await readJson(CODE_PACKAGE_JSON_PATH); @@ -223,14 +223,40 @@ const bumpDeferred = async (nextVersion: string) => { console.log(`✅ Set a ${chalk.cyan('deferred')} version bump. Not bumping any packages.`); }; +const applyDeferredVersionBump = async () => { + console.log( + `⏩ Applying previously deferred version bump set at ${chalk.blue( + 'code/package.json#deferredNextVersion' + )}...` + ); + const codePkgJson = await readJson(CODE_PACKAGE_JSON_PATH); + + const { deferredNextVersion } = codePkgJson; + + if (!deferredNextVersion) { + throw new Error( + "The 'deferredNextVersion' property in code/package.json is unset. This is necessary to apply a deferred version bump" + ); + } + + delete codePkgJson.deferredNextVersion; + await writeJson(CODE_PACKAGE_JSON_PATH, codePkgJson, { spaces: 2 }); + + console.log( + `✅ Extracted and removed deferred version ${chalk.green( + deferredNextVersion + )} from ${chalk.blue('code/package.json#deferredNextVersion')}` + ); + + return deferredNextVersion; +}; + export const run = async (options: unknown) => { if (!validateOptions(options)) { return; } const { verbose } = options; - // TODO: if apply, set next version from deferred and removed deferred version - console.log(`🚛 Finding Storybook packages...`); const [packages, currentVersion] = await Promise.all([getWorkspaces(), getCurrentVersion()]); @@ -248,7 +274,9 @@ export const run = async (options: unknown) => { let nextVersion: string; - if ('exact' in options && options.exact) { + if ('apply' in options && options.apply) { + nextVersion = await applyDeferredVersionBump(); + } else if ('exact' in options && options.exact) { console.log(`📈 Exact version selected: ${chalk.green(options.exact)}`); nextVersion = options.exact; } else { From cc0dbb86a394c720509496caa1e358cb5b479d02 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 11 Jul 2023 00:23:24 +0200 Subject: [PATCH 06/13] add apply bash step to publish --- .github/workflows/publish.yml | 20 +++++++++++++++++++- scripts/release/__tests__/version.test.ts | 14 ++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b4c69eba7e86..fcda0cf73f29 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -53,7 +53,25 @@ jobs: run: | yarn install - # TODO: apply deferred version + - name: Apply deferred version bump and commit + id: version-bump + working-directory: . + run: | + CURRENT_VERSION=$(cat ./code/package.json | jq '.version') + DEFERRED_NEXT_VERSION=$(cat ./code/package.json | jq '.deferredNextVersion') + + if [[ "$DEFERRED_NEXT_VERSION" == "null" ]]; then + echo "No deferred version set, not bumping versions" + exit 0 + fi + cd scripts + yarn release:version --apply --verbose + + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + git add . + git commit -m "Bump version from $CURRENT_VERSION to $DEFERRED_NEXT_VERSION" || true + git push origin ${{ github.ref_name }} - name: Get current version id: version diff --git a/scripts/release/__tests__/version.test.ts b/scripts/release/__tests__/version.test.ts index 6c483599dc8c..33dc12fbba2d 100644 --- a/scripts/release/__tests__/version.test.ts +++ b/scripts/release/__tests__/version.test.ts @@ -189,6 +189,20 @@ describe('Version', () => { `); }); + it('should throw when applying without a "deferredNextVersion" set', async () => { + fsExtra.__setMockFiles({ + [CODE_PACKAGE_JSON_PATH]: JSON.stringify({ version: '1.0.0' }), + }); + + await expect(version({ apply: true })).rejects.toThrowErrorMatchingInlineSnapshot( + `"The 'deferredNextVersion' property in code/package.json is unset. This is necessary to apply a deferred version bump"` + ); + + expect(fsExtra.writeJson).not.toHaveBeenCalled(); + expect(fsExtra.writeFile).not.toHaveBeenCalled(); + expect(execaCommand).not.toHaveBeenCalled(); + }); + it.each([ // prettier-ignore { releaseType: 'major', currentVersion: '1.1.1', expectedVersion: '2.0.0' }, From 3f1ac957baaa5bdce1f59b212a81524f34e641dd Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 11 Jul 2023 00:23:55 +0200 Subject: [PATCH 07/13] set correct git user --- .github/workflows/publish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e5bd1ae68ef9..aad219900495 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -67,8 +67,8 @@ jobs: cd scripts yarn release:version --apply --verbose - git config --global user.name 'github-actions[bot]' - git config --global user.email 'github-actions[bot]@users.noreply.github.com' + git config --global user.name "storybook-bot" + git config --global user.email "32066757+storybook-bot@users.noreply.github.com" git add . git commit -m "Bump version from $CURRENT_VERSION to $DEFERRED_NEXT_VERSION" || true git push origin ${{ github.ref_name }} From 1ceb3608328d774d24e25fbf6eea2c00ba3475a0 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 11 Jul 2023 00:26:50 +0200 Subject: [PATCH 08/13] defer version bumps in workflows --- .github/workflows/prepare-patch-release.yml | 6 +++--- .github/workflows/prepare-prerelease.yml | 6 +++--- .github/workflows/publish.yml | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/prepare-patch-release.yml b/.github/workflows/prepare-patch-release.yml index 41f9691bb5a4..c88022c7ea01 100644 --- a/.github/workflows/prepare-patch-release.yml +++ b/.github/workflows/prepare-patch-release.yml @@ -88,11 +88,11 @@ jobs: git config --global user.email '32066757+storybook-bot@users.noreply.github.com' yarn release:pick-patches - - name: Bump version # TODO: defer + - name: Bump version deferred id: bump-version if: steps.unreleased-changes.outputs.has-changes-to-release == 'true' run: | - yarn release:version --release-type patch --verbose + yarn release:version --deferred --release-type patch --verbose # We need the current version to set the branch name, even when not bumping the version - name: Get current version @@ -121,7 +121,7 @@ jobs: git config --global user.email '32066757+storybook-bot@users.noreply.github.com' git checkout -b version-patch-from-${{ steps.versions.outputs.current }} git add . - git commit -m "Bump version from ${{ steps.versions.outputs.current }} to ${{ steps.versions.outputs.next }}" || true + git commit -m "Write changelog for ${{ steps.versions.outputs.next }}" || true git push --force origin version-patch-from-${{ steps.versions.outputs.current }} - name: Generate PR description diff --git a/.github/workflows/prepare-prerelease.yml b/.github/workflows/prepare-prerelease.yml index 3a7ad1b6e8a2..1250aedcfaa3 100644 --- a/.github/workflows/prepare-prerelease.yml +++ b/.github/workflows/prepare-prerelease.yml @@ -107,10 +107,10 @@ jobs: gh run cancel ${{ github.run_id }} gh run watch ${{ github.run_id }} - - name: Bump version # TODO: defer + - name: Bump version deferred id: bump-version run: | - yarn release:version --release-type ${{ inputs.release-type || 'prerelease' }} ${{ inputs.pre-id && format('{0} {1}', '--pre-id', inputs.pre-id) || '' }} --verbose + yarn release:version --deferred --release-type ${{ inputs.release-type || 'prerelease' }} ${{ inputs.pre-id && format('{0} {1}', '--pre-id', inputs.pre-id) || '' }} --verbose - name: Write changelog env: @@ -125,7 +125,7 @@ jobs: git config --global user.email '32066757+storybook-bot@users.noreply.github.com' git checkout -b version-prerelease-from-${{ steps.bump-version.outputs.current-version }} git add . - git commit -m "Bump version from ${{ steps.bump-version.outputs.current-version }} to ${{ steps.bump-version.outputs.next-version }}" || true + git commit -m "Write changelog for ${{ steps.bump-version.outputs.next-version }}" || true git push --force origin version-prerelease-from-${{ steps.bump-version.outputs.current-version }} - name: Generate PR description diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index aad219900495..2fabf980c754 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -53,6 +53,7 @@ jobs: run: | yarn install + # TODO: test this locally - name: Apply deferred version bump and commit id: version-bump working-directory: . From 192d1daecf9ad6506d96bdce2066eec4ca1e817e Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 11 Jul 2023 07:56:28 +0200 Subject: [PATCH 09/13] add warning about existing deferredNextVersion --- scripts/release/version.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/release/version.ts b/scripts/release/version.ts index adddb0535920..7be86686b8b9 100644 --- a/scripts/release/version.ts +++ b/scripts/release/version.ts @@ -217,6 +217,14 @@ const bumpDeferred = async (nextVersion: string) => { ); const codePkgJson = await readJson(CODE_PACKAGE_JSON_PATH); + if (codePkgJson.deferredNextVersion) { + console.warn( + `❗ A "deferredNextVersion" property already exists with the value of ${chalk.cyan( + codePkgJson.deferredNextVersion + )}. This will be overwritten and ignored.` + ); + } + codePkgJson.deferredNextVersion = nextVersion; await writeJson(CODE_PACKAGE_JSON_PATH, codePkgJson, { spaces: 2 }); From 4463962a5c77ee2b500128260e07bd941f22b166 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 11 Jul 2023 07:59:54 +0200 Subject: [PATCH 10/13] fix apply step in publish --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2fabf980c754..23a8f37bfaa4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -53,7 +53,6 @@ jobs: run: | yarn install - # TODO: test this locally - name: Apply deferred version bump and commit id: version-bump working-directory: . @@ -67,6 +66,7 @@ jobs: fi cd scripts yarn release:version --apply --verbose + cd .. git config --global user.name "storybook-bot" git config --global user.email "32066757+storybook-bot@users.noreply.github.com" From e283b9a56142c92935fd9a52d093c21fded5f817 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 11 Jul 2023 08:23:51 +0200 Subject: [PATCH 11/13] update docs with deferred versioning flow --- CONTRIBUTING/RELEASING.md | 43 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/CONTRIBUTING/RELEASING.md b/CONTRIBUTING/RELEASING.md index 5a999af5e6de..685091db4b9e 100644 --- a/CONTRIBUTING/RELEASING.md +++ b/CONTRIBUTING/RELEASING.md @@ -102,7 +102,7 @@ The high-level flow is: 1. When a PR is merged to `next` (or a commit is pushed), both release pull requests are (re)generated. 2. They create a new branch - `version-(patch|prerelease)-from-`. -3. They bump all versions according to the version strategy. +3. They calculate which version to bump to according to the version strategy. 4. They update `CHANGELOG(.prerelease).md` with all changes detected. 5. They commit everything. 6. They **force push**. @@ -112,7 +112,7 @@ A few key points to note in this flow: - The PRs are regenerated on any changes to `next`, or can be manually triggered (see [the Re-trigger the Workflow section](#4-re-trigger-the-workflow)). - The changes are force pushed to the branch, so any manual changes on the release branch before merging risk being overwritten if someone else merges a new change to `next`, triggering the workflow. To avoid this, apply the **"freeze"** label to the pull request. -- The version bumps and changelogs are committed during the preparation, but the packages are not published until later. +- The changelogs are committed during the preparation, but the packages are not version bumped and not published until later. - The release pull requests don't target their working branches (`next` and `main`), but rather `next-release` and `latest-release`. ### Prereleases @@ -149,9 +149,10 @@ gitGraph checkout next merge some-bugfix type: HIGHLIGHT branch version-prerelease-from-7.1.0-alpha.28 - commit id: "bump version" + commit id: "write changelog" checkout next-release - merge version-prerelease-from-7.1.0-alpha.28 tag: "7.1.0-alpha.29" + merge version-prerelease-from-7.1.0-alpha.28 + commit id: "bump versions" tag: "7.1.0-alpha.29" checkout next merge next-release ``` @@ -199,9 +200,10 @@ gitGraph branch version-patch-from-7.0.18 cherry-pick id: "patch1" cherry-pick id: "patch2" - commit id: "version bump" + commit id: "write changelog" checkout latest-release - merge version-patch-from-7.0.18 tag: "v7.0.19" + merge version-patch-from-7.0.18 + commit id: "bump versions" tag: "v7.0.19" checkout main merge latest-release ``` @@ -213,13 +215,14 @@ gitGraph When either a prerelease or a patch release branch is merged into `main` or `next-release`, the publishing workflow is triggered. This workflow performs the following tasks: -1. Install dependencies and build all packages. -2. Publish packages to npm. -3. (If this is a patch release, add the "**picked**" label to all relevant pull requests.) -4. Create a new GitHub Release, including a version tag in the release branch (`latest-release` or `next-release`). -5. Merge the release branch into the core branch (`main` or `next`). -6. (If this is a patch release, copy the `CHANGELOG.md` changes from `main` to `next`.) -7. (If this is [a promotion from a prerelease to a stable release](#minormajor-releases---710-rc2---710-or-800-rc3---800), force push `next` to `main`.) +1. Bump versions of all packages according to the plan from the prepared PRs +2. Install dependencies and build all packages. +3. Publish packages to npm. +4. (If this is a patch release, add the "**picked**" label to all relevant pull requests.) +5. Create a new GitHub Release, including a version tag in the release branch (`latest-release` or `next-release`). +6. Merge the release branch into the core branch (`main` or `next`). +7. (If this is a patch release, copy the `CHANGELOG.md` changes from `main` to `next`.) +8. (If this is [a promotion from a prerelease to a stable release](#minormajor-releases---710-rc2---710-or-800-rc3---800), force push `next` to `main`.) The publish workflow runs in the "release" GitHub environment, which has the npm token required to publish packages to the `@storybook` npm organization. For security reasons, this environment can only be accessed from the four "core" branches: `main`, `next`, `latest-release` and `next-release`. @@ -318,7 +321,7 @@ When the pull request was frozen, a CI run was triggered on the branch. If it's ### 7. See the "Publish" Workflow Finish -Merging the pull request will trigger [the publish workflow](https://github.com/storybookjs/storybook/actions/workflows/publish.yml), which does the final publishing. As a Releaser, you're responsible for this to finish successfully, so you should watch it until the end. If it fails, it will notify in Discord, so you can monitor that instead if you want to. +Merging the pull request will trigger [the publish workflow](https://github.com/storybookjs/storybook/actions/workflows/publish.yml), which does the final version bumping and publishing. As a Releaser, you're responsible for this to finish successfully, so you should watch it until the end. If it fails, it will notify in Discord, so you can monitor that instead if you want to. Done! 🚀 @@ -500,7 +503,7 @@ gitGraph commit checkout next branch version-prerelease-from-7.1.0-alpha.28 - commit id: "bump version" + commit id checkout next merge some-simultaneous-bugfix type: HIGHLIGHT id: "whoops!" merge version-prerelease-from-7.1.0-alpha.28 tag: "v7.1.0-alpha.29" @@ -524,17 +527,19 @@ gitGraph commit checkout next branch version-prerelease-from-7.1.0-alpha.28 - commit id: "bump version" + commit id: "write changelog" checkout next merge some-simultanous-bugfix id: "whoops!" checkout next-release - merge version-prerelease-from-7.1.0-alpha.28 tag: "v7.1.0-alpha.29" + merge version-prerelease-from-7.1.0-alpha.28 + commit id: "bump versions" tag: "v7.1.0-alpha.29" checkout next merge next-release branch version-prerelease-from-7.1.0-alpha.29 - commit id: "bump version again" + commit id: "write changelog again" checkout next-release - merge version-prerelease-from-7.1.0-alpha.29 tag: "v7.1.0-alpha.30" + merge version-prerelease-from-7.1.0-alpha.29 + commit id: "bump versions again" tag: "v7.1.0-alpha.30" checkout next merge next-release ``` From bbc71e06cc00a6512b9bfa01c3075902ef03c88e Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 11 Jul 2023 08:42:18 +0200 Subject: [PATCH 12/13] fix writeJson assertions --- scripts/release/write-changelog.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release/write-changelog.ts b/scripts/release/write-changelog.ts index 7481c46e5468..bf5897f536c2 100644 --- a/scripts/release/write-changelog.ts +++ b/scripts/release/write-changelog.ts @@ -4,7 +4,7 @@ import path from 'path'; import program from 'commander'; import semver from 'semver'; import { z } from 'zod'; -import { readFile, writeFile, writeJSON } from 'fs-extra'; +import { readFile, writeFile, writeJson } from 'fs-extra'; import { getChanges } from './utils/get-changes'; program @@ -103,7 +103,7 @@ const writeToDocsVersionFile = async ({ }, }; - await writeJSON(filepath, content); + await writeJson(filepath, content); }; export const run = async (args: unknown[], options: unknown) => { From 7d3df77ddae8612fe2fd34e039dc5281d8e98174 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 11 Jul 2023 09:02:38 +0200 Subject: [PATCH 13/13] add note about deferring locally --- CONTRIBUTING/RELEASING.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING/RELEASING.md b/CONTRIBUTING/RELEASING.md index 685091db4b9e..fb19619be129 100644 --- a/CONTRIBUTING/RELEASING.md +++ b/CONTRIBUTING/RELEASING.md @@ -342,15 +342,18 @@ Before you start you should make sure that your working tree is clean and the re 5. (If patch release) Cherry pick: 1. `yarn release:pick-patches` 2. Manually cherry pick any necessary patches based on the previous output -6. Bump versions: `yarn release:version --verbose --release-type --pre-id ` +6. Bump versions: + 1. If you plan on using automatic publishing (ie. stop at step 12), bump with deferred: `yarn release:version --verbose --deferred --release-type --pre-id ` + 2. If doing the whole release locally, **do not** defer the bump: `yarn release:version --verbose --release-type --pre-id ` 7. To see a list of changes (for your own to-do list), run `yarn release:generate-pr-description --current-version --next-version --verbose` 8. Write changelogs: `yarn release:write-changelog --verbose` 9. `git add .`. 10. Commit changes: `git commit -m "Bump version from to MANUALLY"` 11. Merge changes to the release branch: 1. `git checkout <"latest-release" | "next-release">` - 2. `git merge ` - 3. `git push origin` + 2. `git pull` + 3. `git merge ` + 4. `git push origin` 12. (If automatic publishing is still working, it should kick in now and the rest of the steps can be skipped) 13. `cd ..` 14. Publish to the registry: `YARN_NPM_AUTH_TOKEN= yarn release:publish --tag <"next" OR "latest"> --verbose`