Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/build-dep-graph.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const path = require('path');
const semver = require('semver');
const { satisfies } = require('./semver');
const dependencyTypes = require('./dependency-types');
const readJson = require('./json').read;
const { getWorkspacesPaths } = require('./get-workspaces-paths');
Expand Down Expand Up @@ -46,7 +46,7 @@ function deleteOutOfRangePackages(_package, packages) {
for (let dependencyType of dependencyTypes) {
for (let packageName in _package[dependencyType]) {
let versionRange = _package[dependencyType][packageName];
if (semver.satisfies(packages[packageName].version, versionRange)) {
if (satisfies(packages[packageName].version, versionRange)) {
continue;
}

Expand Down
5 changes: 3 additions & 2 deletions src/build-release-graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const dependencyTypes = require('./dependency-types');
const { loadPackageConfig } = require('./config');
const debug = require('./debug');
const { createSyncLogger, createAsyncLogger } = require('./log');
const { satisfies } = require('./semver');

const defaultReleaseType = 'patch';

Expand Down Expand Up @@ -46,7 +47,7 @@ function isReleaseTypeLessThan(type1, type2) {
}

function isReleaseTypeInRange(version, type, range) {
return semver.satisfies(semver.inc(version, type), range);
return satisfies(semver.inc(version, type), range);
}

let shouldVersionBumpSymbol = Symbol('shouldVersionBump');
Expand Down Expand Up @@ -326,7 +327,7 @@ function fourthPass({

let newVersion = semver.inc(parent.oldVersion, parent.releaseType);

if (shouldBumpInRangeDependencies || !semver.satisfies(newVersion, newRange)) {
if (shouldBumpInRangeDependencies || !satisfies(newVersion, newRange)) {
newRange = trackNewVersion({
name,
oldRange,
Expand Down
36 changes: 29 additions & 7 deletions src/defrag.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ const dependencyTypes = require('./dependency-types');
const semverMinVersion = require('semver/ranges/min-version');
const semverGt = require('semver/functions/gt');
const semverSatisfies = require('semver/functions/satisfies');
const semverValidRange = require('semver/ranges/valid');
const {
isValidRange,
isWorkspaceProtocol,
extractRange,
isWorkspaceProtocolReplacementVersion,
} = require('./semver');
const semverMajor = require('semver/functions/major');
const semverMinor = require('semver/functions/minor');
const Range = require('semver/classes/range');
Expand Down Expand Up @@ -62,18 +67,25 @@ function filterRangeUpdates(allRanges, {
continue;
}

if (!semverValidRange(oldRange) || !semverValidRange(newRange)) {
if (!isValidRange(oldRange) || !isValidRange(newRange)) {
continue;
}

let oldSemverRange = extractRange(oldRange);
let newSemverRange = extractRange(newRange);

if (isWorkspaceProtocolReplacementVersion(oldSemverRange) || isWorkspaceProtocolReplacementVersion(newSemverRange)) {
continue;
}

// Assume ranges like "*" are monorepo links
// and should be ignored.
if (new Range(oldRange).range === '') {
if (new Range(oldSemverRange).range === '') {
continue;
}

let oldMinVersion = semverMinVersion(oldRange);
let newMinVersion = semverMinVersion(newRange);
let oldMinVersion = semverMinVersion(oldSemverRange);
let newMinVersion = semverMinVersion(newSemverRange);

let oldMajor = semverMajor(oldMinVersion).toString();
let oldMinor = semverMinor(oldMinVersion).toString();
Expand All @@ -82,7 +94,7 @@ function filterRangeUpdates(allRanges, {

switch (outOfRange) {
default:
isInRange = semverSatisfies(newMinVersion, oldRange);
isInRange = semverSatisfies(newMinVersion, oldSemverRange);
break;
case 'patch':
isInRange = semverSatisfies(newMinVersion, `${oldMajor}.${oldMinor}`);
Expand All @@ -101,7 +113,17 @@ function filterRangeUpdates(allRanges, {
rangeUpdates[packageName] = {};
}

rangeUpdates[packageName][oldRange] = newRange;
let updatedRange = newRange;

if (isWorkspaceProtocol(oldRange) !== isWorkspaceProtocol(newRange)) {
if (isWorkspaceProtocol(newRange)) {
updatedRange = newSemverRange;
} else {
updatedRange = `workspace:${newRange}`;
}
}

rangeUpdates[packageName][oldRange] = updatedRange;
}
}
}
Expand Down
19 changes: 15 additions & 4 deletions src/release.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,18 @@ async function release({

let commitMessage = `chore(release): ${tags.join()}`;

let isPnpm = false;
let isYarn = false;

if (await fsExists(path.join(workspaceCwd, 'pnpm-lock.yaml'))) {
await module.exports.updatePnpmLockfile({ cwd: workspaceCwd, silent, dryRun });
isPnpm = true;
} else if (await fsExists(path.join(workspaceCwd, 'yarn.lock'))) {
isYarn = true;
}

if (isPnpm) {
await module.exports.updatePnpmLockfile({ cwd: workspaceCwd, silent, dryRun });
} else if (isYarn) {
await module.exports.updateYarnLockfile({ cwd: workspaceCwd, silent, dryRun });
}

Expand Down Expand Up @@ -250,7 +259,7 @@ async function release({
if (shouldPublish && _shouldPublish) {
// eslint-disable-next-line no-inner-declarations
async function originalPublish() {
await publish({ cwd, silent, distTag, dryRun });
await publish({ cwd, silent, distTag, dryRun, isPnpm });
}

if (publishOverride) {
Expand All @@ -259,6 +268,7 @@ async function release({
originalPublish,
distTag,
dryRun,
isPnpm,
});
} else {
await originalPublish();
Expand Down Expand Up @@ -309,10 +319,11 @@ async function push({ cwd, silent, dryRun }) {
}
}

async function publish({ cwd, silent, distTag, dryRun }) {
async function publish({ cwd, silent, distTag, dryRun, isPnpm }) {
let command = isPnpm ? 'pnpm' : 'npm';
let dryRunArgs = dryRun ? ['--dry-run'] : [];

await execa('npm', ['publish', '--tag', distTag, ...dryRunArgs], { cwd, silent });
await execa(command, ['publish', '--tag', distTag, ...dryRunArgs], { cwd, silent });
}

async function updatePnpmLockfile({ cwd, silent, dryRun }) {
Expand Down
67 changes: 67 additions & 0 deletions src/semver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict';

const semver = require('semver');

/**
* @param {string} range
*/
function isWorkspaceProtocol(range) {
return range.startsWith('workspace:');
}

/**
* @param {string} range
*/
function extractRange(range) {
return range.replace(/^workspace:/, '');
}

/**
* @param {string} range
*/
function isWorkspaceProtocolReplacementVersion(range) {
if (range === '^' || range === '~') {
return true;
} else {
return false;
}
}

/**
* @param {string} version
* @param {string} range
*/
function satisfies(version, range) {
if (isWorkspaceProtocol(range)) {
range = extractRange(range);

if (isWorkspaceProtocolReplacementVersion(range)) {
return true;
}
}

return semver.satisfies(version, range);
}

/**
* @param {string} range
*/
function isValidRange(range) {
if (isWorkspaceProtocol(range)) {
range = extractRange(range);

if (isWorkspaceProtocolReplacementVersion(range)) {
return true;
}
}

return semver.validRange(range);
}

module.exports = {
isWorkspaceProtocol,
extractRange,
isWorkspaceProtocolReplacementVersion,
satisfies,
isValidRange,
};
26 changes: 24 additions & 2 deletions src/version.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
'use strict';

const semver = require('semver');
const {
isWorkspaceProtocol,
isWorkspaceProtocolReplacementVersion,
extractRange,
} = require('./semver');

function trackNewVersion({
name,
oldRange,
newRange,
oldRange: _oldRange,
newRange: _newRange,
newVersion,
}) {
let oldRange = _oldRange;
let newRange = _newRange;
let _isWorkspaceProtocol = isWorkspaceProtocol(_oldRange);

if (_isWorkspaceProtocol) {
oldRange = extractRange(_oldRange);
newRange = extractRange(_newRange);

if (isWorkspaceProtocolReplacementVersion(oldRange)) {
return _oldRange;
}
}

let range = new semver.Range(newRange);

if (range.set.length > 1) {
Expand Down Expand Up @@ -41,6 +59,10 @@ function trackNewVersion({
}
}

if (_isWorkspaceProtocol) {
newRange = `workspace:${newRange}`;
}

return newRange;
}

Expand Down
77 changes: 77 additions & 0 deletions test/defrag-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,83 @@ describe(function() {
expect(rangeUpdates).to.deep.equal({});
});

it('handles workspace protocol ranges', function() {
let allRanges = {
packageA: [
'workspace:^1.0.0',
'workspace:^1.0.1',
],
};

let rangeUpdates = filterRangeUpdates(allRanges);

expect(rangeUpdates).to.deep.equal({
packageA: {
'workspace:^1.0.0': 'workspace:^1.0.1',
},
});
});

it('ignores workspace wildcard ranges', function() {
let allRanges = {
packageA: [
'workspace:*',
'workspace:^1.0.1',
],
};

let rangeUpdates = filterRangeUpdates(allRanges);

expect(rangeUpdates).to.deep.equal({});
});

it('converts workspace protocols while preserving protocol type', function() {
let allRanges = {
packageA: [
'workspace:^1.0.0',
'^1.0.1',
],
};

let rangeUpdates = filterRangeUpdates(allRanges);

expect(rangeUpdates).to.deep.equal({
packageA: {
'workspace:^1.0.0': 'workspace:^1.0.1',
},
});
});

it('updates regular semver based on workspace protocol versions', function() {
let allRanges = {
packageA: [
'^1.0.0',
'workspace:^1.0.1',
],
};

let rangeUpdates = filterRangeUpdates(allRanges);

expect(rangeUpdates).to.deep.equal({
packageA: {
'^1.0.0': '^1.0.1',
},
});
});

it('ignores workspace protocol shortcuts', function() {
let allRanges = {
packageA: [
'workspace:^',
'^1.0.1',
],
};

let rangeUpdates = filterRangeUpdates(allRanges);

expect(rangeUpdates).to.deep.equal({});
});

it('can include out of range patches', function() {
let allRanges = {
packageA: [
Expand Down
Loading