Skip to content
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

feat(manifest): add support for releasing root module #833

Merged
merged 10 commits into from
Mar 24, 2021
Merged
145 changes: 145 additions & 0 deletions __snapshots__/manifest.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,148 @@
exports['Manifest pullRequest allows root module to be published, via special "." path: changes'] = `

filename: node/pkg1/CHANGELOG.md
# Changelog

## [4.0.0](https://github.com/fake/repo/compare/pkg1-v3.2.1...pkg1-v4.0.0) (1983-10-10)


### ⚠ BREAKING CHANGES

* **@node/pkg1:** major new feature

### Features

* **@node/pkg1:** major new feature ([e3ab0ab](https://github.com/fake/repo/commit/e3ab0abfd66e66324f685ceeececf35c))

filename: node/pkg1/package.json
{
"name": "@node/pkg1",
"version": "4.0.0"
}

filename: node/pkg2/CHANGELOG.md
# Changelog

## [2.0.0](https://github.com/fake/repo/compare/pkg2-v1.2.3...pkg2-v2.0.0) (1983-10-10)


### ⚠ BREAKING CHANGES

* **@node/pkg2:** major new feature

### Features

* **@node/pkg2:** major new feature ([72f962d](https://github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b))

filename: node/pkg2/package.json
{
"name": "@node/pkg2",
"version": "2.0.0"
}

filename: CHANGELOG.md
# Changelog

## [3.0.0](https://github.com/fake/repo/compare/googleapis-v2.0.0...googleapis-v3.0.0) (1983-10-10)


### ⚠ BREAKING CHANGES

* **@node/pkg1:** major new feature
* **@node/pkg2:** major new feature

### Features

* **@node/pkg1:** major new feature ([e3ab0ab](https://github.com/fake/repo/commit/e3ab0abfd66e66324f685ceeececf35c))
* **@node/pkg2:** major new feature ([72f962d](https://github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b))


### Bug Fixes

* **root:** root only change ([8b55db3](https://github.com/fake/repo/commit/8b55db3f6115306cc9c132bec0bb1447))

filename: package.json
{
"name": "googleapis",
"version": "3.0.0"
}

filename: .release-please-manifest.json
{
".": "3.0.0",
"node/pkg1": "4.0.0",
"node/pkg2": "2.0.0"
}

`

exports['Manifest pullRequest allows root module to be published, via special "." path: options'] = `

upstreamOwner: fake
upstreamRepo: repo
title: chore: release
branch: release-please/branches/main
description: :robot: I have created a release \\*beep\\* \\*boop\\*

---
@node/pkg1: 4.0.0
## [4.0.0](https://github.com/fake/repo/compare/pkg1-v3.2.1...pkg1-v4.0.0) (1983-10-10)


### ⚠ BREAKING CHANGES

* **@node/pkg1:** major new feature

### Features

* **@node/pkg1:** major new feature ([e3ab0ab](https://github.com/fake/repo/commit/e3ab0abfd66e66324f685ceeececf35c))
---


---
@node/pkg2: 2.0.0
## [2.0.0](https://github.com/fake/repo/compare/pkg2-v1.2.3...pkg2-v2.0.0) (1983-10-10)


### ⚠ BREAKING CHANGES

* **@node/pkg2:** major new feature

### Features

* **@node/pkg2:** major new feature ([72f962d](https://github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b))
---


---
googleapis: 3.0.0
## [3.0.0](https://github.com/fake/repo/compare/googleapis-v2.0.0...googleapis-v3.0.0) (1983-10-10)


### ⚠ BREAKING CHANGES

* **@node/pkg1:** major new feature
* **@node/pkg2:** major new feature

### Features

* **@node/pkg1:** major new feature ([e3ab0ab](https://github.com/fake/repo/commit/e3ab0abfd66e66324f685ceeececf35c))
* **@node/pkg2:** major new feature ([72f962d](https://github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b))


### Bug Fixes

* **root:** root only change ([8b55db3](https://github.com/fake/repo/commit/8b55db3f6115306cc9c132bec0bb1447))
---


This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
primary: main
force: true
fork: false
message: chore: release
`

exports['Manifest pullRequest boostraps from HEAD manifest if first PR: changes'] = `

filename: node/pkg1/CHANGELOG.md
Expand Down
12 changes: 12 additions & 0 deletions docs/manifest-releaser.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,15 @@ PRs merge w/out running it). If successful it will remove the
`"autorelease: pending"` label and adds the `"autorelease: tagged"` label.
Creating all the releases is not transactional. If any fail to create the
command can be re-run safely to finish creating releases.

### Releasing Root Path of Library (".")

One use-case that arose for [googleapis](https://github.com/googleapis/google-api-nodejs-client), was the need to publish individual libraries along
with a combined version of the library, i.e.,

* an individual library for `@googleapis/youtube`, `@googleapis/sheets`, etc.
* a root library that combined all these API surfaces.

This functionality can be achieved by using the special `"."` path.
`"."` indicates a release should be created when any changes are made to the
codebase.
8 changes: 5 additions & 3 deletions src/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ export class Manifest {
}

protected async getPackagesToRelease(
commits: Commit[],
allCommits: Commit[],
sha?: string
): Promise<PackageReleaseData[]> {
const packages = (await this.getConfigJson()).parsedPackages;
Expand All @@ -288,12 +288,14 @@ export class Manifest {
includeEmpty: true,
packagePaths: packages.map(p => p.path),
});
const commitsPerPath = cs.split(commits);
const commitsPerPath = cs.split(allCommits);
const packagesToRelease: Record<string, PackageReleaseData> = {};
const missingVersionPaths = [];
const defaultBranch = await this.gh.getDefaultBranch();
for (const pkg of packages) {
const commits = commitsPerPath[pkg.path];
// The special path of '.' indicates the root module is being released
// in this case, use the entire list of commits:
const commits = pkg.path === '.' ? allCommits : commitsPerPath[pkg.path];
if (!commits || commits.length === 0) {
continue;
}
Expand Down
4 changes: 3 additions & 1 deletion src/release-pr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ export class ReleasePR {
constructor(options: ReleasePRConstructorOptions) {
this.bumpMinorPreMajor = options.bumpMinorPreMajor || false;
this.labels = options.labels ?? DEFAULT_LABELS;
this.path = options.path;
// undefined represents the root path of the library, if the special
// '.' path is provided, simply ignore it:
this.path = options.path !== '.' ? options.path : undefined;
this.packageName = options.packageName || '';
this.monorepoTags = options.monorepoTags || false;
this.releaseAs = options.releaseAs;
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/manifest/repo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "googleapis",
"version": "3.3.3"
}
155 changes: 155 additions & 0 deletions test/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ describe('Manifest', () => {
'node/pkg2/CHANGELOG.md',
'python/CHANGELOG.md',
'python/HISTORY.md',
'package-lock.json',
'samples/package.json',
'CHANGELOG.md',
];
for (const notFound of expectedNotFound) {
mock
Expand Down Expand Up @@ -283,6 +286,78 @@ describe('Manifest', () => {
]);
});

it('allows root module to be published, via special "." path', async function () {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, I think we should add a test under the describe('githubRelease' section. I'd be curious to see what the tag creation looks like for the root package.

also maybe a note somewhere in docs/manifest-releaser.md about this root pkg ability?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

const manifest = JSON.stringify({
'node/pkg1': '3.2.1',
'node/pkg2': '1.2.3',
'.': '2.0.0',
});
const config = JSON.stringify({
packages: {
'node/pkg1': {},
'node/pkg2': {},
'.': {},
},
});
const commits = [
buildMockCommit('feat(@node/pkg1)!: major new feature', [
'node/pkg1/src/foo.ts',
]),
buildMockCommit('feat(@node/pkg2)!: major new feature', [
'node/pkg2/src/bar.ts',
]),
buildMockCommit('fix(root): root only change', ['src/foo.ts']),
];

const github = new GitHub({
owner: 'fake',
repo: 'repo',
defaultBranch,
});
const mock = mockGithub(github);
expectManifest(mock, {manifest, lastReleaseSha});
expectPR(mock, {lastReleaseSha});
expectCommitsSinceSha(mock, {commits, lastReleaseSha});
expectGetFiles(mock, {
fixtureFiles: [
'node/pkg1/package.json',
'node/pkg2/package.json',
'package.json',
],
inlineFiles: [
['release-please-config.json', config],
['.release-please-manifest.json', manifest],
],
});
expectLabelAndComment(mock, {addLabel});
stubSuggesterWithSnapshot(sandbox, this.test!.fullTitle());
const logs: [string, CheckpointType][] = [];
const checkpoint = (msg: string, type: CheckpointType) =>
logs.push([msg, type]);

const pr = await new Manifest({github, checkpoint}).pullRequest();

mock.verify();
expect(pr).to.equal(22);
expect(logs).to.eql([
[
'Found version 3.2.1 for node/pkg1 in .release-please-manifest.json at abc123 of main',
CheckpointType.Success,
],
[
'Found version 1.2.3 for node/pkg2 in .release-please-manifest.json at abc123 of main',
CheckpointType.Success,
],
[
'Found version 2.0.0 for . in .release-please-manifest.json at abc123 of main',
CheckpointType.Success,
],
['Processing package: Node(@node/pkg1)', CheckpointType.Success],
['Processing package: Node(@node/pkg2)', CheckpointType.Success],
['Processing package: Node(googleapis)', CheckpointType.Success],
]);
});

it('respects python releaser specific config over defaults', async function () {
// https://github.com/googleapis/release-please/pull/790#issuecomment-783792069
if (process.versions.node.split('.')[0] === '10') {
Expand Down Expand Up @@ -1750,6 +1825,86 @@ describe('Manifest', () => {
],
]);
});

it('releases library in root (".")', async () => {
const manifest = JSON.stringify({
'.': '3.2.1',
});
const config = JSON.stringify({
packages: {
'.': {},
},
});

const github = new GitHub({
owner: 'fake',
repo: 'repo',
defaultBranch,
});
const mock = mockGithub(github);
expectManifest(mock, {manifest, lastReleaseSha});
expectPR(mock, {
lastReleaseSha,
mergedPRFiles: [
// lack of any "node/pkg2/ files indicates that package did not
// change in the last merged PR.
'package.json',
'CHANGELOG.md',
],
});
expectGetFiles(mock, {
fixtureFiles: ['package.json'],
inlineFiles: [
['release-please-config.json', config],
['.release-please-manifest.json', manifest],
['CHANGELOG.md', '#Changelog\n\n## v3.2.1\n\n* entry'],
],
});
expectLabelAndComment(mock, {
addLabel: 'autorelease: tagged',
removeLabel: 'autorelease: pending',
prComments: [
':robot: Release for googleapis is at https://[email protected]:html :sunflower:',
],
});
mock
.expects('createRelease')
.withArgs(
'googleapis',
'googleapis-v3.2.1',
lastReleaseSha,
sinon.match.string,
false
)
.once()
.resolves({
name: 'googleapis googleapis-v3.2.1',
tag_name: 'googleapis-v3.2.1',
draft: false,
body: '',
html_url: 'https://[email protected]:html',
upload_url: 'https://[email protected]:upload',
});

const releases = await new Manifest({github}).githubRelease();
mock.verify();
expect(releases).to.eql({
'.': {
version: '3.2.1',
major: 3,
minor: 2,
patch: 1,
pr: 22,
draft: false,
body: '',
sha: 'abc123',
html_url: 'https://[email protected]:html',
tag_name: 'googleapis-v3.2.1',
name: 'googleapis googleapis-v3.2.1',
upload_url: 'https://[email protected]:upload',
},
});
});
});

describe('validate', () => {
Expand Down