Skip to content

Commit

Permalink
feat: Command and "Runner" Pattern for release-please
Browse files Browse the repository at this point in the history
- Moves Yargs command parser to an isolated file (for reuse and testing).
- Updates command handlers to use a shared "runner" module.
- Adds `changelog-types` option
- Adds ability to configure the CLI tool using a JSON file (via '--config' flag)

The intent of the runner is to introduce a new entrypoint to this package that can be used by consumers to centralize execution and configuration parsing (and mapping).

see #511
  • Loading branch information
Joe Bottigliero authored and jbottigliero committed Oct 8, 2020
1 parent c61659b commit 961e54d
Show file tree
Hide file tree
Showing 8 changed files with 450 additions and 199 deletions.
18 changes: 18 additions & 0 deletions __snapshots__/runner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
exports['Runner release-pr allows customization of changelog sections 1'] = `
[
[
"CHANGELOG.md",
{
"content": "# Changelog\\n\\n### [1.0.1](https://www.github.com/googleapis/release-please/compare/v1.0.0...v1.0.1) (1983-10-10)\\n\\n\\n### Other\\n\\n* **deps:** update dependency com.google.cloud:google-cloud-spanner to v1.50.0 ([1f9663c](https://www.github.com/googleapis/release-please/commit/1f9663cf08ab1cf3b68d95dee4dc99b7c4aac373))\\n* **deps:** update dependency com.google.cloud:google-cloud-storage to v1.120.0 ([fcd1c89](https://www.github.com/googleapis/release-please/commit/fcd1c890dc1526f4d62ceedad561f498195c8939))\\n* update common templates ([3006009](https://www.github.com/googleapis/release-please/commit/3006009a2b1b2cb4bd5108c0f469c410759f3a6a))\\n",
"mode": "100644"
}
],
[
"package.json",
{
"content": "{\\n \\"name\\": \\"runner-package\\",\\n \\"version\\": \\"1.0.1\\"\\n}\\n",
"mode": "100644"
}
]
]
`
198 changes: 198 additions & 0 deletions src/bin/command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import chalk = require('chalk');
import {coerceOption} from '../util/coerce-option';
import {GitHubReleaseOptions} from '../github-release';
import {ReleasePROptions} from '../release-pr';
import {getReleaserNames} from '../releasers';
import main from '../runner';
import * as yargs from 'yargs';

export interface ErrorObject {
body?: object;
status?: number;
message: string;
stack: string;
}

interface YargsOptions {
describe: string;
choices?: string[];
demand?: boolean;
type?: string;
default?: string | boolean;
}

interface YargsOptionsBuilder {
option(opt: string, options: YargsOptions): YargsOptionsBuilder;
}

export default yargs
.config('config')
.command(
'release-pr',
'create or update a PR representing the next release',
(yargs: YargsOptionsBuilder) => {
yargs
.option('package-name', {
describe: 'name of package release is being minted for',
demand: true,
})
.option('changelog-types', {
describe:
'a JSON formatted string containing to override the outputted changelog sections',
})
.option('version-file', {
describe: 'path to version file to update, e.g., version.rb',
})
.option('last-package-version', {
describe: 'last version # that package was released as',
})
.option('repo-url', {
describe: 'GitHub URL to generate release for',
demand: true,
})
.option('fork', {
describe: 'should the PR be created from a fork',
type: 'boolean',
default: false,
})
.option('label', {
describe: 'label(s) to add to generated PR',
})
.option('snapshot', {
describe: 'is it a snapshot (or pre-release) being generated?',
type: 'boolean',
default: false,
})
.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,
});
},
async (argv: ReleasePROptions & yargs.Arguments) => {
await main(argv, 'release-pr').catch(e => handleError(e, argv));
}
)
.command(
'github-release',
'create a GitHub release from a release PR',
(yargs: YargsOptionsBuilder) => {
yargs
.option('package-name', {
describe: 'name of package release is being minted for',
})
.option('repo-url', {
describe: 'GitHub URL to generate release for',
demand: true,
})
.option('changelog-path', {
default: 'CHANGELOG.md',
describe: 'where can the CHANGELOG be found in the project?',
})
.option('label', {
default: 'autorelease: pending',
describe: 'label to remove from release PR',
})
.option('release-type', {
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',
});
},
async (argv: GitHubReleaseOptions & yargs.Arguments) => {
await main(argv, 'github-release').catch(e => handleError(e, argv));
}
)
.middleware(_argv => {
const argv = _argv as GitHubReleaseOptions;
// allow secrets to be loaded from file path
// rather than being passed directly to the bin.
if (argv.token) argv.token = coerceOption(argv.token);
if (argv.apiUrl) argv.apiUrl = coerceOption(argv.apiUrl);
if (argv.proxyKey) argv.proxyKey = coerceOption(argv.proxyKey);
})
.option('token', {describe: 'GitHub token with repo write permissions'})
.option('release-as', {
describe: 'override the semantically determined release version',
type: 'string',
})
.option('release-type', {
describe: 'what type of repo is a release being created for?',
choices: getReleaserNames(),
default: 'node',
})
.option('bump-minor-pre-major', {
describe:
'should we bump the semver minor prior to the first major release',
default: false,
type: 'boolean',
})
.option('api-url', {
describe: 'URL to use when making API requests',
default: 'https://api.github.com',
type: 'string',
})
.option('proxy-key', {
describe: 'key used by some GitHub proxies',
type: 'string',
})
.option('debug', {
describe: 'print verbose errors (use only for local debugging).',
default: false,
type: 'boolean',
})
.option('default-branch', {
describe: '',
type: 'string',
})
.demandCommand(1)
.strict(true);

// The errors returned by octokit currently contain the
// request object, this contains information we don't want to
// leak. For this reason, we capture exceptions and print
// a less verbose error message (run with --debug to output
// the request object, don't do this in CI/CD).
export function handleError(err: ErrorObject, argv: yargs.Arguments) {
let status = '';
const command = argv._.length === 0 ? '' : argv._[0];
if (err.status) {
status = '' + err.status;
}
console.error(
chalk.red(
`command ${command} failed${status ? ` with status ${status}` : ''}`
)
);
if (argv.debug) {
console.error('---------');
console.error(err.stack);
}
process.exitCode = 1;
}
Loading

0 comments on commit 961e54d

Please sign in to comment.