Skip to content

package rename changelog validation #157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
44 changes: 44 additions & 0 deletions src/changelog-config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import fs from 'fs';
import path from 'path';

import {
getOriginalLatestVersion,
getOriginalTagPrefix,
} from './changelog-config';

const packageJson = {
autoChangelog: {
packageRename: {
originalLastestVersion: '1.0.0',
originalTagPrefix: 'test-package',
},
},
};

describe('getOriginalLatestVersion', () => {
it('reads the original latest version from an package.json', () => {
jest.spyOn(path, 'resolve').mockReturnValue('/fakepath');
jest.spyOn(fs, 'readFileSync').mockReturnValue(JSON.stringify(packageJson));
expect(getOriginalLatestVersion()).toBe('1.0.0');
});

it('returns null when there is no org latest version in the package.json', () => {
jest.spyOn(path, 'resolve').mockReturnValue('/fakepath');
jest.spyOn(fs, 'readFileSync').mockReturnValue('{}');
expect(getOriginalLatestVersion()).toBeNull();
});
});

describe('getOriginalTagPrefix', () => {
it('reads the original tag prefix from an package.json', () => {
jest.spyOn(path, 'resolve').mockReturnValue('/fakepath');
jest.spyOn(fs, 'readFileSync').mockReturnValue(JSON.stringify(packageJson));
expect(getOriginalTagPrefix()).toBe('test-package');
});

it('returns null when there is no tag prefix in the package.json', () => {
jest.spyOn(path, 'resolve').mockReturnValue('/fakepath');
jest.spyOn(fs, 'readFileSync').mockReturnValue('{}');
expect(getOriginalTagPrefix()).toBeNull();
});
});
63 changes: 63 additions & 0 deletions src/changelog-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* eslint-disable node/no-process-env, node/no-sync */

import fs from 'fs';
import path from 'path';

type PackageJson = {
autoChangelog: {
packageRename: {
originalLastestVersion: string;
originalTagPrefix: string;
};
};
};

/**
* Returns the latest version of the original package in case of package renamed.
*
* @returns The original package latest version.
*/
export function getOriginalLatestVersion(): string | null {
// Set automatically by Yarn 3.x
const packageJsonPath = process.env.npm_package_json;
if (packageJsonPath) {
const packageJson = path.resolve(packageJsonPath);
const packageJsonContent = JSON.parse(
fs.readFileSync(packageJson, 'utf8'),
) as PackageJson;

if (
typeof packageJsonContent.autoChangelog?.packageRename
?.originalLastestVersion === 'string'
) {
return packageJsonContent.autoChangelog.packageRename
.originalLastestVersion;
}
}

return null;
}

/**
* Returns the original package tag prefix in case of package renamed.
*
* @returns The original package tag prefix.
*/
export function getOriginalTagPrefix(): string | null {
// Set automatically by Yarn 3.x
const packageJsonPath = process.env.npm_package_json;
if (packageJsonPath) {
const packageJson = path.resolve(packageJsonPath);
const packageJsonContent = JSON.parse(
fs.readFileSync(packageJson, 'utf8'),
) as PackageJson;
if (
typeof packageJsonContent.autoChangelog?.packageRename
?.originalTagPrefix === 'string'
) {
return packageJsonContent.autoChangelog.packageRename.originalTagPrefix;
}
}

return null;
}
59 changes: 49 additions & 10 deletions src/changelog.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import semver from 'semver';

import {
getOriginalLatestVersion,
getOriginalTagPrefix,
} from './changelog-config';
import {
ChangeCategory,
orderedChangeCategories,
Expand Down Expand Up @@ -181,7 +185,6 @@ function stringifyLinkReferenceDefinitions(
// A list of release versions in chronological order
const chronologicalVersions = releases.map(({ version }) => version);
const hasReleases = chronologicalVersions.length > 0;

// The "Unreleased" section represents all changes made since the *highest*
// release, not the most recent release. This is to accomodate patch releases
// of older versions that don't represent the latest set of changes.
Expand All @@ -192,35 +195,71 @@ function stringifyLinkReferenceDefinitions(
//
// If there have not been any releases yet, the repo URL is used directly as
// the link definition.
const orgLatestVersion = getOriginalLatestVersion();
const orgTagPrefix = getOriginalTagPrefix();
let tagPrefixToCompare = tagPrefix;
// if there is a package renamed and version and tag prefix set in package.json
// original package tag prefix will be considered for compare
// below if is for an example from changelog [Unreleased]: https://github.com/MetaMask/core/compare/[email protected]
if (
orgTagPrefix &&
orgLatestVersion &&
orgLatestVersion === latestSemverVersion
) {
tagPrefixToCompare = orgTagPrefix;
}
const unreleasedLinkReferenceDefinition = `[${unreleased}]: ${
hasReleases
? getCompareUrl(repoUrl, `${tagPrefix}${latestSemverVersion}`, 'HEAD')
? getCompareUrl(
repoUrl,
`${tagPrefixToCompare}${latestSemverVersion}`,
'HEAD',
)
: withTrailingSlash(repoUrl)
}`;

// The "previous" release that should be used for comparison is not always
// the most recent release chronologically. The _highest_ version that is
// lower than the current release is used as the previous release, so that
// patch releases on older releases can be accomodated.
// by default tag prefix from new package will be used
tagPrefixToCompare = tagPrefix;
const releaseLinkReferenceDefinitions = releases
.map(({ version }) => {
let diffUrl;
// once the version matches with original version, rest of the lines in changelog will be assumed as migrated tags
if (orgTagPrefix && orgLatestVersion === version) {
tagPrefixToCompare = orgTagPrefix;
}
if (version === chronologicalVersions[chronologicalVersions.length - 1]) {
diffUrl = getTagUrl(repoUrl, `${tagPrefix}${version}`);
diffUrl = getTagUrl(repoUrl, `${tagPrefixToCompare}${version}`);
} else {
const versionIndex = chronologicalVersions.indexOf(version);
const previousVersion = chronologicalVersions
.slice(versionIndex)
.find((releaseVersion: Version) => {
return semver.gt(version, releaseVersion);
});
diffUrl = previousVersion
? getCompareUrl(
repoUrl,
`${tagPrefix}${previousVersion}`,
`${tagPrefix}${version}`,
)
: getTagUrl(repoUrl, `${tagPrefix}${version}`);
// if there is a package renamed and version and tag prefix set in config
// this if condition will fix the validation for original package's first release from new/renamed package
// [6.0.0]: https://github.com/MetaMask/core/compare/[email protected]...@metamask/[email protected]
if (orgLatestVersion && orgLatestVersion === previousVersion) {
diffUrl = previousVersion
? getCompareUrl(
repoUrl,
`${orgTagPrefix as string}${previousVersion}`,
`${tagPrefixToCompare}${version}`,
)
: getTagUrl(repoUrl, `${tagPrefixToCompare}${version}`);
} else {
diffUrl = previousVersion
? getCompareUrl(
repoUrl,
`${tagPrefixToCompare}${previousVersion}`,
`${tagPrefixToCompare}${version}`,
)
: getTagUrl(repoUrl, `${tagPrefixToCompare}${version}`);
}
}
return `[${version}]: ${diffUrl}`;
})
Expand Down