diff --git a/GUIDE.md b/GUIDE.md index 91990c44..6a99f6bc 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -284,7 +284,7 @@ const fs = require("fs"); const path = require("path"); module.exports = { - versionUpdated: ({ version, dir, exec }) => { + versionUpdated: ({ version, releaseType, dir, exec }) => { // update `lerna.json` const lernaConfigPath = path.resolve(dir, "lerna.json"); const lernaConfig = JSON.parse(fs.readFileSync(lernaConfigPath).toString()); diff --git a/packages/shipjs-lib/src/index.js b/packages/shipjs-lib/src/index.js index f10c9d7b..258c1e9d 100644 --- a/packages/shipjs-lib/src/index.js +++ b/packages/shipjs-lib/src/index.js @@ -4,6 +4,7 @@ export { default as getNextVersion } from './lib/util/getNextVersion'; export { default as updateVersion } from './lib/util/updateVersion'; export { default as isValidVersion } from './lib/util/isValidVersion'; export { default as getReleaseTag } from './lib/util/getReleaseTag'; +export { default as getReleaseType } from './lib/util/getReleaseType'; /* git */ export { default as hasLocalBranch } from './lib/git/hasLocalBranch'; diff --git a/packages/shipjs-lib/src/lib/config/defaultConfig.js b/packages/shipjs-lib/src/lib/config/defaultConfig.js index 8101a49f..0a98faa6 100644 --- a/packages/shipjs-lib/src/lib/config/defaultConfig.js +++ b/packages/shipjs-lib/src/lib/config/defaultConfig.js @@ -11,14 +11,14 @@ export default { conventionalChangelogArgs: '-p angular -i CHANGELOG.md -s', installCommand: ({ isYarn }) => isYarn ? 'yarn install --silent' : 'npm install', - versionUpdated: ({ version, dir, exec }) => {}, - beforeCommitChanges: ({ nextVersion, exec, dir }) => {}, - getStagingBranchName: ({ nextVersion }) => `releases/v${nextVersion}`, - formatCommitMessage: ({ version, mergeStrategy, baseBranch }) => + versionUpdated: ({ version, releaseType, dir, exec }) => {}, + beforeCommitChanges: ({ nextVersion, releaseType, exec, dir }) => {}, + getStagingBranchName: ({ nextVersion, releaseType }) => `releases/v${nextVersion}`, + formatCommitMessage: ({ version, releaseType, mergeStrategy, baseBranch }) => mergeStrategy.toSameBranch.includes(baseBranch) ? `chore: release v${version}` : `chore: prepare v${version}`, - formatPullRequestTitle: ({ version }) => `chore: release v${version}`, + formatPullRequestTitle: ({ version, releaseType }) => `chore: release v${version}`, formatPullRequestMessage: ({ formatPullRequestTitle, repoURL, @@ -28,8 +28,12 @@ export default { mergeStrategy, currentVersion, nextVersion, + releaseType, }) => { - const pullRequestTitle = formatPullRequestTitle({ version: nextVersion }); + const pullRequestTitle = formatPullRequestTitle({ + version: nextVersion, + releaseType, + }); const lines = [ pullRequestTitle, '', diff --git a/packages/shipjs-lib/src/lib/util/__tests__/getReleaseType.spec.js b/packages/shipjs-lib/src/lib/util/__tests__/getReleaseType.spec.js new file mode 100644 index 00000000..0277654c --- /dev/null +++ b/packages/shipjs-lib/src/lib/util/__tests__/getReleaseType.spec.js @@ -0,0 +1,7 @@ +import getReleaseType from '../getReleaseType'; + +describe('getReleaseType', () => { + it('gets release type from current version and next version', () => { + expect(getReleaseType('1.0.0', '0.10.99')).toBe('major'); + }); +}); diff --git a/packages/shipjs-lib/src/lib/util/getReleaseType.js b/packages/shipjs-lib/src/lib/util/getReleaseType.js new file mode 100644 index 00000000..513b4741 --- /dev/null +++ b/packages/shipjs-lib/src/lib/util/getReleaseType.js @@ -0,0 +1,5 @@ +import { diff } from 'semver'; + +export default function getReleaseType(currentVersion, nextVersion) { + return diff(currentVersion, nextVersion); +} diff --git a/packages/shipjs/src/flow/prepare.js b/packages/shipjs/src/flow/prepare.js index fba0f332..073d3d27 100644 --- a/packages/shipjs/src/flow/prepare.js +++ b/packages/shipjs/src/flow/prepare.js @@ -1,4 +1,4 @@ -import { getAppName, loadConfig } from 'shipjs-lib'; +import { getAppName, loadConfig, getReleaseType } from 'shipjs-lib'; import printHelp from '../step/prepare/printHelp'; import printDryRunBanner from '../step/printDryRunBanner'; @@ -54,24 +54,34 @@ async function prepare({ nextVersion, dryRun, }); + const releaseType = getReleaseType(currentVersion, nextVersion); const { stagingBranch } = prepareStagingBranch({ config, nextVersion, + releaseType, dir, }); checkoutToStagingBranch({ stagingBranch, dir, dryRun }); const updateVersionFn = config.monorepo ? updateVersionMonorepo : updateVersion; - await updateVersionFn({ config, nextVersion, dir, dryRun }); + await updateVersionFn({ config, nextVersion, releaseType, dir, dryRun }); installDependencies({ config, dir, dryRun }); updateChangelog({ config, firstRelease, releaseCount, dir, dryRun }); - await commitChanges({ nextVersion, dir, config, baseBranch, dryRun }); + await commitChanges({ + nextVersion, + releaseType, + dir, + config, + baseBranch, + dryRun, + }); const { pullRequestUrl } = createPullRequest({ baseBranch, stagingBranch, currentVersion, nextVersion, + releaseType, noBrowse, config, dir, diff --git a/packages/shipjs/src/step/prepare/__tests__/commitChanges.spec.js b/packages/shipjs/src/step/prepare/__tests__/commitChanges.spec.js index d275e8e2..5314b28c 100644 --- a/packages/shipjs/src/step/prepare/__tests__/commitChanges.spec.js +++ b/packages/shipjs/src/step/prepare/__tests__/commitChanges.spec.js @@ -32,25 +32,37 @@ describe('commitChanges', () => { .fn() .mockImplementation(() => Promise.resolve()); wrapExecWithDir.mockImplementation(() => jest.fn()); + const formatCommitMessage = jest + .fn() + .mockImplementation(() => 'test message'); await commitChanges({ config: { - formatCommitMessage: () => 'test message', + formatCommitMessage, beforeCommitChanges, }, dryRun: false, dir: '.', nextVersion: '1.2.3', + releaseType: 'patch', }); expect(wrapExecWithDir).toHaveBeenCalledTimes(1); expect(wrapExecWithDir).toHaveBeenCalledWith('.'); + expect(formatCommitMessage).toHaveBeenCalledTimes(1); + expect(formatCommitMessage).toHaveBeenCalledWith( + expect.objectContaining({ + version: '1.2.3', + releaseType: 'patch', + }) + ); expect(beforeCommitChanges).toHaveBeenCalledTimes(1); expect(beforeCommitChanges).toHaveBeenCalledWith( expect.objectContaining({ exec: expect.any(Function), dir: '.', nextVersion: '1.2.3', + releaseType: 'patch', }) ); expect(run.mock.calls[0]).toMatchInlineSnapshot(` diff --git a/packages/shipjs/src/step/prepare/__tests__/createPullRequest.spec.js b/packages/shipjs/src/step/prepare/__tests__/createPullRequest.spec.js index 2599b9fc..b00b2c1a 100644 --- a/packages/shipjs/src/step/prepare/__tests__/createPullRequest.spec.js +++ b/packages/shipjs/src/step/prepare/__tests__/createPullRequest.spec.js @@ -5,18 +5,30 @@ import { run } from '../../../util'; import { getDestinationBranchName } from '../../../helper'; jest.mock('temp-write'); -const defaultParams = { +const getDefaultParams = ({ + currentVersion = '1.2.2', + nextVersion = '1.2.3', + releaseType = 'patch', + formatPullRequestTitle = () => 'chore: releases v0.1.1', + formatPullRequestMessage = () => 'chore: releases v0.1.1', + dryRun = false, +} = {}) => ({ baseBranch: 'master', + currentVersion, + nextVersion, + releaseType, config: { mergeStrategy: { toSameBranch: ['master'], }, - formatPullRequestMessage: () => 'chore: releases v0.1.1', + formatPullRequestTitle, + formatPullRequestMessage, remote: 'origin', pullRequestReviewer: ['foo', 'bar'], }, dir: '.', -}; + dryRun, +}); describe('createPullRequest', () => { beforeEach(() => { @@ -26,10 +38,7 @@ describe('createPullRequest', () => { }); it('works in dry mode', () => { - const ret = createPullRequest({ - ...defaultParams, - dryRun: true, - }); + const ret = createPullRequest(getDefaultParams({ dryRun: true })); expect(run.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "command": "git remote prune origin", @@ -51,9 +60,42 @@ describe('createPullRequest', () => { silentExec.mockImplementationOnce(() => ({ toString: () => `13 chore: releases v0.1.1\n12 docs: update README`, })); - const { pullRequestUrl } = createPullRequest({ - ...defaultParams, - }); + const { pullRequestUrl } = createPullRequest(getDefaultParams()); expect(pullRequestUrl).toEqual('https://github.com/my/repo/pull/13'); }); + + it('pass releaseType to hooks', () => { + const mockFormatPullRequestTitle = jest + .fn() + .mockImplementation(({ version, type }) => `# v${version} (${type})`); + const mockFormatPullRequestMessage = jest + .fn() + .mockImplementation( + ({ formatPullRequestTitle, nextVersion, releaseType }) => { + return [ + formatPullRequestTitle({ + version: nextVersion, + releaseType, + }), + ].join('\n'); + } + ); + createPullRequest( + getDefaultParams({ + dryRun: true, + formatPullRequestTitle: mockFormatPullRequestTitle, + formatPullRequestMessage: mockFormatPullRequestMessage, + }) + ); + expect(mockFormatPullRequestTitle).toHaveBeenCalledWith({ + version: '1.2.3', + releaseType: 'patch', + }); + expect(mockFormatPullRequestMessage).toHaveBeenCalled(); + expect(mockFormatPullRequestMessage.mock.calls[0][0]).toMatchObject({ + currentVersion: '1.2.2', + nextVersion: '1.2.3', + releaseType: 'patch', + }); + }); }); diff --git a/packages/shipjs/src/step/prepare/__tests__/updateVersion.spec.js b/packages/shipjs/src/step/prepare/__tests__/updateVersion.spec.js index b83dd0d2..65c99817 100644 --- a/packages/shipjs/src/step/prepare/__tests__/updateVersion.spec.js +++ b/packages/shipjs/src/step/prepare/__tests__/updateVersion.spec.js @@ -11,6 +11,7 @@ describe('updateVersion', () => { versionUpdated, }, nextVersion: '1.2.3', + releaseType: 'patch', dir: '.', dryRun: false, }); @@ -23,6 +24,7 @@ describe('updateVersion', () => { Object { "dir": ".", "exec": undefined, + "releaseType": "patch", "version": "1.2.3", } `); diff --git a/packages/shipjs/src/step/prepare/__tests__/updateVersionMonorepo.spec.js b/packages/shipjs/src/step/prepare/__tests__/updateVersionMonorepo.spec.js index 1eec4601..6e9dd55a 100644 --- a/packages/shipjs/src/step/prepare/__tests__/updateVersionMonorepo.spec.js +++ b/packages/shipjs/src/step/prepare/__tests__/updateVersionMonorepo.spec.js @@ -20,6 +20,7 @@ describe('updateVersionMonorepo', () => { }, dir: '.', nextVersion: '1.2.3', + releaseType: 'patch', }); expect(updateVersion).toHaveBeenCalledTimes(3); expect(updateVersion.mock.calls[0]).toMatchInlineSnapshot(` @@ -52,6 +53,7 @@ describe('updateVersionMonorepo', () => { Object { "dir": ".", "exec": undefined, + "releaseType": "patch", "version": "1.2.3", } `); diff --git a/packages/shipjs/src/step/prepare/commitChanges.js b/packages/shipjs/src/step/prepare/commitChanges.js index 8e141219..5098cff6 100644 --- a/packages/shipjs/src/step/prepare/commitChanges.js +++ b/packages/shipjs/src/step/prepare/commitChanges.js @@ -3,11 +3,19 @@ import runStep from '../runStep'; import { wrapExecWithDir, run, print } from '../../util'; import { info } from '../../color'; -export default async ({ nextVersion, dir, config, baseBranch, dryRun }) => +export default async ({ + nextVersion, + releaseType, + dir, + config, + baseBranch, + dryRun, +}) => await runStep({ title: 'Committing the changes.' }, async () => { const { formatCommitMessage, mergeStrategy, beforeCommitChanges } = config; const message = formatCommitMessage({ version: nextVersion, + releaseType, mergeStrategy, baseBranch, }); @@ -19,7 +27,12 @@ export default async ({ nextVersion, dir, config, baseBranch, dryRun }) => print(' |'); return; } - await beforeCommitChanges({ nextVersion, exec: wrapExecWithDir(dir), dir }); + await beforeCommitChanges({ + nextVersion, + releaseType, + exec: wrapExecWithDir(dir), + dir, + }); const filePath = tempWrite.sync(message); run({ command: 'git add .', dir }); run({ command: `git commit --file=${filePath}`, dir }); diff --git a/packages/shipjs/src/step/prepare/createPullRequest.js b/packages/shipjs/src/step/prepare/createPullRequest.js index 841ee8fe..6eccf874 100644 --- a/packages/shipjs/src/step/prepare/createPullRequest.js +++ b/packages/shipjs/src/step/prepare/createPullRequest.js @@ -10,6 +10,7 @@ export default ({ stagingBranch, currentVersion, nextVersion, + releaseType, noBrowse, config, dir, @@ -55,6 +56,7 @@ export default ({ mergeStrategy, currentVersion, nextVersion, + releaseType, }); const filePath = tempWrite.sync(message); run({ command: `git remote prune ${remote}`, dir, dryRun }); diff --git a/packages/shipjs/src/step/prepare/prepareStagingBranch.js b/packages/shipjs/src/step/prepare/prepareStagingBranch.js index df8a4304..22cf8883 100644 --- a/packages/shipjs/src/step/prepare/prepareStagingBranch.js +++ b/packages/shipjs/src/step/prepare/prepareStagingBranch.js @@ -3,10 +3,10 @@ import runStep from '../runStep'; import { print, exitProcess } from '../../util'; import { error } from '../../color'; -export default ({ config, nextVersion, dir }) => +export default ({ config, nextVersion, releaseType, dir }) => runStep({ title: 'Preparing a staging branch' }, () => { const { getStagingBranchName, remote } = config; - const stagingBranch = getStagingBranchName({ nextVersion }); + const stagingBranch = getStagingBranchName({ nextVersion, releaseType }); if (hasLocalBranch(stagingBranch, dir)) { print(error(`The branch "${stagingBranch}" already exists locally.`)); print('Delete the local branch and try again. For example,'); diff --git a/packages/shipjs/src/step/prepare/updateVersion.js b/packages/shipjs/src/step/prepare/updateVersion.js index 984463e3..c673352c 100644 --- a/packages/shipjs/src/step/prepare/updateVersion.js +++ b/packages/shipjs/src/step/prepare/updateVersion.js @@ -3,7 +3,7 @@ import runStep from '../runStep'; import { print, wrapExecWithDir } from '../../util'; import { info } from '../../color'; -export default async ({ config, nextVersion, dir, dryRun }) => +export default async ({ config, nextVersion, releaseType, dir, dryRun }) => await runStep({ title: 'Updating the version.' }, async () => { const { versionUpdated } = config; if (dryRun) { @@ -14,6 +14,7 @@ export default async ({ config, nextVersion, dir, dryRun }) => updateVersion({ nextVersion, dir }); await versionUpdated({ version: nextVersion, + releaseType, dir, exec: wrapExecWithDir(dir), }); diff --git a/packages/shipjs/src/step/prepare/updateVersionMonorepo.js b/packages/shipjs/src/step/prepare/updateVersionMonorepo.js index 56d5b014..6a55a0ab 100644 --- a/packages/shipjs/src/step/prepare/updateVersionMonorepo.js +++ b/packages/shipjs/src/step/prepare/updateVersionMonorepo.js @@ -3,7 +3,7 @@ import runStep from '../runStep'; import { wrapExecWithDir, print } from '../../util'; import { info } from '../../color'; -export default async ({ config, nextVersion, dir, dryRun }) => +export default async ({ config, nextVersion, releaseType, dir, dryRun }) => await runStep( { title: 'Updating the versions on the monorepo.' }, async () => { @@ -30,6 +30,7 @@ export default async ({ config, nextVersion, dir, dryRun }) => }); await versionUpdated({ version: nextVersion, + releaseType, dir, exec: wrapExecWithDir(dir), });