Skip to content

Commit

Permalink
feat(CLI): Allows configuration of changelogSections via CLI and prov…
Browse files Browse the repository at this point in the history
…ides option for using a configuration file for options.

- `changelog-sections` will now be parsed similar to the feature found in `release-please-action`
- Since this option is likely to be a bit unwieldy in CLI contexts, the CLI now accepts a `--config` option to supply options from a JSON configuration file.

- A `--no-operation/--no-op` flag has been added to allow short-circuiting of Yargs `.command` handlers to appease tests (`nock`)

see: googleapis#511
  • Loading branch information
Joe Bottigliero committed Oct 4, 2020
1 parent 70bcfa0 commit 1fb5e52
Show file tree
Hide file tree
Showing 5 changed files with 362 additions and 184 deletions.
18 changes: 18 additions & 0 deletions __snapshots__/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
exports['CLI release-pr supports custom changelogSections 1'] = `
[
[
"CHANGELOG.md",
{
"content": "# Changelog\\n\\n### [1.0.1](https://github.com/googleapis/release-please-cli/compare/v1.0.0...v1.0.1) (2020-10-04)\\n\\n\\n### Bug Fixes\\n\\n* **deps:** update dependency com.google.cloud:google-cloud-spanner to v1.50.0 ([1f9663c](https://github.com/googleapis/release-please-cli/commit/1f9663cf08ab1cf3b68d95dee4dc99b7c4aac373))\\n* **deps:** update dependency com.google.cloud:google-cloud-storage to v1.120.0 ([fcd1c89](https://github.com/googleapis/release-please-cli/commit/fcd1c890dc1526f4d62ceedad561f498195c8939))\\n\\n\\n### Miscellaneous Chores\\n\\n* update common templates ([3006009](https://github.com/googleapis/release-please-cli/commit/3006009a2b1b2cb4bd5108c0f469c410759f3a6a))\\n",
"mode": "100644"
}
],
[
"package.json",
{
"content": "{\\n \\"name\\": \\"simple-package\\",\\n \\"version\\": \\"1.0.1\\"\\n}\\n",
"mode": "100644"
}
]
]
`
192 changes: 192 additions & 0 deletions src/bin/command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import chalk = require('chalk');
import {coerceOption} from '../util/coerce-option';
import {GitHubRelease, GitHubReleaseOptions} from '../github-release';
import {ReleasePROptions} from '../release-pr';
import {ReleasePRFactory} from '../release-pr-factory';
import {getReleaserNames} from '../releasers';
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('changelog-sections', {
describe: 'a JSON formatted string used to override the outputted changelog sections'
})
.option('package-name', {
describe: 'name of package release is being minted for',
demand: true,
})
.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,
});
},
(argv: ReleasePROptions & yargs.Arguments) => {
if (argv.noOperation) return;
const rp = ReleasePRFactory.build(argv.releaseType, argv);
return rp.run().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',
});
},
(argv: GitHubReleaseOptions & yargs.Arguments) => {
const gr = new GitHubRelease(argv);
return gr.createRelease().catch((e) => handleError(e, argv));
}
)
.middleware((argv: (GitHubReleaseOptions | ReleasePROptions) & yargs.Arguments) => {
if (argv.changelogSections) argv.changelogSections = JSON.parse(argv.changelogSections as string);

// 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('no-operation', {
alias: 'no-op',
type: 'boolean',
default: false
})
.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 1fb5e52

Please sign in to comment.