Skip to content
This repository has been archived by the owner on May 21, 2021. It is now read-only.

Validate new version #24

Merged
merged 1 commit into from
May 14, 2021
Merged
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
25 changes: 25 additions & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7343,6 +7343,9 @@ var inc_default = /*#__PURE__*/__nccwpck_require__.n(inc);
// EXTERNAL MODULE: ./node_modules/semver/functions/diff.js
var diff = __nccwpck_require__(4297);
var diff_default = /*#__PURE__*/__nccwpck_require__.n(diff);
// EXTERNAL MODULE: ./node_modules/semver/functions/gt.js
var gt = __nccwpck_require__(4123);
var gt_default = /*#__PURE__*/__nccwpck_require__.n(gt);
// EXTERNAL MODULE: external "path"
var external_path_ = __nccwpck_require__(5622);
var external_path_default = /*#__PURE__*/__nccwpck_require__.n(external_path_);
Expand Down Expand Up @@ -8053,6 +8056,7 @@ function getManifestErrorMessagePrefix(invalidField, manifest, manifestDirPath)




/**
* Action entry function. Gets git tags, reads the work space root package.json,
* and updates the package(s) of the repository per the Action inputs.
Expand All @@ -8079,6 +8083,9 @@ async function performUpdate(actionInputs) {
newVersion = actionInputs.ReleaseVersion;
versionDiff = diff_default()(currentVersion, newVersion);
}
// Ensure that the new version is greater than the current version, and that
// there's no existing tag for it.
validateVersion(currentVersion, newVersion, tags);
if (FieldNames.Workspaces in rootManifest) {
console.log('Project appears to have workspaces. Applying monorepo workflow.');
await updateMonorepo(newVersion, versionDiff, validateMonorepoPackageManifest(rootManifest, WORKSPACE_ROOT), repositoryUrl, tags);
Expand Down Expand Up @@ -8136,6 +8143,24 @@ async function updateMonorepo(newVersion, versionDiff, rootManifest, repositoryU
await updatePackages(allPackages, updateSpecification);
await updatePackage({ dirPath: WORKSPACE_ROOT, manifest: rootManifest }, { ...updateSpecification, shouldUpdateChangelog: false });
}
/**
* Throws an error if the current version is equal to the new version, if a
* tag for the new version already exists, or if the new version is less than
* the current version.
*
* @param currentVersion - The most recently released version.
* @param newVersion - The new version to be released.
* @param tags - All tags reachable from the current git HEAD, as from "git
* tag --merged".
*/
function validateVersion(currentVersion, newVersion, tags) {
if (!gt_default()(newVersion, currentVersion)) {
throw new Error(`The new version "${newVersion}" is not greater than the current version "${currentVersion}".`);
}
if (tags.has(`v${newVersion}`)) {
throw new Error(`Tag "v${newVersion}" for new version "${newVersion}" already exists.`);
}
}
//# sourceMappingURL=update.js.map
;// CONCATENATED MODULE: ./lib/index.js

Expand Down
92 changes: 85 additions & 7 deletions src/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,7 @@ describe('performUpdate', () => {
getRepositoryHttpsUrlMock = jest
.spyOn(gitOperations, 'getRepositoryHttpsUrl')
.mockImplementationOnce(async () => mockRepoUrl);
getTagsMock = jest
.spyOn(gitOperations, 'getTags')
.mockImplementationOnce(async () => [
new Set(['1.0.0', '1.1.0']),
'1.1.0',
]);
getTagsMock = jest.spyOn(gitOperations, 'getTags');
consoleLogMock = jest
.spyOn(console, 'log')
.mockImplementation(() => undefined);
Expand All @@ -72,6 +67,11 @@ describe('performUpdate', () => {
const oldVersion = '1.1.0';
const newVersion = '2.0.0';

getTagsMock.mockImplementationOnce(async () => [
new Set(['v1.0.0', 'v1.1.0']),
'v1.1.0',
]);

getPackageManifestMock.mockImplementationOnce(async () => {
return {
name: packageName,
Expand Down Expand Up @@ -103,6 +103,11 @@ describe('performUpdate', () => {
const oldVersion = '1.1.0';
const newVersion = '2.0.0';

getTagsMock.mockImplementationOnce(async () => [
new Set(['v1.0.0', 'v1.1.0']),
'v1.1.0',
]);

getPackageManifestMock.mockImplementationOnce(async () => {
return {
name: packageName,
Expand Down Expand Up @@ -138,6 +143,11 @@ describe('performUpdate', () => {
const newVersion = '2.0.0';
const workspaces: readonly string[] = ['a', 'b', 'c'];

getTagsMock.mockImplementationOnce(async () => [
new Set(['v1.0.0', 'v1.1.0']),
'v1.1.0',
]);

getPackageManifestMock.mockImplementationOnce(async () => {
return {
name: rootManifestName,
Expand Down Expand Up @@ -171,7 +181,7 @@ describe('performUpdate', () => {
expect(getPackagesToUpdateMock).toHaveBeenCalledWith(
{ a: {}, b: {}, c: {} },
true,
new Set(['1.0.0', '1.1.0']),
new Set(['v1.0.0', 'v1.1.0']),
);

expect(packageOperations.updatePackages).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -209,4 +219,72 @@ describe('performUpdate', () => {
expect(setActionOutputMock).toHaveBeenCalledTimes(1);
expect(setActionOutputMock).toHaveBeenCalledWith('NEW_VERSION', newVersion);
});

it('throws if the new version is less than the current version', async () => {
const packageName = 'A';
const oldVersion = '1.1.0';
const newVersion = '1.0.0';

getTagsMock.mockImplementationOnce(async () => [
new Set(['v1.1.0']),
'v1.1.0',
]);

getPackageManifestMock.mockImplementationOnce(async () => {
return {
name: packageName,
version: oldVersion,
};
});

await expect(
performUpdate({ ReleaseType: null, ReleaseVersion: newVersion }),
).rejects.toThrow(/^The new version "1\.0\.0" is not greater than/u);
});

it('throws if the new version is equal to the current version', async () => {
const packageName = 'A';
const oldVersion = '1.1.0';
const newVersion = '1.1.0';

getTagsMock.mockImplementationOnce(async () => [
new Set(['v1.1.0']),
'v1.1.0',
]);

getPackageManifestMock.mockImplementationOnce(async () => {
return {
name: packageName,
version: oldVersion,
};
});

await expect(
performUpdate({ ReleaseType: null, ReleaseVersion: newVersion }),
).rejects.toThrow(/^The new version "1\.1\.0" is not greater than/u);
});

it('throws if there is already a tag for the new version', async () => {
const packageName = 'A';
const oldVersion = '1.1.0';
const newVersion = '2.0.0';

getTagsMock.mockImplementationOnce(async () => [
new Set(['v1.0.0', 'v1.1.0', 'v2.0.0']),
'v2.0.0',
]);

getPackageManifestMock.mockImplementationOnce(async () => {
return {
name: packageName,
version: oldVersion,
};
});

await expect(
performUpdate({ ReleaseType: null, ReleaseVersion: newVersion }),
).rejects.toThrow(
/^Tag "v2\.0\.0" for new version "2\.0\.0" already exists\.$/u,
);
});
});
32 changes: 32 additions & 0 deletions src/update.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { setOutput as setActionOutput } from '@actions/core';
import semverIncrement from 'semver/functions/inc';
import semverDiff from 'semver/functions/diff';
import semverGt from 'semver/functions/gt';
import type { ReleaseType as SemverReleaseType } from 'semver';

import { getRepositoryHttpsUrl, getTags } from './git-operations';
Expand Down Expand Up @@ -55,6 +56,10 @@ export async function performUpdate(actionInputs: ActionInputs): Promise<void> {
versionDiff = semverDiff(currentVersion, newVersion) as SemverReleaseType;
}

// Ensure that the new version is greater than the current version, and that
// there's no existing tag for it.
validateVersion(currentVersion, newVersion, tags);

if (FieldNames.Workspaces in rootManifest) {
console.log(
'Project appears to have workspaces. Applying monorepo workflow.',
Expand Down Expand Up @@ -151,3 +156,30 @@ async function updateMonorepo(
{ ...updateSpecification, shouldUpdateChangelog: false },
);
}

/**
* Throws an error if the current version is equal to the new version, if a
* tag for the new version already exists, or if the new version is less than
* the current version.
*
* @param currentVersion - The most recently released version.
* @param newVersion - The new version to be released.
* @param tags - All tags reachable from the current git HEAD, as from "git
* tag --merged".
*/
function validateVersion(
currentVersion: string,
newVersion: string,
tags: ReadonlySet<string>,
) {
if (!semverGt(newVersion, currentVersion)) {
throw new Error(
`The new version "${newVersion}" is not greater than the current version "${currentVersion}".`,
);
}
if (tags.has(`v${newVersion}`)) {
throw new Error(
`Tag "v${newVersion}" for new version "${newVersion}" already exists.`,
);
}
}