From 4a1a1eaefb1cabb541d5a90d316e9a3f4f55228e Mon Sep 17 00:00:00 2001 From: bcoe Date: Fri, 19 Mar 2021 17:16:22 -0700 Subject: [PATCH 1/9] feat(manifest): add support for releasing root module --- __snapshots__/manifest.js | 131 +++++++++++++++++++++++ src/manifest.ts | 4 +- src/release-pr.ts | 4 +- test/fixtures/manifest/repo/package.json | 4 + test/manifest.ts | 74 +++++++++++++ 5 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/manifest/repo/package.json diff --git a/__snapshots__/manifest.js b/__snapshots__/manifest.js index baf4bd7e9..ff14e0c38 100644 --- a/__snapshots__/manifest.js +++ b/__snapshots__/manifest.js @@ -1,3 +1,134 @@ +exports['Manifest pullRequest allows root module to be published, via special "." path: changes'] = ` + +filename: node/pkg1/CHANGELOG.md +# Changelog + +## [4.0.0](https://www.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://www.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://www.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://www.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://www.github.com/fake/repo/compare/googleapis-v2.0.0...googleapis-v3.0.0) (1983-10-10) + + +### ⚠ BREAKING CHANGES + +* **@node/pkg2:** major new feature + +### Features + +* **@node/pkg2:** major new feature ([72f962d](https://www.github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b)) + +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://www.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://www.github.com/fake/repo/commit/e3ab0abfd66e66324f685ceeececf35c)) +--- + + +--- +@node/pkg2: 2.0.0 +## [2.0.0](https://www.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://www.github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b)) +--- + + +--- +googleapis: 3.0.0 +## [3.0.0](https://www.github.com/fake/repo/compare/googleapis-v2.0.0...googleapis-v3.0.0) (1983-10-10) + + +### ⚠ BREAKING CHANGES + +* **@node/pkg2:** major new feature + +### Features + +* **@node/pkg2:** major new feature ([72f962d](https://www.github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b)) +--- + + +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 diff --git a/src/manifest.ts b/src/manifest.ts index 03d0ec272..c3a021cd1 100644 --- a/src/manifest.ts +++ b/src/manifest.ts @@ -293,7 +293,9 @@ export class Manifest { 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: + commits = pkg.path === '.' ? commits : commitsPerPath[pkg.path]; if (!commits || commits.length === 0) { continue; } diff --git a/src/release-pr.ts b/src/release-pr.ts index bc5e51246..373144309 100644 --- a/src/release-pr.ts +++ b/src/release-pr.ts @@ -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; diff --git a/test/fixtures/manifest/repo/package.json b/test/fixtures/manifest/repo/package.json new file mode 100644 index 000000000..931166036 --- /dev/null +++ b/test/fixtures/manifest/repo/package.json @@ -0,0 +1,4 @@ +{ + "name": "googleapis", + "version": "3.3.3" +} diff --git a/test/manifest.ts b/test/manifest.ts index 7c039b8e0..d6084bdf0 100644 --- a/test/manifest.ts +++ b/test/manifest.ts @@ -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 @@ -283,6 +286,77 @@ describe('Manifest', () => { ]); }); + it('allows root module to be published, via special "." path', async function () { + 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', + ]), + ]; + + 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') { From 474479883173cc0b1b4b61b1d145c3e78c792df4 Mon Sep 17 00:00:00 2001 From: bcoe Date: Mon, 22 Mar 2021 17:38:56 -0700 Subject: [PATCH 2/9] fix: address bug with CHANGELOG generation --- __snapshots__/manifest.js | 4 ++++ src/manifest.ts | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/__snapshots__/manifest.js b/__snapshots__/manifest.js index ff14e0c38..57deadcd8 100644 --- a/__snapshots__/manifest.js +++ b/__snapshots__/manifest.js @@ -48,10 +48,12 @@ filename: CHANGELOG.md ### ⚠ BREAKING CHANGES +* **@node/pkg1:** major new feature * **@node/pkg2:** major new feature ### Features +* **@node/pkg1:** major new feature ([e3ab0ab](https://www.github.com/fake/repo/commit/e3ab0abfd66e66324f685ceeececf35c)) * **@node/pkg2:** major new feature ([72f962d](https://www.github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b)) filename: package.json @@ -114,10 +116,12 @@ googleapis: 3.0.0 ### ⚠ BREAKING CHANGES +* **@node/pkg1:** major new feature * **@node/pkg2:** major new feature ### Features +* **@node/pkg1:** major new feature ([e3ab0ab](https://www.github.com/fake/repo/commit/e3ab0abfd66e66324f685ceeececf35c)) * **@node/pkg2:** major new feature ([72f962d](https://www.github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b)) --- diff --git a/src/manifest.ts b/src/manifest.ts index c3a021cd1..a76e71725 100644 --- a/src/manifest.ts +++ b/src/manifest.ts @@ -279,7 +279,7 @@ export class Manifest { } protected async getPackagesToRelease( - commits: Commit[], + allCommits: Commit[], sha?: string ): Promise { const packages = (await this.getConfigJson()).parsedPackages; @@ -288,14 +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 = {}; const missingVersionPaths = []; const defaultBranch = await this.gh.getDefaultBranch(); for (const pkg of packages) { // The special path of '.' indicates the root module is being released // in this case, use the entire list of commits: - commits = pkg.path === '.' ? commits : commitsPerPath[pkg.path]; + const commits = pkg.path === '.' ? allCommits : commitsPerPath[pkg.path]; if (!commits || commits.length === 0) { continue; } From 9d2e93a942f17d6ac51cb3221b54083a0931c6ec Mon Sep 17 00:00:00 2001 From: bcoe Date: Mon, 22 Mar 2021 17:44:55 -0700 Subject: [PATCH 3/9] test: add test case from code review --- __snapshots__/manifest.js | 10 ++++++++++ test/manifest.ts | 1 + 2 files changed, 11 insertions(+) diff --git a/__snapshots__/manifest.js b/__snapshots__/manifest.js index 57deadcd8..69195db56 100644 --- a/__snapshots__/manifest.js +++ b/__snapshots__/manifest.js @@ -56,6 +56,11 @@ filename: CHANGELOG.md * **@node/pkg1:** major new feature ([e3ab0ab](https://www.github.com/fake/repo/commit/e3ab0abfd66e66324f685ceeececf35c)) * **@node/pkg2:** major new feature ([72f962d](https://www.github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b)) + +### Bug Fixes + +* **root:** root only change ([8b55db3](https://www.github.com/fake/repo/commit/8b55db3f6115306cc9c132bec0bb1447)) + filename: package.json { "name": "googleapis", @@ -123,6 +128,11 @@ googleapis: 3.0.0 * **@node/pkg1:** major new feature ([e3ab0ab](https://www.github.com/fake/repo/commit/e3ab0abfd66e66324f685ceeececf35c)) * **@node/pkg2:** major new feature ([72f962d](https://www.github.com/fake/repo/commit/72f962d44ba0bcee15594ea6bdc67d8b)) + + +### Bug Fixes + +* **root:** root only change ([8b55db3](https://www.github.com/fake/repo/commit/8b55db3f6115306cc9c132bec0bb1447)) --- diff --git a/test/manifest.ts b/test/manifest.ts index d6084bdf0..981bbdc09 100644 --- a/test/manifest.ts +++ b/test/manifest.ts @@ -306,6 +306,7 @@ describe('Manifest', () => { 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({ From 3273eaf0ee41140a1f17f50c37ac1b60bf8f1500 Mon Sep 17 00:00:00 2001 From: bcoe Date: Mon, 22 Mar 2021 18:01:46 -0700 Subject: [PATCH 4/9] test: added test for creating a release --- test/manifest.ts | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/test/manifest.ts b/test/manifest.ts index 981bbdc09..7fe12c05f 100644 --- a/test/manifest.ts +++ b/test/manifest.ts @@ -1825,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://pkg1@3.2.1: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://pkg1@3.2.1:html', + upload_url: 'https://pkg1@3.2.1: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://pkg1@3.2.1:html', + tag_name: 'googleapis-v3.2.1', + name: 'googleapis googleapis-v3.2.1', + upload_url: 'https://pkg1@3.2.1:upload', + }, + }); + }); }); describe('validate', () => { From 1d1f232159f95f0ccfeee0e10b951130f13d9dd2 Mon Sep 17 00:00:00 2001 From: bcoe Date: Mon, 22 Mar 2021 18:11:01 -0700 Subject: [PATCH 5/9] docs: add blurb about root level releases --- docs/manifest-releaser.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/manifest-releaser.md b/docs/manifest-releaser.md index aff59ae83..17272451a 100644 --- a/docs/manifest-releaser.md +++ b/docs/manifest-releaser.md @@ -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. From 262865afe66c9d76f00d86d2ac33bc64465f9198 Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Wed, 24 Mar 2021 08:26:08 -0700 Subject: [PATCH 6/9] Update test/manifest.ts Co-authored-by: Joel Dodge --- test/manifest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/manifest.ts b/test/manifest.ts index 7fe12c05f..73849e4f9 100644 --- a/test/manifest.ts +++ b/test/manifest.ts @@ -1864,7 +1864,7 @@ describe('Manifest', () => { addLabel: 'autorelease: tagged', removeLabel: 'autorelease: pending', prComments: [ - ':robot: Release for googleapis is at https://pkg1@3.2.1:html :sunflower:', + ':robot: Release for googleapis is at https://googleapis@3.2.1:html :sunflower:', ], }); mock From 9effd3a02bca8144fc30d30aed116385b997dc8c Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Wed, 24 Mar 2021 08:26:27 -0700 Subject: [PATCH 7/9] Update test/manifest.ts Co-authored-by: Joel Dodge --- test/manifest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/manifest.ts b/test/manifest.ts index 73849e4f9..fae6bff01 100644 --- a/test/manifest.ts +++ b/test/manifest.ts @@ -1882,8 +1882,8 @@ describe('Manifest', () => { tag_name: 'googleapis-v3.2.1', draft: false, body: '', - html_url: 'https://pkg1@3.2.1:html', - upload_url: 'https://pkg1@3.2.1:upload', + html_url: 'https://googleapis@3.2.1:html', + upload_url: 'https://googleapis@3.2.1:upload', }); const releases = await new Manifest({github}).githubRelease(); From 938959d0a3b26cb59f5f60b58f5ac898f5324e3d Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Wed, 24 Mar 2021 08:26:35 -0700 Subject: [PATCH 8/9] Update test/manifest.ts Co-authored-by: Joel Dodge --- test/manifest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/manifest.ts b/test/manifest.ts index fae6bff01..56652b15a 100644 --- a/test/manifest.ts +++ b/test/manifest.ts @@ -1901,7 +1901,7 @@ describe('Manifest', () => { html_url: 'https://pkg1@3.2.1:html', tag_name: 'googleapis-v3.2.1', name: 'googleapis googleapis-v3.2.1', - upload_url: 'https://pkg1@3.2.1:upload', + upload_url: 'https://googleapis@3.2.1:upload', }, }); }); From 6ed91142f56b38f50420e991658a1ec074b96ed3 Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Wed, 24 Mar 2021 08:26:45 -0700 Subject: [PATCH 9/9] Update test/manifest.ts Co-authored-by: Joel Dodge --- test/manifest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/manifest.ts b/test/manifest.ts index 56652b15a..0de8b81f9 100644 --- a/test/manifest.ts +++ b/test/manifest.ts @@ -1898,7 +1898,7 @@ describe('Manifest', () => { draft: false, body: '', sha: 'abc123', - html_url: 'https://pkg1@3.2.1:html', + html_url: 'https://googleapis@3.2.1:html', tag_name: 'googleapis-v3.2.1', name: 'googleapis googleapis-v3.2.1', upload_url: 'https://googleapis@3.2.1:upload',