Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@changesets/assemble-release-plan

Package Overview
Dependencies
Maintainers
3
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@changesets/assemble-release-plan - npm Package Compare versions

Comparing version 3.0.1 to 4.0.0

14

CHANGELOG.md
# @changesets/assemble-release-plan
## 4.0.0
### Major Changes
- [`ab98fe3`](https://github.com/atlassian/changesets/commit/ab98fe33814867ba740fc04733602be80771915c) [#454](https://github.com/atlassian/changesets/pull/454) Thanks [@Andarist](https://github.com/Andarist)! - Returned releases in pre mode will have type of the highest bump type within the current release now, instead of having the highest bump type from among all changesets within this pre mode. So if you release a new prerelease including a major bump and later release the same package with a minor bump the assembled release will be of type minor - the final computed version will, of course, still be the next one for a major bump.
### Patch Changes
- [`d1d987c`](https://github.com/atlassian/changesets/commit/d1d987c42cddff8be5d7f04d3ebb5a262779fa9f) [#455](https://github.com/atlassian/changesets/pull/455) Thanks [@Andarist](https://github.com/Andarist)! - Fixed an issue with linked package being assigned a non-none release type when another package from the linked set has been added to current releases and the package had just a none release type.
* [`9d99bd1`](https://github.com/atlassian/changesets/commit/9d99bd16f2b6b3ab4fe820358d4c9f313cb2ae76) [#446](https://github.com/atlassian/changesets/pull/446) Thanks [@Andarist](https://github.com/Andarist)! - Fixed an issue with dependant packages not being updated to their highest bump type in pre mode sometimes. This could happen when dependant packages were only versioned because of their dependencies being upgraded and not because of a dedicated changeset for those dependant packages.
For the very same reason linked packages were also not always bumped correctly in pre mode to the highest bump type in a linked group.
## 3.0.1

@@ -4,0 +18,0 @@

204

dist/assemble-release-plan.cjs.dev.js

@@ -270,3 +270,3 @@ 'use strict';

// First we filter down to all the relevent releases for one set of linked packages
let releasingLinkedPackages = [...releases.values()].filter(release => linkedPackages.includes(release.name)); // If we proceed any further we do extra work with calculating highestVersion for things that might
let releasingLinkedPackages = [...releases.values()].filter(release => linkedPackages.includes(release.name) && release.type !== "none"); // If we proceed any further we do extra work with calculating highestVersion for things that might
// not need one, as they only have workspace based packages

@@ -340,2 +340,6 @@

function getSnapshotSuffix(snapshot) {
if (snapshot === undefined) {
return;
}
const now = new Date();

@@ -348,3 +352,3 @@ let dateAndTime = [now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds()].join("");

function getNewVersion(release, preInfo, snapshot, snapshotSuffix, useCalculatedVersionForSnapshots) {
function getNewVersion(release, preInfo, snapshotSuffix, useCalculatedVersionForSnapshots) {
/**

@@ -359,3 +363,3 @@ * Using version as 0.0.0 so that it does not hinder with other version release

*/
if (snapshot && !useCalculatedVersionForSnapshots) {
if (snapshotSuffix && !useCalculatedVersionForSnapshots) {
return `0.0.0${snapshotSuffix}`;

@@ -366,3 +370,3 @@ }

if (snapshot && useCalculatedVersionForSnapshots) {
if (snapshotSuffix && useCalculatedVersionForSnapshots) {
return `${calculatedVersion}${snapshotSuffix}`;

@@ -375,112 +379,15 @@ }

function assembleReleasePlan(changesets, packages, config, preState, snapshot) {
validateChangesets(changesets, config.ignore);
let updatedPreState = preState === undefined ? undefined : _objectSpread(_objectSpread({}, preState), {}, {
initialVersions: _objectSpread({}, preState.initialVersions)
}); // Caching the snapshot version here and use this if it is snapshot release
let snapshotSuffix;
if (snapshot !== undefined) {
snapshotSuffix = getSnapshotSuffix(snapshot);
}
let packagesByName = new Map(packages.packages.map(x => [x.packageJson.name, x]));
let unfilteredChangesets = changesets;
let preVersions = new Map();
const relevantChangesets = getRelevantChangesets(changesets, config.ignore, preState);
const preInfo = getPreInfo(changesets, packagesByName, config, preState); // Caching the snapshot version here and use this if it is snapshot release
if (updatedPreState !== undefined) {
for (let pkg of packages.packages) {
if (updatedPreState.initialVersions[pkg.packageJson.name] === undefined) {
updatedPreState.initialVersions[pkg.packageJson.name] = pkg.packageJson.version;
}
}
if (updatedPreState.mode !== "exit") {
let usedChangesetIds = new Set(updatedPreState.changesets);
updatedPreState.changesets = changesets.map(x => x.id);
changesets = changesets.filter(changeset => !usedChangesetIds.has(changeset.id));
} // Populate preVersion
// preVersion is the map between package name and its next pre version number.
for (let pkg of packages.packages) {
preVersions.set(pkg.packageJson.name, getPreVersion(pkg.packageJson.version));
}
for (let linkedGroup of config.linked) {
let highestPreVersion = 0;
for (let linkedPackage of linkedGroup) {
highestPreVersion = Math.max(getPreVersion(packagesByName.get(linkedPackage).packageJson.version), highestPreVersion);
}
for (let linkedPackage of linkedGroup) {
preVersions.set(linkedPackage, highestPreVersion);
}
}
for (let pkg of packages.packages) {
packagesByName.set(pkg.packageJson.name, _objectSpread(_objectSpread({}, pkg), {}, {
packageJson: _objectSpread(_objectSpread({}, pkg.packageJson), {}, {
version: updatedPreState.initialVersions[pkg.packageJson.name]
})
}));
}
} // releases is, at this point a list of all packages we are going to releases,
const snapshotSuffix = getSnapshotSuffix(snapshot); // releases is, at this point a list of all packages we are going to releases,
// flattened down to one release per package, having a reference back to their
// changesets, and with a calculated new versions
let releases = flattenReleases(changesets, packagesByName, config.ignore);
if (updatedPreState !== undefined) {
if (updatedPreState.mode === "exit") {
for (let pkg of packages.packages) {
// If a package had a prerelease, but didn't trigger a version bump in the regular release,
// we want to give it a patch release.
// Detailed explaination at https://github.com/atlassian/changesets/pull/382#discussion_r434434182
if (preVersions.get(pkg.packageJson.name) !== 0) {
if (!releases.has(pkg.packageJson.name)) {
releases.set(pkg.packageJson.name, {
type: "patch",
name: pkg.packageJson.name,
changesets: [],
oldVersion: pkg.packageJson.version
});
}
}
}
} else {
// for every release in pre mode, we want versions to be bumped to the highest bump type
// across all the changesets even if the package doesn't have a changeset that releases
// to the highest bump type in a given release in pre mode and importantly
// we don't want to add any new releases, we only want to update ones that will already happen
// because if they're not being released, the version will already have been bumped with the highest bump type
let releasesFromUnfilteredChangesets = flattenReleases(unfilteredChangesets, packagesByName, config.ignore);
releases.forEach((value, key) => {
let releaseFromUnfilteredChangesets = releasesFromUnfilteredChangesets.get(key);
if (releaseFromUnfilteredChangesets === undefined) {
throw new errors.InternalError("releaseFromUnfilteredChangesets is undefined");
}
releases.set(key, _objectSpread(_objectSpread({}, value), {}, {
// note that we're only setting the type, not the changesets which could be different(the name and oldVersion would be the same so they don't matter)
// because the changesets on a given release refer to why a given package is being released
// NOT why it's being released with a given bump type
// (the bump type could change because of this, linked or peer dependencies)
type: releaseFromUnfilteredChangesets.type
}));
});
}
}
let preInfo = updatedPreState === undefined ? undefined : {
state: updatedPreState,
preVersions
};
let releases = flattenReleases(relevantChangesets, packagesByName, config.ignore);
let dependencyGraph = getDependentsGraph.getDependentsGraph(packages);
let releaseObjectValidated = false;
let releasesValidated = false;
while (releaseObjectValidated === false) {
while (releasesValidated === false) {
// The map passed in to determineDependents will be mutated

@@ -497,18 +404,35 @@ let dependentAdded = getDependents({

let linksUpdated = applyLinks(releases, packagesByName, config.linked);
releaseObjectValidated = !linksUpdated && !dependentAdded;
releasesValidated = !linksUpdated && !dependentAdded;
}
if ((preInfo === null || preInfo === void 0 ? void 0 : preInfo.state.mode) === "exit") {
for (let pkg of packages.packages) {
// If a package had a prerelease, but didn't trigger a version bump in the regular release,
// we want to give it a patch release.
// Detailed explaination at https://github.com/atlassian/changesets/pull/382#discussion_r434434182
if (preInfo.preVersions.get(pkg.packageJson.name) !== 0) {
if (!releases.has(pkg.packageJson.name)) {
releases.set(pkg.packageJson.name, {
type: "patch",
name: pkg.packageJson.name,
changesets: [],
oldVersion: pkg.packageJson.version
});
}
}
}
}
return {
changesets,
changesets: relevantChangesets,
releases: [...releases.values()].map(incompleteRelease => {
return _objectSpread(_objectSpread({}, incompleteRelease), {}, {
newVersion: getNewVersion(incompleteRelease, preInfo, snapshot, snapshotSuffix, config.___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH.useCalculatedVersionForSnapshots)
newVersion: getNewVersion(incompleteRelease, preInfo, snapshotSuffix, config.___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH.useCalculatedVersionForSnapshots)
});
}),
preState: updatedPreState
preState: preInfo === null || preInfo === void 0 ? void 0 : preInfo.state
};
} // Changesets that contains both ignored and not ignored packages are not allowed
}
function validateChangesets(changesets, ignored) {
function getRelevantChangesets(changesets, ignored, preState) {
for (const changeset of changesets) {

@@ -532,4 +456,56 @@ // Using the following 2 arrays to decide whether a changeset

}
if (preState && preState.mode !== "exit") {
let usedChangesetIds = new Set(preState.changesets);
return changesets.filter(changeset => !usedChangesetIds.has(changeset.id));
}
return changesets;
}
function getPreInfo(changesets, packagesByName, config, preState) {
if (preState === undefined) {
return;
}
let updatedPreState = _objectSpread(_objectSpread({}, preState), {}, {
initialVersions: _objectSpread({}, preState.initialVersions)
});
let preVersions = new Map();
if (updatedPreState !== undefined) {
for (const [, pkg] of packagesByName) {
if (updatedPreState.initialVersions[pkg.packageJson.name] === undefined) {
updatedPreState.initialVersions[pkg.packageJson.name] = pkg.packageJson.version;
}
} // Populate preVersion
// preVersion is the map between package name and its next pre version number.
for (const [, pkg] of packagesByName) {
preVersions.set(pkg.packageJson.name, getPreVersion(pkg.packageJson.version));
}
for (let linkedGroup of config.linked) {
let highestPreVersion = 0;
for (let linkedPackage of linkedGroup) {
highestPreVersion = Math.max(getPreVersion(packagesByName.get(linkedPackage).packageJson.version), highestPreVersion);
}
for (let linkedPackage of linkedGroup) {
preVersions.set(linkedPackage, highestPreVersion);
}
}
updatedPreState.changesets = changesets.map(changeset => changeset.id);
}
return {
state: updatedPreState,
preVersions
};
}
exports.default = assembleReleasePlan;

@@ -117,3 +117,3 @@ "use strict";

for (let linkedPackages of linked) {
let highestReleaseType, highestVersion, releasingLinkedPackages = [ ...releases.values() ].filter(release => linkedPackages.includes(release.name));
let highestReleaseType, highestVersion, releasingLinkedPackages = [ ...releases.values() ].filter(release => linkedPackages.includes(release.name) && "none" !== release.type);
if (!(releasingLinkedPackages.length < 1)) {

@@ -175,2 +175,3 @@ for (let pkg of releasingLinkedPackages) highestReleaseType ? "major" === pkg.type ? highestReleaseType = pkg.type : "minor" === pkg.type && "major" !== highestReleaseType && (highestReleaseType = pkg.type) : highestReleaseType = pkg.type;

function getSnapshotSuffix(snapshot) {
if (void 0 === snapshot) return;
const now = new Date;

@@ -181,54 +182,13 @@ let tag = "";

function getNewVersion(release, preInfo, snapshot, snapshotSuffix, useCalculatedVersionForSnapshots) {
if (snapshot && !useCalculatedVersionForSnapshots) return `0.0.0${snapshotSuffix}`;
function getNewVersion(release, preInfo, snapshotSuffix, useCalculatedVersionForSnapshots) {
if (snapshotSuffix && !useCalculatedVersionForSnapshots) return `0.0.0${snapshotSuffix}`;
const calculatedVersion = incrementVersion(release, preInfo);
return snapshot && useCalculatedVersionForSnapshots ? `${calculatedVersion}${snapshotSuffix}` : calculatedVersion;
return snapshotSuffix && useCalculatedVersionForSnapshots ? `${calculatedVersion}${snapshotSuffix}` : calculatedVersion;
}
function assembleReleasePlan(changesets, packages, config, preState, snapshot) {
validateChangesets(changesets, config.ignore);
let snapshotSuffix, updatedPreState = void 0 === preState ? void 0 : _objectSpread(_objectSpread({}, preState), {}, {
initialVersions: _objectSpread({}, preState.initialVersions)
});
void 0 !== snapshot && (snapshotSuffix = getSnapshotSuffix(snapshot));
let packagesByName = new Map(packages.packages.map(x => [ x.packageJson.name, x ])), unfilteredChangesets = changesets, preVersions = new Map;
if (void 0 !== updatedPreState) {
for (let pkg of packages.packages) void 0 === updatedPreState.initialVersions[pkg.packageJson.name] && (updatedPreState.initialVersions[pkg.packageJson.name] = pkg.packageJson.version);
if ("exit" !== updatedPreState.mode) {
let usedChangesetIds = new Set(updatedPreState.changesets);
updatedPreState.changesets = changesets.map(x => x.id), changesets = changesets.filter(changeset => !usedChangesetIds.has(changeset.id));
}
for (let pkg of packages.packages) preVersions.set(pkg.packageJson.name, getPreVersion(pkg.packageJson.version));
for (let linkedGroup of config.linked) {
let highestPreVersion = 0;
for (let linkedPackage of linkedGroup) highestPreVersion = Math.max(getPreVersion(packagesByName.get(linkedPackage).packageJson.version), highestPreVersion);
for (let linkedPackage of linkedGroup) preVersions.set(linkedPackage, highestPreVersion);
}
for (let pkg of packages.packages) packagesByName.set(pkg.packageJson.name, _objectSpread(_objectSpread({}, pkg), {}, {
packageJson: _objectSpread(_objectSpread({}, pkg.packageJson), {}, {
version: updatedPreState.initialVersions[pkg.packageJson.name]
})
}));
}
let releases = flattenReleases(changesets, packagesByName, config.ignore);
if (void 0 !== updatedPreState) if ("exit" === updatedPreState.mode) for (let pkg of packages.packages) 0 !== preVersions.get(pkg.packageJson.name) && (releases.has(pkg.packageJson.name) || releases.set(pkg.packageJson.name, {
type: "patch",
name: pkg.packageJson.name,
changesets: [],
oldVersion: pkg.packageJson.version
})); else {
let releasesFromUnfilteredChangesets = flattenReleases(unfilteredChangesets, packagesByName, config.ignore);
releases.forEach((value, key) => {
let releaseFromUnfilteredChangesets = releasesFromUnfilteredChangesets.get(key);
if (void 0 === releaseFromUnfilteredChangesets) throw new errors.InternalError("releaseFromUnfilteredChangesets is undefined");
releases.set(key, _objectSpread(_objectSpread({}, value), {}, {
type: releaseFromUnfilteredChangesets.type
}));
});
}
let preInfo = void 0 === updatedPreState ? void 0 : {
state: updatedPreState,
preVersions: preVersions
}, dependencyGraph = getDependentsGraph.getDependentsGraph(packages), releaseObjectValidated = !1;
for (;!1 === releaseObjectValidated; ) {
let packagesByName = new Map(packages.packages.map(x => [ x.packageJson.name, x ]));
const relevantChangesets = getRelevantChangesets(changesets, config.ignore, preState), preInfo = getPreInfo(changesets, packagesByName, config, preState), snapshotSuffix = getSnapshotSuffix(snapshot);
let releases = flattenReleases(relevantChangesets, packagesByName, config.ignore), dependencyGraph = getDependentsGraph.getDependentsGraph(packages), releasesValidated = !1;
for (;!1 === releasesValidated; ) {
let dependentAdded = getDependents({

@@ -242,14 +202,20 @@ releases: releases,

});
releaseObjectValidated = !applyLinks(releases, packagesByName, config.linked) && !dependentAdded;
releasesValidated = !applyLinks(releases, packagesByName, config.linked) && !dependentAdded;
}
if ("exit" === (null == preInfo ? void 0 : preInfo.state.mode)) for (let pkg of packages.packages) 0 !== preInfo.preVersions.get(pkg.packageJson.name) && (releases.has(pkg.packageJson.name) || releases.set(pkg.packageJson.name, {
type: "patch",
name: pkg.packageJson.name,
changesets: [],
oldVersion: pkg.packageJson.version
}));
return {
changesets: changesets,
changesets: relevantChangesets,
releases: [ ...releases.values() ].map(incompleteRelease => _objectSpread(_objectSpread({}, incompleteRelease), {}, {
newVersion: getNewVersion(incompleteRelease, preInfo, snapshot, snapshotSuffix, config.___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH.useCalculatedVersionForSnapshots)
newVersion: getNewVersion(incompleteRelease, preInfo, snapshotSuffix, config.___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH.useCalculatedVersionForSnapshots)
})),
preState: updatedPreState
preState: null == preInfo ? void 0 : preInfo.state
};
}
function validateChangesets(changesets, ignored) {
function getRelevantChangesets(changesets, ignored, preState) {
for (const changeset of changesets) {

@@ -260,4 +226,30 @@ const ignoredPackages = [], notIgnoredPackages = [];

}
if (preState && "exit" !== preState.mode) {
let usedChangesetIds = new Set(preState.changesets);
return changesets.filter(changeset => !usedChangesetIds.has(changeset.id));
}
return changesets;
}
function getPreInfo(changesets, packagesByName, config, preState) {
if (void 0 === preState) return;
let updatedPreState = _objectSpread(_objectSpread({}, preState), {}, {
initialVersions: _objectSpread({}, preState.initialVersions)
}), preVersions = new Map;
if (void 0 !== updatedPreState) {
for (const [, pkg] of packagesByName) void 0 === updatedPreState.initialVersions[pkg.packageJson.name] && (updatedPreState.initialVersions[pkg.packageJson.name] = pkg.packageJson.version);
for (const [, pkg] of packagesByName) preVersions.set(pkg.packageJson.name, getPreVersion(pkg.packageJson.version));
for (let linkedGroup of config.linked) {
let highestPreVersion = 0;
for (let linkedPackage of linkedGroup) highestPreVersion = Math.max(getPreVersion(packagesByName.get(linkedPackage).packageJson.version), highestPreVersion);
for (let linkedPackage of linkedGroup) preVersions.set(linkedPackage, highestPreVersion);
}
updatedPreState.changesets = changesets.map(changeset => changeset.id);
}
return {
state: updatedPreState,
preVersions: preVersions
};
}
exports.default = assembleReleasePlan;

@@ -263,3 +263,3 @@ import semver__default, { inc, parse } from 'semver';

// First we filter down to all the relevent releases for one set of linked packages
let releasingLinkedPackages = [...releases.values()].filter(release => linkedPackages.includes(release.name)); // If we proceed any further we do extra work with calculating highestVersion for things that might
let releasingLinkedPackages = [...releases.values()].filter(release => linkedPackages.includes(release.name) && release.type !== "none"); // If we proceed any further we do extra work with calculating highestVersion for things that might
// not need one, as they only have workspace based packages

@@ -333,2 +333,6 @@

function getSnapshotSuffix(snapshot) {
if (snapshot === undefined) {
return;
}
const now = new Date();

@@ -341,3 +345,3 @@ let dateAndTime = [now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds()].join("");

function getNewVersion(release, preInfo, snapshot, snapshotSuffix, useCalculatedVersionForSnapshots) {
function getNewVersion(release, preInfo, snapshotSuffix, useCalculatedVersionForSnapshots) {
/**

@@ -352,3 +356,3 @@ * Using version as 0.0.0 so that it does not hinder with other version release

*/
if (snapshot && !useCalculatedVersionForSnapshots) {
if (snapshotSuffix && !useCalculatedVersionForSnapshots) {
return `0.0.0${snapshotSuffix}`;

@@ -359,3 +363,3 @@ }

if (snapshot && useCalculatedVersionForSnapshots) {
if (snapshotSuffix && useCalculatedVersionForSnapshots) {
return `${calculatedVersion}${snapshotSuffix}`;

@@ -368,112 +372,15 @@ }

function assembleReleasePlan(changesets, packages, config, preState, snapshot) {
validateChangesets(changesets, config.ignore);
let updatedPreState = preState === undefined ? undefined : _objectSpread(_objectSpread({}, preState), {}, {
initialVersions: _objectSpread({}, preState.initialVersions)
}); // Caching the snapshot version here and use this if it is snapshot release
let snapshotSuffix;
if (snapshot !== undefined) {
snapshotSuffix = getSnapshotSuffix(snapshot);
}
let packagesByName = new Map(packages.packages.map(x => [x.packageJson.name, x]));
let unfilteredChangesets = changesets;
let preVersions = new Map();
const relevantChangesets = getRelevantChangesets(changesets, config.ignore, preState);
const preInfo = getPreInfo(changesets, packagesByName, config, preState); // Caching the snapshot version here and use this if it is snapshot release
if (updatedPreState !== undefined) {
for (let pkg of packages.packages) {
if (updatedPreState.initialVersions[pkg.packageJson.name] === undefined) {
updatedPreState.initialVersions[pkg.packageJson.name] = pkg.packageJson.version;
}
}
if (updatedPreState.mode !== "exit") {
let usedChangesetIds = new Set(updatedPreState.changesets);
updatedPreState.changesets = changesets.map(x => x.id);
changesets = changesets.filter(changeset => !usedChangesetIds.has(changeset.id));
} // Populate preVersion
// preVersion is the map between package name and its next pre version number.
for (let pkg of packages.packages) {
preVersions.set(pkg.packageJson.name, getPreVersion(pkg.packageJson.version));
}
for (let linkedGroup of config.linked) {
let highestPreVersion = 0;
for (let linkedPackage of linkedGroup) {
highestPreVersion = Math.max(getPreVersion(packagesByName.get(linkedPackage).packageJson.version), highestPreVersion);
}
for (let linkedPackage of linkedGroup) {
preVersions.set(linkedPackage, highestPreVersion);
}
}
for (let pkg of packages.packages) {
packagesByName.set(pkg.packageJson.name, _objectSpread(_objectSpread({}, pkg), {}, {
packageJson: _objectSpread(_objectSpread({}, pkg.packageJson), {}, {
version: updatedPreState.initialVersions[pkg.packageJson.name]
})
}));
}
} // releases is, at this point a list of all packages we are going to releases,
const snapshotSuffix = getSnapshotSuffix(snapshot); // releases is, at this point a list of all packages we are going to releases,
// flattened down to one release per package, having a reference back to their
// changesets, and with a calculated new versions
let releases = flattenReleases(changesets, packagesByName, config.ignore);
if (updatedPreState !== undefined) {
if (updatedPreState.mode === "exit") {
for (let pkg of packages.packages) {
// If a package had a prerelease, but didn't trigger a version bump in the regular release,
// we want to give it a patch release.
// Detailed explaination at https://github.com/atlassian/changesets/pull/382#discussion_r434434182
if (preVersions.get(pkg.packageJson.name) !== 0) {
if (!releases.has(pkg.packageJson.name)) {
releases.set(pkg.packageJson.name, {
type: "patch",
name: pkg.packageJson.name,
changesets: [],
oldVersion: pkg.packageJson.version
});
}
}
}
} else {
// for every release in pre mode, we want versions to be bumped to the highest bump type
// across all the changesets even if the package doesn't have a changeset that releases
// to the highest bump type in a given release in pre mode and importantly
// we don't want to add any new releases, we only want to update ones that will already happen
// because if they're not being released, the version will already have been bumped with the highest bump type
let releasesFromUnfilteredChangesets = flattenReleases(unfilteredChangesets, packagesByName, config.ignore);
releases.forEach((value, key) => {
let releaseFromUnfilteredChangesets = releasesFromUnfilteredChangesets.get(key);
if (releaseFromUnfilteredChangesets === undefined) {
throw new InternalError("releaseFromUnfilteredChangesets is undefined");
}
releases.set(key, _objectSpread(_objectSpread({}, value), {}, {
// note that we're only setting the type, not the changesets which could be different(the name and oldVersion would be the same so they don't matter)
// because the changesets on a given release refer to why a given package is being released
// NOT why it's being released with a given bump type
// (the bump type could change because of this, linked or peer dependencies)
type: releaseFromUnfilteredChangesets.type
}));
});
}
}
let preInfo = updatedPreState === undefined ? undefined : {
state: updatedPreState,
preVersions
};
let releases = flattenReleases(relevantChangesets, packagesByName, config.ignore);
let dependencyGraph = getDependentsGraph(packages);
let releaseObjectValidated = false;
let releasesValidated = false;
while (releaseObjectValidated === false) {
while (releasesValidated === false) {
// The map passed in to determineDependents will be mutated

@@ -490,18 +397,35 @@ let dependentAdded = getDependents({

let linksUpdated = applyLinks(releases, packagesByName, config.linked);
releaseObjectValidated = !linksUpdated && !dependentAdded;
releasesValidated = !linksUpdated && !dependentAdded;
}
if ((preInfo === null || preInfo === void 0 ? void 0 : preInfo.state.mode) === "exit") {
for (let pkg of packages.packages) {
// If a package had a prerelease, but didn't trigger a version bump in the regular release,
// we want to give it a patch release.
// Detailed explaination at https://github.com/atlassian/changesets/pull/382#discussion_r434434182
if (preInfo.preVersions.get(pkg.packageJson.name) !== 0) {
if (!releases.has(pkg.packageJson.name)) {
releases.set(pkg.packageJson.name, {
type: "patch",
name: pkg.packageJson.name,
changesets: [],
oldVersion: pkg.packageJson.version
});
}
}
}
}
return {
changesets,
changesets: relevantChangesets,
releases: [...releases.values()].map(incompleteRelease => {
return _objectSpread(_objectSpread({}, incompleteRelease), {}, {
newVersion: getNewVersion(incompleteRelease, preInfo, snapshot, snapshotSuffix, config.___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH.useCalculatedVersionForSnapshots)
newVersion: getNewVersion(incompleteRelease, preInfo, snapshotSuffix, config.___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH.useCalculatedVersionForSnapshots)
});
}),
preState: updatedPreState
preState: preInfo === null || preInfo === void 0 ? void 0 : preInfo.state
};
} // Changesets that contains both ignored and not ignored packages are not allowed
}
function validateChangesets(changesets, ignored) {
function getRelevantChangesets(changesets, ignored, preState) {
for (const changeset of changesets) {

@@ -525,4 +449,56 @@ // Using the following 2 arrays to decide whether a changeset

}
if (preState && preState.mode !== "exit") {
let usedChangesetIds = new Set(preState.changesets);
return changesets.filter(changeset => !usedChangesetIds.has(changeset.id));
}
return changesets;
}
function getPreInfo(changesets, packagesByName, config, preState) {
if (preState === undefined) {
return;
}
let updatedPreState = _objectSpread(_objectSpread({}, preState), {}, {
initialVersions: _objectSpread({}, preState.initialVersions)
});
let preVersions = new Map();
if (updatedPreState !== undefined) {
for (const [, pkg] of packagesByName) {
if (updatedPreState.initialVersions[pkg.packageJson.name] === undefined) {
updatedPreState.initialVersions[pkg.packageJson.name] = pkg.packageJson.version;
}
} // Populate preVersion
// preVersion is the map between package name and its next pre version number.
for (const [, pkg] of packagesByName) {
preVersions.set(pkg.packageJson.name, getPreVersion(pkg.packageJson.version));
}
for (let linkedGroup of config.linked) {
let highestPreVersion = 0;
for (let linkedPackage of linkedGroup) {
highestPreVersion = Math.max(getPreVersion(packagesByName.get(linkedPackage).packageJson.version), highestPreVersion);
}
for (let linkedPackage of linkedGroup) {
preVersions.set(linkedPackage, highestPreVersion);
}
}
updatedPreState.changesets = changesets.map(changeset => changeset.id);
}
return {
state: updatedPreState,
preVersions
};
}
export default assembleReleasePlan;

@@ -10,3 +10,3 @@ import { VersionType, PreState } from "@changesets/types";

state: PreState;
preVersions: Map<string, string>;
preVersions: Map<string, number>;
};
{
"name": "@changesets/assemble-release-plan",
"version": "3.0.1",
"version": "4.0.0",
"description": "Reads changesets and adds information on dependents that need bumping",

@@ -5,0 +5,0 @@ "main": "dist/assemble-release-plan.cjs.js",

@@ -29,4 +29,5 @@ import semver from "semver";

// First we filter down to all the relevent releases for one set of linked packages
let releasingLinkedPackages = [...releases.values()].filter(release =>
linkedPackages.includes(release.name)
let releasingLinkedPackages = [...releases.values()].filter(
release =>
linkedPackages.includes(release.name) && release.type !== "none"
);

@@ -33,0 +34,0 @@

@@ -507,4 +507,4 @@ import { defaultConfig } from "@changesets/config";

describe("pre mode exit", () => {
it("should not generate a release for package that has no changesets and is not a dependent of any packages being released", () => {
describe("pre mode", () => {
it("should not generate a release for package that has no changesets and is not a dependent of any packages being released when exiting pre mode", () => {
const { releases } = assembleReleasePlan(

@@ -528,2 +528,49 @@ setup.changesets,

});
it("should return a release with the highest bump type within the current release despite of having a higher release among previous prereleases", () => {
// previous release
setup.addChangeset({
id: "major-bumping-one",
releases: [
{
name: "pkg-a",
type: "major"
}
]
});
setup.updatePackage("pkg-a", "2.0.0-next.0");
// current release
setup.addChangeset({
id: "minor-bumping-one",
releases: [
{
name: "pkg-a",
type: "minor"
}
]
});
const { releases } = assembleReleasePlan(
setup.changesets,
setup.packages,
{
...defaultConfig
},
{
changesets: ["major-bumping-one"],
tag: "next",
initialVersions: {
"pkg-a": "1.0.0",
"pkg-b": "1.0.0",
"pkg-c": "1.0.0"
},
mode: "pre"
}
);
expect(releases.length).toEqual(1);
expect(releases[0].name).toEqual("pkg-a");
expect(releases[0].newVersion).toEqual("2.0.0-next.1");
expect(releases[0].type).toEqual("minor");
});
});

@@ -530,0 +577,0 @@ });

@@ -8,3 +8,3 @@ import { ReleasePlan, Config, NewChangeset, PreState } from "@changesets/types";

import { InternalError } from "@changesets/errors";
import { Packages } from "@manypkg/get-packages";
import { Packages, Package } from "@manypkg/get-packages";
import { getDependentsGraph } from "@changesets/get-dependents-graph";

@@ -24,3 +24,6 @@ import { PreInfo, InternalRelease } from "./types";

function getSnapshotSuffix(snapshot?: string | boolean): string {
function getSnapshotSuffix(snapshot?: string | boolean): string | undefined {
if (snapshot === undefined) {
return;
}
const now = new Date();

@@ -46,4 +49,3 @@

preInfo: PreInfo | undefined,
snapshot: string | boolean | undefined,
snapshotSuffix: string,
snapshotSuffix: string | undefined,
useCalculatedVersionForSnapshots: boolean

@@ -60,3 +62,3 @@ ): string {

*/
if (snapshot && !useCalculatedVersionForSnapshots) {
if (snapshotSuffix && !useCalculatedVersionForSnapshots) {
return `0.0.0${snapshotSuffix}`;

@@ -67,3 +69,3 @@ }

if (snapshot && useCalculatedVersionForSnapshots) {
if (snapshotSuffix && useCalculatedVersionForSnapshots) {
return `${calculatedVersion}${snapshotSuffix}`;

@@ -82,20 +84,2 @@ }

): ReleasePlan {
validateChangesets(changesets, config.ignore);
let updatedPreState: PreState | undefined =
preState === undefined
? undefined
: {
...preState,
initialVersions: {
...preState.initialVersions
}
};
// Caching the snapshot version here and use this if it is snapshot release
let snapshotSuffix: string;
if (snapshot !== undefined) {
snapshotSuffix = getSnapshotSuffix(snapshot);
}
let packagesByName = new Map(

@@ -105,120 +89,26 @@ packages.packages.map(x => [x.packageJson.name, x])

let unfilteredChangesets = changesets;
const relevantChangesets = getRelevantChangesets(
changesets,
config.ignore,
preState
);
let preVersions = new Map();
if (updatedPreState !== undefined) {
for (let pkg of packages.packages) {
if (updatedPreState.initialVersions[pkg.packageJson.name] === undefined) {
updatedPreState.initialVersions[pkg.packageJson.name] =
pkg.packageJson.version;
}
}
if (updatedPreState.mode !== "exit") {
let usedChangesetIds = new Set(updatedPreState.changesets);
updatedPreState.changesets = changesets.map(x => x.id);
changesets = changesets.filter(
changeset => !usedChangesetIds.has(changeset.id)
);
}
const preInfo = getPreInfo(changesets, packagesByName, config, preState);
// Populate preVersion
// preVersion is the map between package name and its next pre version number.
for (let pkg of packages.packages) {
preVersions.set(
pkg.packageJson.name,
getPreVersion(pkg.packageJson.version)
);
}
for (let linkedGroup of config.linked) {
let highestPreVersion = 0;
for (let linkedPackage of linkedGroup) {
highestPreVersion = Math.max(
getPreVersion(packagesByName.get(linkedPackage)!.packageJson.version),
highestPreVersion
);
}
for (let linkedPackage of linkedGroup) {
preVersions.set(linkedPackage, highestPreVersion);
}
}
// Caching the snapshot version here and use this if it is snapshot release
const snapshotSuffix = getSnapshotSuffix(snapshot);
for (let pkg of packages.packages) {
packagesByName.set(pkg.packageJson.name, {
...pkg,
packageJson: {
...pkg.packageJson,
version: updatedPreState.initialVersions[pkg.packageJson.name]
}
});
}
}
// releases is, at this point a list of all packages we are going to releases,
// flattened down to one release per package, having a reference back to their
// changesets, and with a calculated new versions
let releases = flattenReleases(changesets, packagesByName, config.ignore);
let releases = flattenReleases(
relevantChangesets,
packagesByName,
config.ignore
);
if (updatedPreState !== undefined) {
if (updatedPreState.mode === "exit") {
for (let pkg of packages.packages) {
// If a package had a prerelease, but didn't trigger a version bump in the regular release,
// we want to give it a patch release.
// Detailed explaination at https://github.com/atlassian/changesets/pull/382#discussion_r434434182
if (preVersions.get(pkg.packageJson.name) !== 0) {
if (!releases.has(pkg.packageJson.name)) {
releases.set(pkg.packageJson.name, {
type: "patch",
name: pkg.packageJson.name,
changesets: [],
oldVersion: pkg.packageJson.version
});
}
}
}
} else {
// for every release in pre mode, we want versions to be bumped to the highest bump type
// across all the changesets even if the package doesn't have a changeset that releases
// to the highest bump type in a given release in pre mode and importantly
// we don't want to add any new releases, we only want to update ones that will already happen
// because if they're not being released, the version will already have been bumped with the highest bump type
let releasesFromUnfilteredChangesets = flattenReleases(
unfilteredChangesets,
packagesByName,
config.ignore
);
releases.forEach((value, key) => {
let releaseFromUnfilteredChangesets = releasesFromUnfilteredChangesets.get(
key
);
if (releaseFromUnfilteredChangesets === undefined) {
throw new InternalError(
"releaseFromUnfilteredChangesets is undefined"
);
}
releases.set(key, {
...value,
// note that we're only setting the type, not the changesets which could be different(the name and oldVersion would be the same so they don't matter)
// because the changesets on a given release refer to why a given package is being released
// NOT why it's being released with a given bump type
// (the bump type could change because of this, linked or peer dependencies)
type: releaseFromUnfilteredChangesets.type
});
});
}
}
let preInfo: PreInfo | undefined =
updatedPreState === undefined
? undefined
: {
state: updatedPreState,
preVersions
};
let dependencyGraph = getDependentsGraph(packages);
let releaseObjectValidated = false;
while (releaseObjectValidated === false) {
let releasesValidated = false;
while (releasesValidated === false) {
// The map passed in to determineDependents will be mutated

@@ -239,7 +129,25 @@ let dependentAdded = determineDependents({

releaseObjectValidated = !linksUpdated && !dependentAdded;
releasesValidated = !linksUpdated && !dependentAdded;
}
if (preInfo?.state.mode === "exit") {
for (let pkg of packages.packages) {
// If a package had a prerelease, but didn't trigger a version bump in the regular release,
// we want to give it a patch release.
// Detailed explaination at https://github.com/atlassian/changesets/pull/382#discussion_r434434182
if (preInfo.preVersions.get(pkg.packageJson.name) !== 0) {
if (!releases.has(pkg.packageJson.name)) {
releases.set(pkg.packageJson.name, {
type: "patch",
name: pkg.packageJson.name,
changesets: [],
oldVersion: pkg.packageJson.version
});
}
}
}
}
return {
changesets,
changesets: relevantChangesets,
releases: [...releases.values()].map(incompleteRelease => {

@@ -251,3 +159,2 @@ return {

preInfo,
snapshot,
snapshotSuffix,

@@ -259,11 +166,11 @@ config.___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH

}),
preState: updatedPreState
preState: preInfo?.state
};
}
// Changesets that contains both ignored and not ignored packages are not allowed
function validateChangesets(
function getRelevantChangesets(
changesets: NewChangeset[],
ignored: Readonly<string[]>
): void {
ignored: Readonly<string[]>,
preState: PreState | undefined
): NewChangeset[] {
for (const changeset of changesets) {

@@ -293,4 +200,66 @@ // Using the following 2 arrays to decide whether a changeset

}
if (preState && preState.mode !== "exit") {
let usedChangesetIds = new Set(preState.changesets);
return changesets.filter(changeset => !usedChangesetIds.has(changeset.id));
}
return changesets;
}
function getPreInfo(
changesets: NewChangeset[],
packagesByName: Map<string, Package>,
config: Config,
preState: PreState | undefined
): PreInfo | undefined {
if (preState === undefined) {
return;
}
let updatedPreState = {
...preState,
initialVersions: {
...preState.initialVersions
}
};
let preVersions = new Map<string, number>();
if (updatedPreState !== undefined) {
for (const [, pkg] of packagesByName) {
if (updatedPreState.initialVersions[pkg.packageJson.name] === undefined) {
updatedPreState.initialVersions[pkg.packageJson.name] =
pkg.packageJson.version;
}
}
// Populate preVersion
// preVersion is the map between package name and its next pre version number.
for (const [, pkg] of packagesByName) {
preVersions.set(
pkg.packageJson.name,
getPreVersion(pkg.packageJson.version)
);
}
for (let linkedGroup of config.linked) {
let highestPreVersion = 0;
for (let linkedPackage of linkedGroup) {
highestPreVersion = Math.max(
getPreVersion(packagesByName.get(linkedPackage)!.packageJson.version),
highestPreVersion
);
}
for (let linkedPackage of linkedGroup) {
preVersions.set(linkedPackage, highestPreVersion);
}
}
updatedPreState.changesets = changesets.map(changeset => changeset.id);
}
return {
state: updatedPreState,
preVersions
};
}
export default assembleReleasePlan;

@@ -12,3 +12,3 @@ import { VersionType, PreState } from "@changesets/types";

state: PreState;
preVersions: Map<string, string>;
preVersions: Map<string, number>;
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc