Skip to content

Commit

Permalink
fix: do not use tags for normal prerelease dependency bump
Browse files Browse the repository at this point in the history
  • Loading branch information
hanseltime committed Sep 16, 2023
1 parent 9963fb0 commit 1fea2cb
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 18 deletions.
2 changes: 2 additions & 0 deletions lib/multiSemanticRelease.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import { createRequire } from "module";
* @param {Package[]} localDeps Array of local dependencies this package relies on.
* @param {context|void} context The semantic-release context for this package's release (filled in once semantic-release runs).
* @param {undefined|Result|false} result The result of semantic-release (object with lastRelease, nextRelease, commits, releases), false if this package was skipped (no changes or similar), or undefined if the package's release hasn't completed yet.
* @param {Object} _lastRelease The last release object for the package before its current release (set during anaylze-commit)
* @param {Object} _nextRelease The next release object (the release the package is releasing for this cycle) (set during generateNotes)
*/

/**
Expand Down
50 changes: 37 additions & 13 deletions lib/updateDeps.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,49 @@ const getVersionFromTag = (pkg, tag) => {
return strMatch && strMatch[0] && semver.valid(strMatch[0]) ? strMatch[0] : null;
};

/**
* Options for NextPreVersion
*
* @typedef {Object} NextPreVersionOptions
* @param {Array<string>|undefined} tags - will use the tags as a reference, overrides useGitTags
* @param {boolean|undefined} useGitTags - if true, will look up all git tags for this prerelease
*/

/**
* Resolve next package version on prereleases.
*
* Will resolve highest next version of either:
*
* 1. The last release for the package during this multi-release cycle
* 2. (if tag options provided):
* a. the highest increment of the tags array provided
* b. the highest increment of the gitTags for the prerelease
*
* @param {Package} pkg Package object.
* @param {Array<string>} tags Override list of tags from specific pkg and branch.
* @param {NextPreVersionOptions|undefined} options additional options
* @returns {string|undefined} Next pkg version.
* @internal
*/
const getNextPreVersion = (pkg, tags) => {
const getNextPreVersion = (pkg, options) => {
const tagFilters = [pkg._preRelease];
const lastVersion = pkg._lastRelease && pkg._lastRelease.version;
// Note: this is only set is a current multi-semantic-release released
const lastVersionForCurrentRelease = pkg._lastRelease && pkg._lastRelease.version;

// Ensure options don't have a conflict
const normalizedOptions = options || {};
if (normalizedOptions.tags && normalizedOptions.useGitTags) {
throw new Error("You can only separately provide a set of tags or specify useGitTags!");
}
let { tags = [] } = normalizedOptions;
const { useGitTags } = normalizedOptions;

// Extract tags:
// 1. Set filter to extract only package tags
// 2. Get tags from a branch considering the filters established
// 3. Resolve the versions from the tags
// TODO: replace {cwd: '.'} with multiContext.cwd
if (pkg.name) tagFilters.push(pkg.name);
if (!tags) {
if (useGitTags) {
try {
tags = getTags(pkg._branch, { cwd: process.cwd() }, tagFilters);
} catch (e) {
Expand All @@ -69,15 +93,15 @@ const getNextPreVersion = (pkg, tags) => {
}
}

const lastPreRelTag = getPreReleaseTag(lastVersion);
const lastPreRelTag = getPreReleaseTag(lastVersionForCurrentRelease);
const isNewPreRelTag = lastPreRelTag && lastPreRelTag !== pkg._preRelease;

const versionToSet =
isNewPreRelTag || !lastVersion
isNewPreRelTag || !lastVersionForCurrentRelease
? `1.0.0-${pkg._preRelease}.1`
: _nextPreVersionCases(
tags.map((tag) => getVersionFromTag(pkg, tag)).filter((tag) => tag),
lastVersion,
lastVersionForCurrentRelease,
pkg._nextType,
pkg._preRelease
);
Expand All @@ -101,23 +125,23 @@ const getPreReleaseTag = (version) => {
/**
* Resolve next prerelease special cases: highest version from tags or major/minor/patch.
*
* @param {Array} tags List of all released tags from package.
* @param {string} lastVersion Last package version released.
* @param {Array<string>} tags - if non-empty, we will use these tags as part fo the comparison
* @param {string} lastVersionForCurrentMultiRelease Last package version released from multi-semantic-release
* @param {string} pkgNextType Next type evaluated for the next package type.
* @param {string} pkgPreRelease Package prerelease suffix.
* @returns {string|undefined} Next pkg version.
* @internal
*/
const _nextPreVersionCases = (tags, lastVersion, pkgNextType, pkgPreRelease) => {
const _nextPreVersionCases = (tags, lastVersionForCurrentMultiRelease, pkgNextType, pkgPreRelease) => {
// Case 1: Normal release on last version and is now converted to a prerelease
if (!semver.prerelease(lastVersion)) {
const { major, minor, patch } = semver.parse(lastVersion);
if (!semver.prerelease(lastVersionForCurrentMultiRelease)) {
const { major, minor, patch } = semver.parse(lastVersionForCurrentMultiRelease);
return `${semver.inc(`${major}.${minor}.${patch}`, pkgNextType || "patch")}-${pkgPreRelease}.1`;
}

// Case 2: Validates version with tags
const latestTag = getLatestVersion(tags, { withPrerelease: true });
return _nextPreHighestVersion(latestTag, lastVersion, pkgPreRelease);
return _nextPreHighestVersion(latestTag, lastVersionForCurrentMultiRelease, pkgPreRelease);
};

/**
Expand Down
84 changes: 79 additions & 5 deletions test/lib/updateDeps.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import {
/* eslint-disable */
import { beforeEach, jest } from "@jest/globals";
jest.unstable_mockModule("../../lib/git.js", () => ({
getTags: jest.fn(),
}));
const { getTags } = await import("../../lib/git.js");
const {
resolveReleaseType,
resolveNextVersion,
getNextVersion,
getNextPreVersion,
getPreReleaseTag,
getVersionFromTag,
} from "../../lib/updateDeps.js";
} = await import("../../lib/updateDeps.js");

describe("resolveNextVersion()", () => {
// prettier-ignore
Expand Down Expand Up @@ -201,6 +207,9 @@ describe("getNextVersion()", () => {
});

describe("getNextPreVersion()", () => {
beforeEach(() => {
jest.clearAllMocks();
});
// prettier-ignore
const cases = [
[undefined, "patch", "rc", [], "1.0.0-rc.1"],
Expand All @@ -226,10 +235,75 @@ describe("getNextPreVersion()", () => {
_nextType: releaseType,
_lastRelease: {version: lastVersion},
_preRelease: preRelease,
_branch: "master",
name: "testing-package"
_branch: "master",
name: "testing-package"
},
{
tags: lastTags,
}
)).toBe(nextVersion);
});
it(`${lastVersion} and ${releaseType} ${
lastTags.length ? "with looked up branch tags " : ""
}gives ${nextVersion}`, () => {
getTags.mockImplementation(() => {
return lastTags;
});
// prettier-ignore
expect(getNextPreVersion(
{
_nextType: releaseType,
_lastRelease: {version: lastVersion},
_preRelease: preRelease,
_branch: "master",
name: "testing-package"
},
{
useGitTags: true,
}
)).toBe(nextVersion);
expect(getTags).toHaveBeenCalledTimes(1);
});
});
it('does not allow tags and useGitTags', () => {
expect(() => getNextPreVersion(
{
_nextType: 'patch',
_lastRelease: {version: '1.0.0'},
_preRelease: 'dev',
_branch: "master",
name: "testing-package"
},
{
useGitTags: true,
tags: [],
},
)).toThrowError('You can only separately provide a set of tags or specify useGitTags!');
});
// Simulates us not using tags as criteria

const noTagCases = [
// prerelease channels just bump up the pre-release
["1.0.0-rc.0", "minor", "rc", "1.0.0-rc.1"],
["1.0.0-dev.0", "major", "dev", "1.0.0-dev.1"],
["1.0.0-dev.0", "major", "dev", "1.0.0-dev.1"],
["1.0.1-dev.0", "major", "dev", "1.0.1-dev.1"],
// main channels obey the release type
["11.0.0", "major", "beta", "12.0.0-beta.1"],
["1.0.0", "minor", "beta", "1.1.0-beta.1"],
["1.0.0", "patch", "beta", "1.0.1-beta.1"],
];
noTagCases.forEach(([lastVersion, releaseType, preRelease, nextVersion]) => {
it(`${lastVersion} and ${releaseType} for channel ${preRelease} gives ${nextVersion}`, () => {
// prettier-ignore
expect(getNextPreVersion(
{
_nextType: releaseType,
_lastRelease: {version: lastVersion},
_preRelease: preRelease,
_branch: "master",
name: "testing-package"
},
lastTags
)).toBe(nextVersion);
});
});
Expand Down

0 comments on commit 1fea2cb

Please sign in to comment.