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: add support for monorepos/releasing from alternate folders #501

Merged
merged 3 commits into from
Jul 27, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,12 @@ release-please release-pr --package-name=@google-cloud/firestore" \

| option | description |
|-------------------|---------------------------------------------------------|
| `--package-name` | is the name of the package to publish to publish to an upstream registry such as npm. |
| `--package-name` | is the name of the package to publish to publish to an upstream registry such as npm. |
| `--repo-url` | is the URL of the repository on GitHub. |
| `--token` | a token with write access to `--repo-url`. |
| `--default-branch`| branch to open pull release PR against (detected by default). |
| `--path` | create a release from a path other than the repository's root |
| `--monorepo-tags` | add prefix to tags and branches, allowing multiple libraries to be released from the same repository. |

### Creating a release on GitHub

Expand All @@ -165,6 +167,7 @@ release-please github-release --repo-url=googleapis/nodejs-firestore \
| `--package-name` | is the name of the package to publish to publish to an upstream registry such as npm. |
| `--repo-url` | is the URL of the repository on GitHub. |
| `--token` | a token with write access to `--repo-url`. |
| `--path` | create a release from a path other than the repository's root |

### Running as a GitHub App

Expand Down
86 changes: 70 additions & 16 deletions __snapshots__/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ exports['papckage-lock-json-node-with'] = `

`

exports['CHANGELOG-node-message-no-package-lock'] = `
exports['CHANGELOG-node-message-with-package-lock'] = `
chore: created CHANGELOG.md [ci skip]
`

exports['CHANGELOG-node-no-package-lock'] = `
exports['CHANGELOG-node-with-package-lock'] = `
# Changelog

### [0.123.5](https://www.github.com/googleapis/node-test-repo/compare/v0.123.4...v0.123.5)
Expand All @@ -26,11 +26,11 @@ exports['CHANGELOG-node-no-package-lock'] = `

`

exports['package-json-node-message-no-package-lock'] = `
exports['package-json-node-message-with-package-lock'] = `
chore: updated package.json
`

exports['package-json-node-no-package-lock'] = `
exports['package-json-node-with-package-lock'] = `
{
"name": "node-test-repo",
"version": "0.123.5",
Expand All @@ -41,11 +41,37 @@ exports['package-json-node-no-package-lock'] = `

`

exports['CHANGELOG-node-message-with-package-lock'] = `
exports['package-lock-json-node-message'] = `
chore: updated package-lock.json [ci skip]
`

exports['PR body-node-with-package-lock'] = `
:robot: I have created a release \\*beep\\* \\*boop\\*
---
### [0.123.5](https://www.github.com/googleapis/node-test-repo/compare/v0.123.4...v0.123.5)


### Bug Fixes

* **deps:** update dependency com.google.cloud:google-cloud-spanner to v1.50.0 ([1f9663c](https://www.github.com/googleapis/node-test-repo/commit/1f9663cf08ab1cf3b68d95dee4dc99b7c4aac373))
* **deps:** update dependency com.google.cloud:google-cloud-storage to v1.120.0 ([fcd1c89](https://www.github.com/googleapis/node-test-repo/commit/fcd1c890dc1526f4d62ceedad561f498195c8939))
---


This PR was generated with [Release Please](https://github.com/googleapis/release-please).
`

exports['labels-node-with-package-lock'] = {
'labels': [
'autorelease: pending'
]
}

exports['CHANGELOG-node-message-'] = `
chore: created CHANGELOG.md [ci skip]
`

exports['CHANGELOG-node-with-package-lock'] = `
exports['CHANGELOG-node-'] = `
# Changelog

### [0.123.5](https://www.github.com/googleapis/node-test-repo/compare/v0.123.4...v0.123.5)
Expand All @@ -58,11 +84,11 @@ exports['CHANGELOG-node-with-package-lock'] = `

`

exports['package-json-node-message-with-package-lock'] = `
exports['package-json-node-message-'] = `
chore: updated package.json
`

exports['package-json-node-with-package-lock'] = `
exports['package-json-node-'] = `
{
"name": "node-test-repo",
"version": "0.123.5",
Expand All @@ -73,11 +99,7 @@ exports['package-json-node-with-package-lock'] = `

`

exports['package-lock-json-node-message'] = `
chore: updated package-lock.json [ci skip]
`

exports['PR body-node-no-package-lock'] = `
exports['PR body-node-'] = `
:robot: I have created a release \\*beep\\* \\*boop\\*
---
### [0.123.5](https://www.github.com/googleapis/node-test-repo/compare/v0.123.4...v0.123.5)
Expand All @@ -93,13 +115,45 @@ exports['PR body-node-no-package-lock'] = `
This PR was generated with [Release Please](https://github.com/googleapis/release-please).
`

exports['labels-node-no-package-lock'] = {
exports['labels-node-'] = {
'labels': [
'autorelease: pending'
]
}

exports['PR body-node-with-package-lock'] = `
exports['CHANGELOG-node-message-with-path'] = `
chore: created packages/foo/CHANGELOG.md [ci skip]
`

exports['CHANGELOG-node-with-path'] = `
# Changelog

### [0.123.5](https://www.github.com/googleapis/node-test-repo/compare/v0.123.4...v0.123.5)


### Bug Fixes

* **deps:** update dependency com.google.cloud:google-cloud-spanner to v1.50.0 ([1f9663c](https://www.github.com/googleapis/node-test-repo/commit/1f9663cf08ab1cf3b68d95dee4dc99b7c4aac373))
* **deps:** update dependency com.google.cloud:google-cloud-storage to v1.120.0 ([fcd1c89](https://www.github.com/googleapis/node-test-repo/commit/fcd1c890dc1526f4d62ceedad561f498195c8939))

`

exports['package-json-node-message-with-path'] = `
chore: updated packages/foo/package.json
`

exports['package-json-node-with-path'] = `
{
"name": "node-test-repo",
"version": "0.123.5",
"repository": {
"url": "git@github.com:samples/node-test-repo.git"
}
}

`

exports['PR body-node-with-path'] = `
:robot: I have created a release \\*beep\\* \\*boop\\*
---
### [0.123.5](https://www.github.com/googleapis/node-test-repo/compare/v0.123.4...v0.123.5)
Expand All @@ -115,7 +169,7 @@ exports['PR body-node-with-package-lock'] = `
This PR was generated with [Release Please](https://github.com/googleapis/release-please).
`

exports['labels-node-with-package-lock'] = {
exports['labels-node-with-path'] = {
'labels': [
'autorelease: pending'
]
Expand Down
13 changes: 13 additions & 0 deletions src/bin/release-please.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ const argv = yargs
.option('default-branch', {
describe: 'default branch to open release PR against',
type: 'string',
})
.option('path', {
describe: 'release from path other than root directory',
type: 'string',
})
.option('monorepo-tags', {
describe: 'include library name in tags and release branches',
type: 'boolean',
default: false,
});
},
(argv: ReleasePROptions) => {
Expand Down Expand Up @@ -99,6 +108,10 @@ const argv = yargs
describe: 'what type of repo is a release being created for?',
choices: getReleaserNames(),
default: 'node',
})
.option('path', {
describe: 'release from path other than root directory',
type: 'string',
});
},
(argv: GitHubReleaseOptions) => {
Expand Down
18 changes: 16 additions & 2 deletions src/github-release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

import chalk = require('chalk');
import {join} from 'path';

import {checkpoint, CheckpointType} from './util/checkpoint';
import {ReleasePRFactory} from './release-pr-factory';
Expand All @@ -30,6 +31,7 @@ const GITHUB_RELEASE_LABEL = 'autorelease: tagged';
export interface GitHubReleaseOptions {
label: string;
repoUrl: string;
path?: string;
packageName?: string;
token?: string;
apiUrl: string;
Expand All @@ -44,6 +46,7 @@ export class GitHubRelease {
gh: GitHub;
labels: string[];
repoUrl: string;
path?: string;
packageName?: string;
token?: string;
proxyKey?: string;
Expand All @@ -55,6 +58,7 @@ export class GitHubRelease {
this.labels = options.label.split(',');
this.repoUrl = options.repoUrl;
this.token = options.token;
this.path = options.path;
this.packageName = options.packageName;
this.releaseType = options.releaseType;

Expand All @@ -76,11 +80,13 @@ export class GitHubRelease {
);

const changelogContents = (
await this.gh.getFileContents(this.changelogPath)
await this.gh.getFileContents(this.addPath(this.changelogPath))
).parsedContent;
console.info(changelogContents, gitHubReleasePR.version);
const latestReleaseNotes = GitHubRelease.extractLatestReleaseNotes(
changelogContents,
gitHubReleasePR.version
// For monorepo releases, the library name is prepended to the tag and branch:
gitHubReleasePR.version.split('-').pop() || gitHubReleasePR.version
);
checkpoint(
`found release notes: \n---\n${chalk.grey(latestReleaseNotes)}\n---\n`,
Expand Down Expand Up @@ -117,6 +123,14 @@ export class GitHubRelease {
}
}

addPath(file: string) {
if (this.path === undefined) {
return file;
} else {
return join(this.path, `./${file}`);
}
}

private gitHubInstance(octokitAPIs?: OctokitAPIs): GitHub {
const [owner, repo] = parseGithubRepoUrl(this.repoUrl);
return new GitHub({
Expand Down
15 changes: 10 additions & 5 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,8 @@ export class GitHub {
return refResponse.data.object.sha;
}

async latestTag(): Promise<GitHubTag | undefined> {
const tags: {[version: string]: GitHubTag} = await this.allTags();
async latestTag(prefix?: string): Promise<GitHubTag | undefined> {
const tags: {[version: string]: GitHubTag} = await this.allTags(prefix);
const versions = Object.keys(tags).filter(t => {
// remove any pre-releases from the list:
return !t.includes('-');
Expand Down Expand Up @@ -517,7 +517,9 @@ export class GitHub {
return openReleasePRs;
}

private async allTags(): Promise<{[version: string]: GitHubTag}> {
private async allTags(
prefix?: string
): Promise<{[version: string]: GitHubTag}> {
const tags: {[version: string]: GitHubTag} = {};
for await (const response of this.octokit.paginate.iterator(
this.decoratePaginateOpts({
Expand All @@ -528,8 +530,11 @@ export class GitHub {
})
)) {
response.data.forEach((data: ReposListTagsResponseItems) => {
const version = semver.valid(data.name);
if (version) {
// For monorepos, a prefix can be provided, indicating that only tags
// matching the prefix should be returned:
if (prefix && !data.name.startsWith(prefix)) return;
let version = data.name.replace(prefix, '');
if ((version = semver.valid(version))) {
tags[version] = {sha: data.commit.sha, name: data.name, version};
}
});
Expand Down