Skip to content

Commit

Permalink
feat(prepare): add shouldPrepare (#654)
Browse files Browse the repository at this point in the history
  • Loading branch information
Eunjae Lee authored Feb 3, 2020
1 parent 354f853 commit 166626d
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 43 deletions.
3 changes: 3 additions & 0 deletions packages/shipjs-lib/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export { default as getReleaseTag } from './lib/util/getReleaseTag';
export { default as getReleaseType } from './lib/util/getReleaseType';

/* git */
export { default as getCommitTitles } from './lib/git/getCommitTitles';
export { default as getCommitBodies } from './lib/git/getCommitBodies';
export { default as hasLocalBranch } from './lib/git/hasLocalBranch';
export { default as hasRemoteBranch } from './lib/git/hasRemoteBranch';
export { default as getCurrentBranch } from './lib/git/getCurrentBranch';
Expand All @@ -32,3 +34,4 @@ export { default as loadConfig } from './lib/config/loadConfig';
/* etc */
export { default as getAppName } from './lib/util/getAppName';
export { default as expandPackageList } from './lib/util/expandPackageList';
export { default as getCommitNumbersPerType } from './lib/util/getCommitNumbersPerType';
1 change: 1 addition & 0 deletions packages/shipjs-lib/src/lib/config/defaultConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default {
// packagesToBump: ['packages/*', 'examples/*'],
// packagesToPublish: ['packages/*'],
// },
shouldPrepare: undefined, // async ({ commits, nextVersion, releaseType, releaseTag, commitNumbersPerType }) => {},
updateChangelog: true,
conventionalChangelogArgs: '-p angular -i CHANGELOG.md -s',
installCommand: ({ isYarn }) =>
Expand Down
8 changes: 8 additions & 0 deletions packages/shipjs-lib/src/lib/git/getCommitBodies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import silentExec from '../shell/silentExec';

export default function getBodies(revisionRange, dir) {
const cmd = `git log ${revisionRange} --pretty=format:%b`;
return silentExec(cmd, { dir, ignoreError: true })
.toString()
.trim();
}
8 changes: 8 additions & 0 deletions packages/shipjs-lib/src/lib/git/getCommitTitles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import silentExec from '../shell/silentExec';

export default function getCommitTitles(revisionRange, dir) {
const cmd = `git log ${revisionRange} --pretty=format:%s`;
return silentExec(cmd, { dir, ignoreError: true })
.toString()
.trim();
}
31 changes: 31 additions & 0 deletions packages/shipjs-lib/src/lib/util/getCommitNumbersPerType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { GIT_COMMIT_PREFIX_PATCH, GIT_COMMIT_PREFIX_MINOR } from '../const';

export default function getCommitNumbersPerType(commitTitles) {
const ignoredMessages = [];
const numbers = {};
commitTitles.split('\n').forEach(rawTitle => {
const title = rawTitle.trim();
if (!title) {
return;
}
if (title.startsWith('Merge branch')) {
return;
}
const match = title.match(/(.*?)(\(.*?\))?:.*/);
if (!match || !match[1]) {
ignoredMessages.push(title);
return;
}
const prefix = match[1].toLowerCase();
if (
GIT_COMMIT_PREFIX_PATCH.has(prefix) ||
GIT_COMMIT_PREFIX_MINOR.has(prefix)
) {
numbers[prefix] = numbers[prefix] || 0;
numbers[prefix] += 1;
} else {
ignoredMessages.push(title);
}
});
return { numbers, ignoredMessages };
}
55 changes: 12 additions & 43 deletions packages/shipjs-lib/src/lib/util/getNextVersion.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import {
GIT_COMMIT_BREAKING_CHANGE,
} from '../const';
import { inc, prerelease } from 'semver';
import silentExec from '../shell/silentExec';
import getCommitTitles from '../git/getCommitTitles';
import getCommitBodies from '../git/getCommitBodies';
import getCommitNumbersPerType from './getCommitNumbersPerType';

export function getNextVersionFromCommitMessages(version, titles, bodies) {
if (prerelease(version)) {
Expand All @@ -13,32 +15,13 @@ export function getNextVersionFromCommitMessages(version, titles, bodies) {
if (bodies.toUpperCase().includes(GIT_COMMIT_BREAKING_CHANGE)) {
return { version: inc(version, 'major') };
}
let patch = false;
let minor = false;
const ignoredMessages = [];
titles.split('\n').forEach(rawTitle => {
const title = rawTitle.trim();
if (!title) {
return;
}
if (title.startsWith('Merge branch')) {
return;
}
const match = title.match(/(.*?)(\(.*?\))?:.*/);
if (!match || !match[1]) {
ignoredMessages.push(title);
return;
}
const prefix = match[1].toLowerCase();
if (GIT_COMMIT_PREFIX_PATCH.has(prefix)) {
patch = true;
} else if (GIT_COMMIT_PREFIX_MINOR.has(prefix)) {
minor = true;
} else {
ignoredMessages.push(title);
}
});

const { numbers, ignoredMessages } = getCommitNumbersPerType(titles);
const minor = Array.from(GIT_COMMIT_PREFIX_MINOR).some(
prefix => numbers[prefix] > 0
);
const patch = Array.from(GIT_COMMIT_PREFIX_PATCH).some(
prefix => numbers[prefix] > 0
);
if (minor) {
return { version: inc(version, 'minor'), ignoredMessages };
} else if (patch) {
Expand All @@ -50,26 +33,12 @@ export function getNextVersionFromCommitMessages(version, titles, bodies) {
}
}

function getTitles(revisionRange, dir) {
const cmd = `git log ${revisionRange} --pretty=format:%s`;
return silentExec(cmd, { dir, ignoreError: true })
.toString()
.trim();
}

function getBodies(revisionRange, dir) {
const cmd = `git log ${revisionRange} --pretty=format:%b`;
return silentExec(cmd, { dir, ignoreError: true })
.toString()
.trim();
}

export default function getNextVersion(
revisionRange,
currentVersion,
dir = '.'
) {
const titles = getTitles(revisionRange, dir);
const bodies = getBodies(revisionRange, dir);
const titles = getCommitTitles(revisionRange, dir);
const bodies = getCommitBodies(revisionRange, dir);
return getNextVersionFromCommitMessages(currentVersion, titles, bodies);
}
9 changes: 9 additions & 0 deletions packages/shipjs/src/flow/prepare.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import commitChanges from '../step/prepare/commitChanges';
import createPullRequest from '../step/prepare/createPullRequest';
import notifyPrepared from '../step/prepare/notifyPrepared';
import pushToStagingBranch from '../step/prepare/pushToStagingBranch';
import validatePreparationConditions from '../step/prepare/validatePreparationConditions';
import checkGitHubToken from '../step/checkGitHubToken';
import finished from '../step/prepare/finished';

Expand Down Expand Up @@ -66,6 +67,14 @@ async function prepare({
dryRun,
});
const releaseType = getReleaseType(currentVersion, nextVersion);
await validatePreparationConditions({
config,
releaseType,
nextVersion,
revisionRange,
dir,
dryRun,
});
const { stagingBranch } = prepareStagingBranch({
config,
nextVersion,
Expand Down
49 changes: 49 additions & 0 deletions packages/shipjs/src/step/prepare/validatePreparationConditions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
getReleaseTag,
getCommitTitles,
getCommitNumbersPerType,
} from 'shipjs-lib';
import runStep from '../runStep';
import { print, exitProcess } from '../../util';
import { info } from '../../color';

export default async ({
config,
releaseType,
nextVersion,
revisionRange,
dir,
dryRun,
}) =>
await runStep(
{
title: 'Validating preparation conditions.',
skipIf: () => config.shouldPrepare === undefined,
},
async () => {
const { shouldPrepare } = config;
if (dryRun) {
print(`-> execute ${info('shouldPrepare()')} callback.`);
return;
}
const releaseTag = getReleaseTag(nextVersion);
const commits = getCommitTitles(revisionRange, dir);
const { numbers: commitNumbersPerType } = getCommitNumbersPerType(
commits
);

const result = await shouldPrepare({
commits,
nextVersion,
releaseType,
releaseTag,
commitNumbersPerType,
});
if (!result) {
print(
info('`shouldPrepare` returned false. So the preparation is skipped.')
);
exitProcess(0);
}
}
);
36 changes: 36 additions & 0 deletions website/reference/all-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,42 @@ Ship.js currently does not provide independent versioning. It means all the pack

1. Ship.js will only publish the packages from `packagesToPublish`.

## `shouldPrepare`

*default*: `undefined`

```js
// example
shouldPrepare: ({
commits,
nextVersion,
releaseType,
releaseTag,
commitNumbersPerType,
}) => { /* ... */ }
```

This is a lifecycle hook where you can decide whether or not to proceed with the preparation.

- commits: string of commit titles. Be aware that it's not an array of strings. It comes from `git log --pretty=format:%s`.
- nextVersion: `x.y.z`
- releaseType: `'major' | 'minor' | 'patch' | 'prerelease'`
- releaseTag: `'latest' | 'alpha' | 'beta' | ...`
- commitNumbersPerType: an object with keys of conventional commit type, and with values of number of commits of the type. `{ feat: 2, fix: 4, chore: 8 }`

```js
// example
shouldPrepare: ({ releaseType, commitNumbersPerType }) => {
const { fix = 0 } = commitNumbersPerType;
if (releaseType === "patch" && fix === 0) {
return false;
}
return true;
}
```

With the config above, you can skip if it's going to be a patch release but without any `fix` commits.

## `updateChangelog`

*default:* `true`
Expand Down

0 comments on commit 166626d

Please sign in to comment.