Skip to content

Commit

Permalink
feat(semver): initial prerelease version consider commits
Browse files Browse the repository at this point in the history
Closes #688, #459, #428, #601, #679
  • Loading branch information
edbzn committed Feb 8, 2024
1 parent 786d545 commit 26d60fb
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`@jscutlery/semver @jscutlery/semver:version when libs/a changed (breaking change) should generate CHANGELOG.md 1`] = `
exports[`@jscutlery/semver @jscutlery/semver:version when libs/a changed (breaking change) should generate CHANGELOG.md: a-1.0.0 1`] = `
"# Changelog
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
Expand Down Expand Up @@ -33,7 +33,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
"
`;

exports[`@jscutlery/semver @jscutlery/semver:version when libs/a changed should generate CHANGELOG.md 1`] = `
exports[`@jscutlery/semver @jscutlery/semver:version when libs/a changed should generate CHANGELOG.md: a-0.1.0 1`] = `
"# Changelog
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
Expand All @@ -52,7 +52,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
"
`;

exports[`@jscutlery/semver @jscutlery/semver:version when libs/b changed (with --skipCommit) should generate CHANGELOG.md 1`] = `
exports[`@jscutlery/semver @jscutlery/semver:version when libs/b changed (with --skipCommit) should generate CHANGELOG.md: b-0.2.0 1`] = `
"# Changelog
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
Expand All @@ -78,7 +78,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
"
`;

exports[`@jscutlery/semver @jscutlery/semver:version when libs/b changed should generate CHANGELOG.md 1`] = `
exports[`@jscutlery/semver @jscutlery/semver:version when libs/b changed should generate CHANGELOG.md: b-0.1.0 1`] = `
"# Changelog
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
Expand All @@ -97,7 +97,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
"
`;

exports[`@jscutlery/semver @jscutlery/semver:version when libs/d changed should generate CHANGELOG.md 1`] = `
exports[`@jscutlery/semver @jscutlery/semver:version when libs/d changed should generate CHANGELOG.md: d-0.1.0 1`] = `
"# Changelog
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
Expand All @@ -111,7 +111,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
"
`;

exports[`@jscutlery/semver @jscutlery/semver:version when pre-releasing libs/a (--releaseAs=preminor --preid=alpha) should generate CHANGELOG.md 1`] = `
exports[`@jscutlery/semver @jscutlery/semver:version when pre-releasing libs/a (--releaseAs=preminor --preid=alpha) when pre-releasing libs/a again (--releaseAs=preminor --preid=alpha) should generate CHANGELOG.md: a-1.2.0-alpha.0 1`] = `
"# Changelog
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
Expand All @@ -125,7 +125,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
# [1.1.0-alpha.0](/compare/a-1.0.1-beta.1...a-1.1.0-alpha.0) (yyyy-mm-dd)
# [1.1.0-alpha.0](/compare/a-1.1.0-beta.1...a-1.1.0-alpha.0) (yyyy-mm-dd)
### Features
Expand All @@ -134,7 +134,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
## [1.0.1-beta.1](/compare/a-1.0.1-beta.0...a-1.0.1-beta.1) (yyyy-mm-dd)
# [1.1.0-beta.1](/compare/a-1.1.0-beta.0...a-1.1.0-beta.1) (yyyy-mm-dd)
### Features
Expand All @@ -143,7 +143,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
## [1.0.1-beta.0](/compare/a-1.0.0...a-1.0.1-beta.0) (yyyy-mm-dd)
# [1.1.0-beta.0](/compare/a-1.0.0...a-1.1.0-beta.0) (yyyy-mm-dd)
### Features
Expand Down Expand Up @@ -180,12 +180,12 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
"
`;

exports[`@jscutlery/semver @jscutlery/semver:version when pre-releasing libs/a (--releaseAs=prerelease --preid=beta) should generate CHANGELOG.md 1`] = `
exports[`@jscutlery/semver @jscutlery/semver:version when pre-releasing libs/a (--releaseAs=prerelease --preid=beta) when pre-releasing libs/a again (--releaseAs=prerelease --preid=beta) should generate CHANGELOG.md: a-1.1.0-beta.1 1`] = `
"# Changelog
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
## [1.0.1-beta.1](/compare/a-1.0.1-beta.0...a-1.0.1-beta.1) (yyyy-mm-dd)
# [1.1.0-beta.1](/compare/a-1.1.0-beta.0...a-1.1.0-beta.1) (yyyy-mm-dd)
### Features
Expand All @@ -194,7 +194,7 @@ This file was generated using [@jscutlery/semver](https://github.com/jscutlery/s
## [1.0.1-beta.0](/compare/a-1.0.0...a-1.0.1-beta.0) (yyyy-mm-dd)
# [1.1.0-beta.0](/compare/a-1.0.0...a-1.1.0-beta.0) (yyyy-mm-dd)
### Features
Expand Down
112 changes: 71 additions & 41 deletions packages/semver/src/executors/version/index.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ describe('@jscutlery/semver', () => {
deterministicChangelog(
readFile(`${testingWorkspace.root}/libs/a/CHANGELOG.md`),
),
).toMatchSnapshot();
).toMatchSnapshot('a-0.1.0');
});
});

Expand Down Expand Up @@ -157,7 +157,7 @@ describe('@jscutlery/semver', () => {
deterministicChangelog(
readFile(`${testingWorkspace.root}/libs/b/CHANGELOG.md`),
),
).toMatchSnapshot();
).toMatchSnapshot('b-0.1.0');
});
});

Expand Down Expand Up @@ -211,7 +211,7 @@ describe('@jscutlery/semver', () => {
deterministicChangelog(
readFile(`${testingWorkspace.root}/libs/d/CHANGELOG.md`),
),
).toMatchSnapshot();
).toMatchSnapshot('d-0.1.0');
});
});

Expand Down Expand Up @@ -242,7 +242,7 @@ describe('@jscutlery/semver', () => {
deterministicChangelog(
readFile(`${testingWorkspace.root}/libs/a/CHANGELOG.md`),
),
).toMatchSnapshot();
).toMatchSnapshot('a-1.0.0');
});
});

Expand All @@ -258,34 +258,49 @@ describe('@jscutlery/semver', () => {
testingWorkspace.runNx(
`run a:version --releaseAs=prerelease --preid=beta --noVerify`,
);
testingWorkspace.exec(
`
echo feat >> libs/a/a.txt
git add .
git commit -m "feat(a): 🚀 new feature 2"
`,
);
testingWorkspace.runNx(
`run a:version --releaseAs=prerelease --preid=beta --noVerify`,
);
});

it('should tag with version', () => {
expect(getLastTag(testingWorkspace.root)).toBe('a-1.0.1-beta.1');
expect(getLastTag(testingWorkspace.root)).toBe('a-1.1.0-beta.0');
});

it('should bump package version', () => {
expect(
readFile(`${testingWorkspace.root}/libs/a/package.json`),
).toMatch(/"version": "1.0.1-beta.1"/);
).toMatch(/"version": "1.1.0-beta.0"/);
});

it('should generate CHANGELOG.md', () => {
expect(
deterministicChangelog(
readFile(`${testingWorkspace.root}/libs/a/CHANGELOG.md`),
),
).toMatchSnapshot();
describe('when pre-releasing libs/a again (--releaseAs=prerelease --preid=beta)', () => {
beforeAll(() => {
testingWorkspace.exec(
`
echo feat >> libs/a/a.txt
git add .
git commit -m "feat(a): 🚀 new feature 2"
`,
);
testingWorkspace.runNx(
`run a:version --releaseAs=prerelease --preid=beta --noVerify`,
);
});

it('should tag with version', () => {
expect(getLastTag(testingWorkspace.root)).toBe('a-1.1.0-beta.1');
});

it('should bump package version', () => {
expect(
readFile(`${testingWorkspace.root}/libs/a/package.json`),
).toMatch(/"version": "1.1.0-beta.1"/);
});

it('should generate CHANGELOG.md', () => {
expect(
deterministicChangelog(
readFile(`${testingWorkspace.root}/libs/a/CHANGELOG.md`),
),
).toMatchSnapshot('a-1.1.0-beta.1');
});
});
});

Expand All @@ -301,34 +316,49 @@ describe('@jscutlery/semver', () => {
testingWorkspace.runNx(
`run a:version --releaseAs=preminor --preid=alpha --noVerify`,
);
testingWorkspace.exec(
`
echo feat >> libs/a/a.txt
git add .
git commit -m "feat(a): 🚀 new feature 2"
`,
);
testingWorkspace.runNx(
`run a:version --releaseAs=preminor --preid=alpha --noVerify`,
);
});

it('should tag with version', () => {
expect(getLastTag(testingWorkspace.root)).toBe('a-1.2.0-alpha.0');
expect(getLastTag(testingWorkspace.root)).toBe('a-1.1.0-alpha.0');
});

it('should bump package version', () => {
expect(
readFile(`${testingWorkspace.root}/libs/a/package.json`),
).toMatch(/"version": "1.2.0-alpha.0"/);
).toMatch(/"version": "1.1.0-alpha.0"/);
});

it('should generate CHANGELOG.md', () => {
expect(
deterministicChangelog(
readFile(`${testingWorkspace.root}/libs/a/CHANGELOG.md`),
),
).toMatchSnapshot();
describe('when pre-releasing libs/a again (--releaseAs=preminor --preid=alpha)', () => {
beforeAll(() => {
testingWorkspace.exec(
`
echo feat >> libs/a/a.txt
git add .
git commit -m "feat(a): 🚀 new feature 2"
`,
);
testingWorkspace.runNx(
`run a:version --releaseAs=preminor --preid=alpha --noVerify`,
);
});

it('should tag with version', () => {
expect(getLastTag(testingWorkspace.root)).toBe('a-1.2.0-alpha.0');
});

it('should bump package version', () => {
expect(
readFile(`${testingWorkspace.root}/libs/a/package.json`),
).toMatch(/"version": "1.2.0-alpha.0"/);
});

it('should generate CHANGELOG.md', () => {
expect(
deterministicChangelog(
readFile(`${testingWorkspace.root}/libs/a/CHANGELOG.md`),
),
).toMatchSnapshot('a-1.2.0-alpha.0');
});
});
});

Expand Down Expand Up @@ -366,7 +396,7 @@ describe('@jscutlery/semver', () => {
deterministicChangelog(
readFile(`${testingWorkspace.root}/libs/b/CHANGELOG.md`),
),
).toMatchSnapshot();
).toMatchSnapshot('b-0.2.0');
});
});
});
Expand Down
51 changes: 32 additions & 19 deletions packages/semver/src/executors/version/utils/try-bump.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,11 @@ export function tryBump({

return forkJoin([lastVersion$, commits$, lastVersionGitRef$]).pipe(
switchMap(([lastVersion, commits, lastVersionGitRef]) => {
/* If release type is manually specified,
* we just release even if there are no changes. */
if (releaseType !== undefined) {
if (releaseType && releaseType !== 'prerelease') {
return _manualBump({
since: lastVersion,
releaseType: releaseType as string,
preid: preid as string,
releaseType,
preid,
}).pipe(
map((version) =>
version
Expand All @@ -153,6 +151,15 @@ export function tryBump({
);
}

const projectBump$ = _semverBump({
since: lastVersion,
preset,
projectRoot,
tagPrefix,
releaseType,
preid,
}).pipe(map((version) => ({ type: 'project', version })));

const dependencyVersions$ = _getDependencyVersions({
commitParserOptions,
lastVersionGitRef,
Expand All @@ -166,13 +173,6 @@ export function tryBump({
preid,
});

const projectBump$ = _semverBump({
since: lastVersion,
preset,
projectRoot,
tagPrefix,
}).pipe(map((version) => ({ type: 'project', version })));

return forkJoin([projectBump$, dependencyVersions$]).pipe(
switchMap(([projectVersion, dependencyVersions]) => {
const dependencyUpdates = dependencyVersions.filter(_isNewVersion);
Expand Down Expand Up @@ -231,11 +231,15 @@ export function _semverBump({
preset,
projectRoot,
tagPrefix,
releaseType,
preid,
}: {
since: string;
preset: PresetOpt;
projectRoot: string;
tagPrefix: string;
releaseType?: ReleaseIdentifier;
preid?: string;
}) {
return defer(async () => {
const recommended = await conventionalRecommendedBump({
Expand All @@ -246,9 +250,19 @@ export function _semverBump({
? { preset: preset.name ?? 'conventionalcommits', config: preset }
: {}),
});
const { releaseType } = recommended;

return releaseType ? semver.inc(since, releaseType) : null;
let recommendedReleaseType: ReleaseIdentifier | undefined =
recommended.releaseType;
if (recommendedReleaseType && releaseType === 'prerelease') {
recommendedReleaseType =
semver.parse(since)?.prerelease.length === 0
? `pre${recommendedReleaseType}`
: releaseType;
}

return recommendedReleaseType
? semver.inc(since, recommendedReleaseType, preid)
: null;
});
}

Expand All @@ -260,14 +274,13 @@ export function _manualBump({
}: {
since: string;
releaseType: string;
preid: string;
preid?: string;
}) {
return defer(() => {
const hasPreid = preid !== null;
const semverArgs: [string, semver.ReleaseType, ...string[]] = [
const semverArgs: [string, ReleaseIdentifier, ...string[]] = [
since,
releaseType as semver.ReleaseType,
...(hasPreid ? [preid] : []),
releaseType as ReleaseIdentifier,
...(preid ? [preid] : []),
];

return of(semver.inc(...semverArgs));
Expand Down

0 comments on commit 26d60fb

Please sign in to comment.