Skip to content

Commit

Permalink
fix: fallback to look at releases when looking for latest release (#1146
Browse files Browse the repository at this point in the history
)
  • Loading branch information
chingor13 committed Dec 21, 2021
1 parent cb9b772 commit 76ed1a7
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 1 deletion.
36 changes: 35 additions & 1 deletion src/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ export class Manifest {
let latestRelease = releasesByPath[path];
if (
!latestRelease &&
this.releasedVersions[path] &&
this.releasedVersions[path].toString() !== '0.0.0'
) {
const version = this.releasedVersions[path];
Expand Down Expand Up @@ -937,11 +938,16 @@ async function latestReleaseVersion(
`Looking for latest release on branch: ${targetBranch} with prefix: ${prefix}`
);

// collect set of recent commit SHAs seen to verify that the release
// is in the current branch
const commitShas = new Set<string>();

// only look at the last 250 or so commits to find the latest tag - we
// don't want to scan the entire repository history if this repo has never
// been released
const generator = github.mergeCommitIterator(targetBranch, 250);
for await (const commitWithPullRequest of generator) {
commitShas.add(commitWithPullRequest.sha);
const mergedPullRequest = commitWithPullRequest.pullRequest;
if (!mergedPullRequest) {
continue;
Expand Down Expand Up @@ -974,7 +980,35 @@ async function latestReleaseVersion(

return version;
}
return;

// If not found from recent pull requests, look at releases. Iterate
// through releases finding valid tags, then cross reference
const releaseGenerator = github.releaseIterator();
const candidateReleaseVersions: Version[] = [];
for await (const release of releaseGenerator) {
const tagName = TagName.parse(release.tagName);
if (!tagName) {
continue;
}

if (tagName.component === prefix) {
logger.debug(`found release for ${prefix}`, tagName.version);
if (!commitShas.has(release.sha)) {
logger.debug(
`SHA not found in recent commits to branch ${targetBranch}, skipping`
);
continue;
}
candidateReleaseVersions.push(tagName.version);
}
}
logger.debug(
`found ${candidateReleaseVersions.length} possible releases.`,
candidateReleaseVersions
);

// Find largest release number (sort descending then return first)
return candidateReleaseVersions.sort((a, b) => b.compare(a))[0];
}

function mergeReleaserConfig(
Expand Down
28 changes: 28 additions & 0 deletions src/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import * as semver from 'semver';

const VERSION_REGEX =
/(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(-(?<preRelease>[^+]+))?(\+(?<build>.*))?/;

/**
* This data class is used to represent a SemVer version.
*/
export class Version {
major: number;
minor: number;
Expand All @@ -36,6 +41,13 @@ export class Version {
this.build = build;
}

/**
* Parse a version string into a data class.
*
* @param {string} versionString the input version string
* @returns {Version} the parsed version
* @throws {Error} if the version string cannot be parsed
*/
static parse(versionString: string): Version {
const match = versionString.match(VERSION_REGEX);
if (!match?.groups) {
Expand All @@ -49,6 +61,22 @@ export class Version {
return new Version(major, minor, patch, preRelease, build);
}

/**
* Comparator to other Versions to be used in sorting.
*
* @param {Version} other The other version to compare to
* @returns {number} -1 if this version is earlier, 0 if the versions
* are the same, or 1 otherwise.
*/
compare(other: Version): -1 | 0 | 1 {
return semver.compare(this.toString(), other.toString());
}

/**
* Returns a normalized string version of this version.
*
* @returns {string}
*/
toString(): string {
const preReleasePart = this.preRelease ? `-${this.preRelease}` : '';
const buildPart = this.build ? `+${this.build}` : '';
Expand Down
137 changes: 137 additions & 0 deletions test/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,143 @@ describe('Manifest', () => {
expect(Object.keys(manifest.repositoryConfig)).lengthOf(1);
expect(Object.keys(manifest.releasedVersions)).lengthOf(1);
});
it('finds manually tagged release', async () => {
mockCommits(github, [
{
sha: 'abc123',
message: 'some commit message',
files: [],
pullRequest: {
headBranchName: 'release-please/branches/main/components/foobar',
baseBranchName: 'main',
number: 123,
title: 'chore: release foobar 1.2.3',
body: '',
labels: [],
files: [],
},
},
]);
mockReleases(github, [
{
tagName: 'other-v3.3.3',
sha: 'abc123',
url: 'http://path/to/release',
},
]);

const manifest = await Manifest.fromConfig(github, 'target-branch', {
releaseType: 'simple',
bumpMinorPreMajor: true,
bumpPatchForMinorPreMajor: true,
component: 'other',
includeComponentInTag: true,
});
expect(Object.keys(manifest.repositoryConfig)).lengthOf(1);
expect(
Object.keys(manifest.releasedVersions),
'found release versions'
).lengthOf(1);
expect(Object.values(manifest.releasedVersions)[0].toString()).to.eql(
'3.3.3'
);
});
it('ignores manually tagged release if commit not found', async () => {
mockCommits(github, [
{
sha: 'abc123',
message: 'some commit message',
files: [],
pullRequest: {
headBranchName: 'release-please/branches/main/components/foobar',
baseBranchName: 'main',
number: 123,
title: 'chore: release foobar 1.2.3',
body: '',
labels: [],
files: [],
},
},
]);
mockReleases(github, [
{
tagName: 'other-v3.3.3',
sha: 'def234',
url: 'http://path/to/release',
},
]);

const manifest = await Manifest.fromConfig(github, 'target-branch', {
releaseType: 'simple',
bumpMinorPreMajor: true,
bumpPatchForMinorPreMajor: true,
component: 'other',
includeComponentInTag: true,
});
expect(Object.keys(manifest.repositoryConfig)).lengthOf(1);
expect(Object.keys(manifest.releasedVersions), 'found release versions')
.to.be.empty;
});
it('finds largest manually tagged release', async () => {
mockCommits(github, [
{
sha: 'abc123',
message: 'some commit message',
files: [],
pullRequest: {
headBranchName: 'release-please/branches/main/components/foobar',
baseBranchName: 'main',
number: 123,
title: 'chore: release foobar 1.2.3',
body: '',
labels: [],
files: [],
},
},
{
sha: 'def234',
message: 'some commit message',
files: [],
pullRequest: {
headBranchName: 'release-please/branches/main/components/foobar',
baseBranchName: 'main',
number: 123,
title: 'chore: release foobar 1.2.3',
body: '',
labels: [],
files: [],
},
},
]);
mockReleases(github, [
{
tagName: 'other-v3.3.3',
sha: 'abc123',
url: 'http://path/to/release',
},
{
tagName: 'other-v3.3.2',
sha: 'def234',
url: 'http://path/to/release',
},
]);

const manifest = await Manifest.fromConfig(github, 'target-branch', {
releaseType: 'simple',
bumpMinorPreMajor: true,
bumpPatchForMinorPreMajor: true,
component: 'other',
includeComponentInTag: true,
});
expect(Object.keys(manifest.repositoryConfig)).lengthOf(1);
expect(
Object.keys(manifest.releasedVersions),
'found release versions'
).lengthOf(1);
expect(Object.values(manifest.releasedVersions)[0].toString()).to.eql(
'3.3.3'
);
});
});

describe('buildPullRequests', () => {
Expand Down
21 changes: 21 additions & 0 deletions test/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,25 @@ describe('Version', () => {
expect(version.toString()).to.equal(input);
});
});
describe('compare', () => {
it('should handle pre-release versions', () => {
const comparison = Version.parse('1.2.3').compare(
Version.parse('1.2.3-alpha')
);
expect(comparison).to.eql(1);
});
it('should sort in ascending order using compare', () => {
const input = [
Version.parse('1.2.3'),
Version.parse('1.2.3-alpha'),
Version.parse('2.2.0'),
];
const output = input.sort((a, b) => a.compare(b));
expect(output.map(version => version.toString())).to.eql([
'1.2.3-alpha',
'1.2.3',
'2.2.0',
]);
});
});
});

0 comments on commit 76ed1a7

Please sign in to comment.