Skip to content

Commit 24ecc3e

Browse files
authored
refactor!: rename factory.run -> call (googleapis#767)
BREAKING CHANGE: factory.run becomes factory.call
1 parent 95af2f4 commit 24ecc3e

File tree

6 files changed

+339
-112
lines changed

6 files changed

+339
-112
lines changed

.mocharc.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414
const config = {
15-
"enable-source-maps": true,
16-
"throw-deprecation": true,
17-
"timeout": 10000,
18-
"recursive": true
19-
}
15+
'enable-source-maps': true,
16+
'throw-deprecation': true,
17+
timeout: 10000,
18+
recursive: true,
19+
};
2020
if (process.env.MOCHA_THROW_DEPRECATION === 'false') {
2121
delete config['throw-deprecation'];
2222
}
@@ -26,4 +26,9 @@ if (process.env.MOCHA_REPORTER) {
2626
if (process.env.MOCHA_REPORTER_OUTPUT) {
2727
config['reporter-option'] = `output=${process.env.MOCHA_REPORTER_OUTPUT}`;
2828
}
29-
module.exports = config
29+
process.on('unhandledRejection', err => {
30+
console.error(err);
31+
process.exit(1);
32+
});
33+
34+
module.exports = config;

src/bin/release-please.ts

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,16 @@ export const parser = yargs
7171
releaseType(yargs, 'node');
7272
},
7373
(argv: ReleasePRFactoryOptions) => {
74-
const releasePR = factory.releasePR(argv);
75-
releasePR
76-
.latestTag()
74+
factory
75+
.runCommand('latest-tag', argv)
7776
.catch(handleError)
7877
.then(latestTag => {
79-
console.log(latestTag);
78+
if (latestTag) {
79+
console.log(latestTag);
80+
} else {
81+
console.log('No latest tag found.');
82+
process.exitCode = 1;
83+
}
8084
});
8185
}
8286
)
@@ -179,40 +183,56 @@ export const parser = yargs
179183
.demandCommand(1)
180184
.strict(true);
181185

182-
// Only run parser if executed with node bin, this allows
183-
// for the parser to be easily tested:
184-
let argv: yargs.Arguments;
185-
if (require.main === module) {
186-
argv = parser.parse();
186+
interface HandleError {
187+
(err: ErrorObject): void;
188+
logger?: Console;
189+
yargsArgs?: yargs.Arguments;
187190
}
188191

189192
// The errors returned by octokit currently contain the
190193
// request object, this contains information we don't want to
191194
// leak. For this reason, we capture exceptions and print
192195
// a less verbose error message (run with --debug to output
193196
// the request object, don't do this in CI/CD).
194-
function handleError(err: ErrorObject) {
197+
export const handleError: HandleError = (err: ErrorObject) => {
195198
let status = '';
196-
const command = argv?._?.length ? argv._[0] : '';
199+
if (handleError.yargsArgs === undefined) {
200+
throw new Error(
201+
'Set handleError.yargsArgs with a yargs.Arguments instance.'
202+
);
203+
}
204+
if (!handleError.logger) {
205+
handleError.logger = console;
206+
}
207+
const ya = handleError.yargsArgs;
208+
const logger = handleError.logger;
209+
const command = ya?._?.length ? ya._[0] : '';
197210
if (err.status) {
198211
status = '' + err.status;
199212
}
200-
console.error(
213+
logger.error(
201214
chalk.red(
202215
`command ${command} failed${status ? ` with status ${status}` : ''}`
203216
)
204217
);
205-
if (argv?.debug) {
206-
console.error('---------');
207-
console.error(err.stack);
218+
if (ya?.debug) {
219+
logger.error('---------');
220+
logger.error(err.stack);
208221
}
209222
process.exitCode = 1;
210-
}
223+
};
211224

212-
process.on('unhandledRejection', err => {
213-
handleError(err as ErrorObject);
214-
});
225+
// Only run parser if executed with node bin, this allows
226+
// for the parser to be easily tested:
227+
let argv: yargs.Arguments;
228+
if (require.main === module) {
229+
argv = parser.parse();
230+
handleError.yargsArgs = argv;
231+
process.on('unhandledRejection', err => {
232+
handleError(err as ErrorObject);
233+
});
215234

216-
process.on('uncaughtException', err => {
217-
handleError(err as ErrorObject);
218-
});
235+
process.on('uncaughtException', err => {
236+
handleError(err as ErrorObject);
237+
});
238+
}

src/factory.ts

Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
// and GitHub Releases:
1717

1818
import {ReleasePR} from './release-pr';
19-
import {GitHubRelease, ReleaseResponse} from './github-release';
19+
import {GitHubRelease, GitHubReleaseResponse} from './github-release';
2020
import {ReleaseType, getReleasers} from './releasers';
21-
import {GitHub} from './github';
21+
import {GitHub, GitHubTag} from './github';
2222
import {
2323
ReleasePRFactoryOptions,
2424
GitHubReleaseFactoryOptions,
@@ -28,26 +28,98 @@ import {DEFAULT_LABELS} from './constants';
2828
// eslint-disable-next-line @typescript-eslint/no-var-requires
2929
const parseGithubRepoUrl = require('parse-github-repo-url');
3030

31+
// types defining methods available to call on instances
32+
export type ReleasePRMethod = 'run' | 'latestTag';
33+
export type GitHubReleaseMethod = 'run';
34+
export type Method = ReleasePRMethod | GitHubReleaseMethod;
35+
36+
// types defining cli commands and their options
37+
export type ReleasePRCommands = 'release-pr' | 'latest-tag';
38+
export type GitHubReleaseCommands = 'github-release';
39+
type Command = ReleasePRCommands | GitHubReleaseCommands;
40+
type IsReleasePRCmd = {
41+
command: Command;
42+
options: ReleasePRFactoryOptions;
43+
};
44+
type IsGitHubReleaseCmd = {
45+
command: Command;
46+
options: GitHubReleaseFactoryOptions;
47+
};
48+
49+
// shorthand aliases for instance/method call return types
50+
export type ReleasePRRunResult = Promise<number | GitHubTag | undefined>;
51+
export type GitHubReleaseRunResult = Promise<GitHubReleaseResponse | undefined>;
52+
export type RunResult = ReleasePRRunResult | GitHubReleaseRunResult;
53+
54+
function isGitHubReleaseCmd(
55+
cmdOpts: IsReleasePRCmd | IsGitHubReleaseCmd
56+
): cmdOpts is IsGitHubReleaseCmd {
57+
const {command, options} = cmdOpts;
58+
return command === 'github-release' && typeof options === 'object';
59+
}
60+
61+
function isReleasePRCmd(
62+
cmdOpts: IsReleasePRCmd | IsGitHubReleaseCmd
63+
): cmdOpts is IsReleasePRCmd {
64+
const {command, options} = cmdOpts;
65+
return (
66+
(command === 'release-pr' || command === 'latest-tag') &&
67+
typeof options === 'object'
68+
);
69+
}
70+
3171
function runCommand(
32-
command: string,
72+
command: ReleasePRCommands,
73+
options: ReleasePRFactoryOptions
74+
): ReleasePRRunResult;
75+
function runCommand(
76+
command: GitHubReleaseCommands,
77+
options: GitHubReleaseFactoryOptions
78+
): GitHubReleaseRunResult;
79+
function runCommand(
80+
command: Command,
3381
options: GitHubReleaseFactoryOptions | ReleasePRFactoryOptions
34-
): Promise<number | undefined | ReleaseResponse> {
35-
if (isGitHubRelease(command, options)) {
36-
return factory.run(githubRelease(options));
82+
): RunResult {
83+
let result: RunResult;
84+
const cmdOpts = {command, options};
85+
if (isReleasePRCmd(cmdOpts)) {
86+
let method: ReleasePRMethod = 'run';
87+
if (command === 'latest-tag') {
88+
method = 'latestTag';
89+
}
90+
result = factory.call(releasePR(cmdOpts.options), method);
91+
} else if (isGitHubReleaseCmd({command, options})) {
92+
result = factory.call(githubRelease(cmdOpts.options), 'run');
3793
} else {
38-
return factory.run(releasePR(options));
94+
throw new Error(
95+
`Invalid command(${cmdOpts.command}) with options(${JSON.stringify(
96+
cmdOpts.options
97+
)})`
98+
);
3999
}
100+
return result;
40101
}
41102

42-
function isGitHubRelease(
43-
command: string,
44-
options: GitHubReleaseFactoryOptions | ReleasePRFactoryOptions
45-
): options is GitHubReleaseFactoryOptions {
46-
return command === 'github-release' && typeof options === 'object';
47-
}
48-
49-
function run(runnable: ReleasePR | GitHubRelease) {
50-
return runnable.run();
103+
function call(instance: ReleasePR, method: ReleasePRMethod): ReleasePRRunResult;
104+
function call(
105+
instance: GitHubRelease,
106+
method: GitHubReleaseMethod
107+
): GitHubReleaseRunResult;
108+
function call(instance: ReleasePR | GitHubRelease, method: Method): RunResult {
109+
if (!(method in instance)) {
110+
throw new Error(
111+
`No such method(${method}) on ${instance.constructor.name}`
112+
);
113+
}
114+
let result: RunResult;
115+
if (instance instanceof ReleasePR) {
116+
result = instance[method as ReleasePRMethod]();
117+
} else if (instance instanceof GitHubRelease) {
118+
result = instance[method as GitHubReleaseMethod]();
119+
} else {
120+
throw new Error('Unknown instance.');
121+
}
122+
return result;
51123
}
52124

53125
function getLabels(label?: string): string[] {
@@ -157,6 +229,6 @@ export const factory = {
157229
githubRelease,
158230
releasePR,
159231
releasePRClass,
160-
run,
232+
call,
161233
runCommand,
162234
};

src/github-release.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {ReleasePR} from './release-pr';
2121
// eslint-disable-next-line @typescript-eslint/no-var-requires
2222
const GITHUB_RELEASE_LABEL = 'autorelease: tagged';
2323

24-
export interface ReleaseResponse {
24+
export interface GitHubReleaseResponse {
2525
major: number;
2626
minor: number;
2727
patch: number;
@@ -48,7 +48,7 @@ export class GitHubRelease {
4848
this.releasePR = options.releasePR;
4949
}
5050

51-
async run(): Promise<ReleaseResponse | undefined> {
51+
async run(): Promise<GitHubReleaseResponse | undefined> {
5252
const candidate = await this.releasePR.buildRelease(this.changelogPath);
5353
if (!candidate) {
5454
checkpoint('Unable to build candidate', CheckpointType.Failure);

0 commit comments

Comments
 (0)