1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.getAutoVersion = exports.determineNextVersion = void 0;
|
4 | const tslib_1 = require("tslib");
|
5 | const dotenv_1 = tslib_1.__importDefault(require("dotenv"));
|
6 | const env_ci_1 = tslib_1.__importDefault(require("env-ci"));
|
7 | const fs_1 = tslib_1.__importDefault(require("fs"));
|
8 | const path_1 = tslib_1.__importDefault(require("path"));
|
9 | const terminal_link_1 = tslib_1.__importDefault(require("terminal-link"));
|
10 | const log_symbols_1 = tslib_1.__importDefault(require("log-symbols"));
|
11 | const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
12 | const semver_1 = require("semver");
|
13 | const endent_1 = tslib_1.__importDefault(require("endent"));
|
14 | const url_1 = require("url");
|
15 | const await_to_js_1 = tslib_1.__importDefault(require("await-to-js"));
|
16 | const https_proxy_agent_1 = tslib_1.__importDefault(require("https-proxy-agent"));
|
17 | const semver_2 = require("./semver");
|
18 | const config_1 = tslib_1.__importDefault(require("./config"));
|
19 | const git_1 = tslib_1.__importDefault(require("./git"));
|
20 | const init_1 = tslib_1.__importDefault(require("./init"));
|
21 | const release_1 = tslib_1.__importStar(require("./release"));
|
22 | const semver_3 = tslib_1.__importStar(require("./semver"));
|
23 | const exec_promise_1 = tslib_1.__importDefault(require("./utils/exec-promise"));
|
24 | const load_plugins_1 = require("./utils/load-plugins");
|
25 | const logger_1 = tslib_1.__importStar(require("./utils/logger"));
|
26 | const make_hooks_1 = require("./utils/make-hooks");
|
27 | const get_current_branch_1 = require("./utils/get-current-branch");
|
28 | const match_sha_to_pr_1 = require("./match-sha-to-pr");
|
29 | const get_repository_1 = tslib_1.__importDefault(require("./utils/get-repository"));
|
30 | const validate_config_1 = require("./validate-config");
|
31 | const omit_1 = require("./utils/omit");
|
32 | const child_process_1 = require("child_process");
|
33 | const is_binary_1 = tslib_1.__importDefault(require("./utils/is-binary"));
|
34 | const git_reset_1 = require("./utils/git-reset");
|
35 | const proxyUrl = process.env.https_proxy || process.env.http_proxy;
|
36 | const env = env_ci_1.default();
|
37 |
|
38 | const makeDetail = (summary, body) => endent_1.default `
|
39 | <details>
|
40 | <summary>${summary}</summary>
|
41 | <br />
|
42 |
|
43 | ${body}
|
44 | </details>
|
45 | `;
|
46 |
|
47 | const loadEnv = () => {
|
48 | const envFile = path_1.default.resolve(process.cwd(), ".env");
|
49 | if (!fs_1.default.existsSync(envFile)) {
|
50 | return;
|
51 | }
|
52 | const envConfig = dotenv_1.default.parse(fs_1.default.readFileSync(envFile));
|
53 | Object.entries(envConfig).forEach(([key, value]) => {
|
54 | process.env[key] = value;
|
55 | });
|
56 | };
|
57 |
|
58 | function getPrNumberFromEnv(pr) {
|
59 | const envPr = "pr" in env && Number(env.pr);
|
60 | const prNumber = pr || envPr;
|
61 | return prNumber;
|
62 | }
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 | function determineNextVersion(lastVersion, currentVersion, bump, tag) {
|
72 | const next = semver_1.inc(lastVersion, `pre${bump}`, tag);
|
73 | return !next || semver_1.lte(next, currentVersion)
|
74 | ? semver_1.inc(currentVersion, "prerelease", tag) || "prerelease"
|
75 | : next;
|
76 | }
|
77 | exports.determineNextVersion = determineNextVersion;
|
78 |
|
79 | function getAutoVersion() {
|
80 | const packagePath = path_1.default.join(__dirname, "../package.json");
|
81 | const packageJson = JSON.parse(fs_1.default.readFileSync(packagePath, "utf8"));
|
82 | return packageJson.version;
|
83 | }
|
84 | exports.getAutoVersion = getAutoVersion;
|
85 |
|
86 | function escapeRegExp(str) {
|
87 | return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
88 | }
|
89 |
|
90 |
|
91 |
|
92 |
|
93 | class Auto {
|
94 |
|
95 | constructor(options = {}) {
|
96 |
|
97 | this.checkClean = async () => {
|
98 | const status = await exec_promise_1.default("git", ["status", "--porcelain"]);
|
99 | if (!status) {
|
100 | return;
|
101 | }
|
102 | this.logger.log.error("Changed Files:\n", status);
|
103 | throw new Error("Working directory is not clean, make sure all files are committed");
|
104 | };
|
105 |
|
106 | this.prefixRelease = (release) => {
|
107 | var _a;
|
108 | if (!this.release) {
|
109 | throw this.createErrorMessage();
|
110 | }
|
111 | return ((_a = this.config) === null || _a === void 0 ? void 0 : _a.noVersionPrefix) || release.startsWith("v")
|
112 | ? release
|
113 | : `v${release}`;
|
114 | };
|
115 | this.options = options;
|
116 | this.baseBranch = options.baseBranch || "master";
|
117 | logger_1.setLogLevel("quiet" in options && options.quiet
|
118 | ? "quiet"
|
119 | : Array.isArray(options.verbose) && options.verbose.length > 1
|
120 | ? "veryVerbose"
|
121 | : options.verbose
|
122 | ? "verbose"
|
123 | : undefined);
|
124 | this.logger = logger_1.default();
|
125 | this.hooks = make_hooks_1.makeHooks();
|
126 | this.hooks.getRepository.tapPromise("Get repo info from origin", get_repository_1.default);
|
127 | this.hooks.onCreateRelease.tap("Link onCreateChangelog", (release) => {
|
128 | release.hooks.onCreateChangelog.tap("Link onCreateChangelog", (changelog, version) => {
|
129 | this.hooks.onCreateChangelog.call(changelog, version);
|
130 | });
|
131 | });
|
132 | this.hooks.onCreateRelease.tap("Link onCreateLogParse", (release) => {
|
133 | release.hooks.onCreateLogParse.tap("Link onCreateLogParse", (logParse) => {
|
134 | this.hooks.onCreateLogParse.call(logParse);
|
135 | });
|
136 | });
|
137 | this.hooks.beforeCommitChangelog.tapPromise("Old Version Branches", async ({ bump }) => {
|
138 | var _a;
|
139 | if (bump === semver_3.default.major && ((_a = this.config) === null || _a === void 0 ? void 0 : _a.versionBranches)) {
|
140 | const branch = `${this.config.versionBranches}${semver_1.major(await this.hooks.getPreviousVersion.promise())}`;
|
141 | await exec_promise_1.default("git", ["branch", branch]);
|
142 | this.logger.log.success(`Created old version branch: ${branch}`);
|
143 | await exec_promise_1.default("git", ["push", this.remote, branch]);
|
144 | }
|
145 | });
|
146 | |
147 |
|
148 |
|
149 |
|
150 | this.hooks.afterVersion.tapPromise("Check remote for commits", async () => {
|
151 |
|
152 |
|
153 | try {
|
154 | const currentBranch = get_current_branch_1.getCurrentBranch();
|
155 | const heads = await exec_promise_1.default("git", [
|
156 | "ls-remote",
|
157 | "--heads",
|
158 | this.remote,
|
159 | currentBranch,
|
160 | ]);
|
161 | this.logger.verbose.info("Branch:", currentBranch);
|
162 | this.logger.verbose.info("HEADs:", heads);
|
163 | const [, remoteHead] = heads.match(/^(\w+)?/) || [];
|
164 | if (remoteHead) {
|
165 |
|
166 | child_process_1.execSync(`git merge-base --is-ancestor ${remoteHead} HEAD`, {
|
167 | stdio: "ignore",
|
168 | });
|
169 | }
|
170 | this.logger.verbose.info("Current branch is up to date, proceeding with release");
|
171 | }
|
172 | catch (error) {
|
173 |
|
174 | this.logger.log.warn("Current commit is behind, skipping the release to avoid collisions.");
|
175 | this.logger.verbose.warn(error);
|
176 | process.exit(0);
|
177 | }
|
178 | });
|
179 | loadEnv();
|
180 | this.logger.verbose.info("ENV:", env);
|
181 | }
|
182 |
|
183 | async listPlugins() {
|
184 | await load_plugins_1.listPlugins(this.config, this.logger, this.getExtendedLocation(this.config));
|
185 | }
|
186 | |
187 |
|
188 |
|
189 |
|
190 | loadDefaultBehavior() {
|
191 | this.hooks.makeRelease.tapPromise("Default", async (options) => {
|
192 | if (options.dryRun) {
|
193 | const bump = await this.getVersion({ from: options.from });
|
194 | this.logger.log.info(`Would have created a release on GitHub for version: ${semver_1.inc(options.newVersion, bump)}`);
|
195 | this.logger.log.note('The above version would only get released if ran with "shipit" or a custom script that bumps the version using the "version" command');
|
196 | }
|
197 | else {
|
198 | this.logger.log.info(`Releasing ${options.newVersion} to GitHub.`);
|
199 | const release = await this.git.publish(options.fullReleaseNotes, options.newVersion, options.isPrerelease);
|
200 | this.logger.log.info(release.data.html_url);
|
201 | return release;
|
202 | }
|
203 | });
|
204 | }
|
205 | |
206 |
|
207 |
|
208 |
|
209 | async loadConfig() {
|
210 | const configLoader = new config_1.default(this.logger);
|
211 | const userConfig = await configLoader.loadConfig();
|
212 | this.logger.verbose.success("Loaded `auto` with config:", userConfig);
|
213 |
|
214 | this.config = Object.assign(Object.assign({}, userConfig), { plugins: this.options.plugins || userConfig.plugins });
|
215 | this.loadPlugins(this.config);
|
216 | this.loadDefaultBehavior();
|
217 | this.config = this.hooks.modifyConfig.call(this.config);
|
218 | this.labels = this.config.labels;
|
219 | this.semVerLabels = release_1.getVersionMap(this.config.labels);
|
220 | await this.hooks.beforeRun.promise(this.config);
|
221 | const errors = [
|
222 | ...(await validate_config_1.validateAutoRc(this.config)),
|
223 | ...(await validate_config_1.validatePlugins(this.hooks.validateConfig, this.config)),
|
224 | ];
|
225 | if (errors.length) {
|
226 | this.logger.log.error(endent_1.default `
|
227 | Found configuration errors:
|
228 |
|
229 | ${errors.map(validate_config_1.formatError).join("\n")}
|
230 | `, "\n");
|
231 | this.logger.log.warn("These errors are for the fully loaded configuration (this is why some paths might seem off).");
|
232 | if (this.config.extends) {
|
233 | this.logger.log.warn("Some errors might originate from an extend config.");
|
234 | }
|
235 | process.exit(1);
|
236 | }
|
237 | const config = Object.assign(Object.assign(Object.assign({}, this.config), omit_1.omit(this.options, ["_command", "_all", "main"])), { baseBranch: this.baseBranch });
|
238 | this.config = config;
|
239 | const repository = await this.getRepo(config);
|
240 | const token = (repository === null || repository === void 0 ? void 0 : repository.token) || process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
|
241 | if (!token || token === "undefined") {
|
242 | this.logger.log.error("No GitHub was found. Make sure it is available on process.env.GH_TOKEN.");
|
243 | throw new Error("GitHub token not found!");
|
244 | }
|
245 | const githubOptions = Object.assign(Object.assign({ owner: config.owner, repo: config.repo }, repository), { token, agent: proxyUrl ? https_proxy_agent_1.default(proxyUrl) : undefined, baseUrl: config.githubApi || "https://api.github.com", graphqlBaseUrl: config.githubGraphqlApi || config.githubApi || "https://api.github.com" });
|
246 | this.git = this.startGit(githubOptions);
|
247 | this.release = new release_1.default(this.git, config, this.logger);
|
248 | this.remote = await this.getRemote();
|
249 | this.logger.verbose.info(`Using remote: ${this.remote.replace(token, `****${token.substring(0, 4)}`)}`);
|
250 | this.hooks.onCreateRelease.call(this.release);
|
251 | return config;
|
252 | }
|
253 |
|
254 | async getRemote() {
|
255 | const [, configuredRemote = "origin"] = await await_to_js_1.default(exec_promise_1.default("git", ["remote", "get-url", "origin"]));
|
256 | if (!this.git) {
|
257 | return configuredRemote;
|
258 | }
|
259 | const { html_url } = (await this.git.getProject()) || { html_url: "" };
|
260 | const GIT_TOKENS = {
|
261 |
|
262 |
|
263 | GITHUB_TOKEN: process.env.GITHUB_ACTION
|
264 | ? `x-access-token:${process.env.GITHUB_TOKEN}`
|
265 | : undefined,
|
266 | };
|
267 | const envVar = Object.keys(GIT_TOKENS).find((v) => process.env[v]) || "";
|
268 | const gitCredentials = GIT_TOKENS[envVar] || process.env.GH_TOKEN;
|
269 | if (gitCredentials) {
|
270 | const _a = url_1.parse(html_url), { port, hostname } = _a, parsed = tslib_1.__rest(_a, ["port", "hostname"]);
|
271 | const urlWithAuth = url_1.format(Object.assign(Object.assign({}, parsed), { auth: gitCredentials, host: `${hostname}${port ? `:${port}` : ""}` }));
|
272 | if (await this.git.verifyAuth(urlWithAuth)) {
|
273 | this.logger.veryVerbose.note("Using token + html URL as remote");
|
274 | return urlWithAuth;
|
275 | }
|
276 | }
|
277 | if (html_url && (await this.git.verifyAuth(html_url))) {
|
278 | this.logger.veryVerbose.note("Using bare html URL as remote");
|
279 | return html_url;
|
280 | }
|
281 | this.logger.veryVerbose.note("Using remote set in environment");
|
282 | return configuredRemote;
|
283 | }
|
284 |
|
285 | async init() {
|
286 | const init = new init_1.default(this);
|
287 | await init.run();
|
288 | }
|
289 |
|
290 | async info(args) {
|
291 | var _a, _b;
|
292 | if (!this.git) {
|
293 | return { hasError: false };
|
294 | }
|
295 | const [, gitVersion = ""] = await await_to_js_1.default(exec_promise_1.default("git", ["--version"]));
|
296 | const [noProject, project] = await await_to_js_1.default(this.git.getProject());
|
297 | const repo = (await this.getRepo(this.config)) || {};
|
298 | const repoLink = terminal_link_1.default(`${repo.owner}/${repo.repo}`, project === null || project === void 0 ? void 0 : project.html_url);
|
299 | const author = (await this.getGitUser()) || {};
|
300 | const [, lastRelease = "0.0.0"] = await await_to_js_1.default(this.git.getLatestRelease());
|
301 | const version = await this.getCurrentVersion(lastRelease);
|
302 | const [err, latestRelease] = await await_to_js_1.default(this.git.getLatestReleaseInfo());
|
303 | const latestReleaseLink = latestRelease
|
304 | ? terminal_link_1.default(latestRelease.tag_name, latestRelease.html_url)
|
305 | : "";
|
306 | const { headers } = await this.git.github.request("HEAD /");
|
307 | const access = headers;
|
308 | const rateLimitRefresh = new Date(Number(access["x-ratelimit-reset"]) * 1000);
|
309 | const token = this.git.options.token || "";
|
310 | const tokenRefresh = `${rateLimitRefresh.toLocaleTimeString()} ${rateLimitRefresh.toLocaleDateString("en-us")}`;
|
311 | const projectLabels = await this.git.getProjectLabels();
|
312 | const hasLabels = (_a = this.config) === null || _a === void 0 ? void 0 : _a.labels.reduce((acc, label) => {
|
313 | var _a, _b;
|
314 | if (label.name === "release" &&
|
315 | !((_a = this.config) === null || _a === void 0 ? void 0 : _a.onlyPublishWithReleaseLabel)) {
|
316 | return acc;
|
317 | }
|
318 | if (label.name === "skip-release" && ((_b = this.config) === null || _b === void 0 ? void 0 : _b.onlyPublishWithReleaseLabel)) {
|
319 | return acc;
|
320 | }
|
321 | return acc && projectLabels.includes(label.name);
|
322 | }, true);
|
323 | const { permission, user } = (await this.git.getTokenPermissionLevel()) || {};
|
324 | let hasError = false;
|
325 |
|
326 | const logSuccess = (err) => {
|
327 | if (err) {
|
328 | hasError = true;
|
329 | return log_symbols_1.default.error;
|
330 | }
|
331 | return log_symbols_1.default.success;
|
332 | };
|
333 | console.log("");
|
334 |
|
335 | console.log(endent_1.default `
|
336 | ${chalk_1.default.underline.white('Environment Information:')}
|
337 |
|
338 | "auto" version: v${getAutoVersion()}
|
339 | "git" version: v${gitVersion.replace('git version ', '')}
|
340 | "node" version: ${process.version.trim()}${access['x-github-enterprise-version']
|
341 | ? `GHE version: v${access['x-github-enterprise-version']}\n`
|
342 | : '\n'}
|
343 | ${chalk_1.default.underline.white('Project Information:')}
|
344 |
|
345 | ${logSuccess(noProject)} Repository: ${repoLink}
|
346 | ${logSuccess(!author.name)} Author Name: ${author.name}
|
347 | ${logSuccess(!author.email)} Author Email: ${author.email}
|
348 | ${logSuccess(!version)} Current Version: ${this.prefixRelease(version)}
|
349 | ${logSuccess(err)} Latest Release: ${latestReleaseLink}
|
350 |
|
351 | ${logSuccess(!hasLabels)} Labels configured on GitHub project ${hasLabels ? '' : '(Try running "auto create-labels")'}
|
352 |
|
353 | ${chalk_1.default.underline.white('GitHub Token Information:')}
|
354 |
|
355 | ${logSuccess(!token)} Token: ${`[Token starting with ${token.substring(0, 4)}]`}
|
356 | ${logSuccess(!(permission === 'admin' || permission === 'write'))} Repo Permission: ${permission}
|
357 | ${logSuccess(!(user === null || user === void 0 ? void 0 : user.login))} User: ${user === null || user === void 0 ? void 0 : user.login}
|
358 | ${logSuccess()} API: ${terminal_link_1.default(this.git.options.baseUrl, this.git.options.baseUrl)}
|
359 | ${logSuccess(!((_b = access['x-oauth-scopes']) === null || _b === void 0 ? void 0 : _b.includes('repo')))} Enabled Scopes: ${access['x-oauth-scopes']}
|
360 | ${logSuccess(Number(access['x-ratelimit-remaining']) === 0)} Rate Limit: ${access['x-ratelimit-remaining'] || '∞'}/${access['x-ratelimit-limit'] || '∞'} ${access['ratelimit-reset'] ? `(Renews @ ${tokenRefresh})` : ''}
|
361 | `);
|
362 | console.log("");
|
363 | if (args.listPlugins) {
|
364 | await this.listPlugins();
|
365 | }
|
366 | return { hasError };
|
367 | }
|
368 |
|
369 | inPrereleaseBranch() {
|
370 | var _a;
|
371 | const branch = get_current_branch_1.getCurrentBranch();
|
372 | const prereleaseBranches = (_a = this.config) === null || _a === void 0 ? void 0 : _a.prereleaseBranches;
|
373 | return Boolean(branch && prereleaseBranches.includes(branch));
|
374 | }
|
375 |
|
376 | inOldVersionBranch() {
|
377 | var _a;
|
378 | const branch = get_current_branch_1.getCurrentBranch();
|
379 | const oldVersionBranchPrefix = (_a = this.config) === null || _a === void 0 ? void 0 : _a.versionBranches;
|
380 | return Boolean(oldVersionBranchPrefix &&
|
381 | branch &&
|
382 | new RegExp(`^${escapeRegExp(oldVersionBranchPrefix)}`).test(branch));
|
383 | }
|
384 | |
385 |
|
386 |
|
387 | async createLabels(options = {}) {
|
388 | if (!this.release || !this.labels) {
|
389 | throw this.createErrorMessage();
|
390 | }
|
391 | await this.release.addLabelsToProject(this.labels, options);
|
392 | }
|
393 | |
394 |
|
395 |
|
396 | async label({ pr } = {}) {
|
397 | if (!this.git) {
|
398 | throw this.createErrorMessage();
|
399 | }
|
400 | this.logger.verbose.info("Using command: 'label'");
|
401 | const number = getPrNumberFromEnv(pr);
|
402 | let labels = [];
|
403 | if (number) {
|
404 | labels = await this.git.getLabels(number);
|
405 | }
|
406 | else {
|
407 | const pulls = await this.git.getPullRequests({
|
408 | state: "closed",
|
409 | });
|
410 | const lastMerged = pulls
|
411 | .sort((a, b) => new Date(b.merged_at).getTime() - new Date(a.merged_at).getTime())
|
412 | .find((pull) => pull.merged_at);
|
413 | if (lastMerged) {
|
414 | labels = lastMerged.labels.map((label) => label.name);
|
415 | }
|
416 | }
|
417 | if (labels.length) {
|
418 | console.log(labels.join("\n"));
|
419 | }
|
420 | }
|
421 | |
422 |
|
423 |
|
424 | async prStatus(_a) {
|
425 | var { dryRun, pr, url } = _a, options = tslib_1.__rest(_a, ["dryRun", "pr", "url"]);
|
426 | if (!this.git) {
|
427 | throw this.createErrorMessage();
|
428 | }
|
429 | let { sha } = options;
|
430 | let prNumber;
|
431 | try {
|
432 | prNumber = this.getPrNumber("pr", pr);
|
433 | }
|
434 | catch (error) {
|
435 |
|
436 | }
|
437 | this.logger.verbose.info("Using command: 'pr-status'");
|
438 | if (!sha && prNumber) {
|
439 | this.logger.verbose.info("Getting commit SHA from PR.");
|
440 | const res = await this.git.getPullRequest(prNumber);
|
441 | sha = res.data.head.sha;
|
442 | }
|
443 | else if (!sha) {
|
444 | this.logger.verbose.info("No PR found, getting commit SHA from HEAD.");
|
445 | sha = await this.git.getSha();
|
446 | }
|
447 | this.logger.verbose.info("Found PR SHA:", sha);
|
448 | const target_url = url;
|
449 | if (dryRun) {
|
450 | this.logger.verbose.info("`pr` dry run complete.");
|
451 | }
|
452 | else {
|
453 | try {
|
454 | await this.git.createStatus(Object.assign(Object.assign({}, options), { sha,
|
455 | target_url }));
|
456 | }
|
457 | catch (error) {
|
458 | throw new Error(`Failed to post status to Pull Request with error code ${error.status}`);
|
459 | }
|
460 | this.logger.log.success("Posted status to Pull Request.");
|
461 | }
|
462 | this.logger.verbose.success("Finished `pr` command");
|
463 | }
|
464 | |
465 |
|
466 |
|
467 | async prCheck(_a) {
|
468 | var _b, _c;
|
469 | var { dryRun, pr, url } = _a, options = tslib_1.__rest(_a, ["dryRun", "pr", "url"]);
|
470 | if (!this.git || !this.release || !this.semVerLabels) {
|
471 | throw this.createErrorMessage();
|
472 | }
|
473 | this.logger.verbose.info(`Using command: 'pr-check' for '${url}'`);
|
474 | const target_url = url;
|
475 | const prNumber = this.getPrNumber("prCheck", pr);
|
476 | let msg;
|
477 | let sha;
|
478 | try {
|
479 | const res = await this.git.getPullRequest(prNumber);
|
480 | sha = res.data.head.sha;
|
481 | const labels = await this.git.getLabels(prNumber);
|
482 | const labelValues = [...this.semVerLabels.values()];
|
483 | const releaseTag = labels.find((l) => l === "release");
|
484 | const skipReleaseLabels = (((_b = this.config) === null || _b === void 0 ? void 0 : _b.labels.filter((l) => l.releaseType === "skip")) || []).map((l) => l.name);
|
485 | const skipReleaseTag = labels.find((l) => skipReleaseLabels.includes(l));
|
486 | const semverTag = labels.find((l) => labelValues.some((labelValue) => labelValue.includes(l)) &&
|
487 | !skipReleaseLabels.includes(l) &&
|
488 | l !== "release");
|
489 | const branch = get_current_branch_1.getCurrentBranch();
|
490 | if (branch && ((_c = this.config) === null || _c === void 0 ? void 0 : _c.prereleaseBranches.includes(branch))) {
|
491 | msg = {
|
492 | description: "PR will graduate prerelease once merged",
|
493 | state: "success",
|
494 | };
|
495 | }
|
496 | else if (semverTag === undefined && !skipReleaseTag) {
|
497 | throw new Error("No semver label!");
|
498 | }
|
499 | else {
|
500 | this.logger.log.success(`PR is using label: ${semverTag || skipReleaseTag}`);
|
501 | let description;
|
502 | if (skipReleaseTag) {
|
503 | description = "PR will not create a release";
|
504 | }
|
505 | else if (releaseTag) {
|
506 | description = `PR will create release once merged - ${semverTag}`;
|
507 | }
|
508 | else {
|
509 | description = `CI - ${semverTag}`;
|
510 | }
|
511 | msg = {
|
512 | description,
|
513 | state: "success",
|
514 | };
|
515 | }
|
516 | }
|
517 | catch (error) {
|
518 | msg = {
|
519 | description: error.message,
|
520 | state: "error",
|
521 | };
|
522 | }
|
523 | this.logger.verbose.info("Posting status to GitHub\n", msg);
|
524 | if (dryRun) {
|
525 | this.logger.verbose.info("`pr-check` dry run complete.");
|
526 | }
|
527 | else {
|
528 | try {
|
529 | await this.git.createStatus(Object.assign(Object.assign(Object.assign({}, options), msg), { target_url,
|
530 | sha }));
|
531 | this.logger.log.success("Posted status to Pull Request.");
|
532 | }
|
533 | catch (error) {
|
534 | throw new Error(`Failed to post status to Pull Request with error code ${error.status}`);
|
535 | }
|
536 | }
|
537 | this.logger.verbose.success("Finished `pr-check` command");
|
538 | }
|
539 | |
540 |
|
541 |
|
542 |
|
543 | async comment(args) {
|
544 | const options = Object.assign(Object.assign({}, this.getCommandDefault("comment")), args);
|
545 | const { message, pr, context = "default", dryRun, delete: deleteFlag, edit: editFlag, } = options;
|
546 | if (!this.git) {
|
547 | throw this.createErrorMessage();
|
548 | }
|
549 | this.logger.verbose.info("Using command: 'comment'");
|
550 | const prNumber = this.getPrNumber("comment", pr);
|
551 | if (dryRun) {
|
552 | if (deleteFlag) {
|
553 | this.logger.log.info(`Would have deleted comment on ${prNumber} under "${context}" context`);
|
554 | }
|
555 | else if (editFlag) {
|
556 | this.logger.log.info(`Would have edited the comment on ${prNumber} under "${context}" context.\n\nNew message: ${message}`);
|
557 | }
|
558 | else {
|
559 | this.logger.log.info(`Would have commented on ${prNumber} under "${context}" context:\n\n${message}`);
|
560 | }
|
561 | }
|
562 | else if (editFlag && message) {
|
563 | await this.git.editComment(message, prNumber, context);
|
564 | this.logger.log.success(`Edited comment on PR #${prNumber} under context "${context}"`);
|
565 | }
|
566 | else {
|
567 | if (deleteFlag) {
|
568 | await this.git.deleteComment(prNumber, context);
|
569 | this.logger.log.success(`Deleted comment on PR #${prNumber} under context "${context}"`);
|
570 | }
|
571 | if (message) {
|
572 | await this.git.createComment(message, prNumber, context);
|
573 | this.logger.log.success(`Commented on PR #${prNumber}`);
|
574 | }
|
575 | }
|
576 | }
|
577 | |
578 |
|
579 |
|
580 |
|
581 |
|
582 | async prBody(options) {
|
583 | const { message, pr, context = "default", dryRun, delete: deleteFlag, } = options;
|
584 | if (!this.git) {
|
585 | throw this.createErrorMessage();
|
586 | }
|
587 | this.logger.verbose.info("Using command: 'pr-body'");
|
588 | const prNumber = this.getPrNumber("pr-body", pr);
|
589 | if (dryRun) {
|
590 | if (deleteFlag) {
|
591 | this.logger.log.info(`Would have deleted PR body on ${prNumber} under "${context}" context`);
|
592 | }
|
593 | else {
|
594 | this.logger.log.info(`Would have appended to PR body on ${prNumber} under "${context}" context:\n\n${message}`);
|
595 | }
|
596 | }
|
597 | else {
|
598 | if (deleteFlag) {
|
599 | await this.git.addToPrBody("", prNumber, context);
|
600 | }
|
601 | if (message) {
|
602 | await this.git.addToPrBody(message, prNumber, context);
|
603 | }
|
604 | this.logger.log.success(`Updated body on PR #${prNumber}`);
|
605 | }
|
606 | }
|
607 | |
608 |
|
609 |
|
610 | async version(options = {}) {
|
611 | this.logger.verbose.info("Using command: 'version'");
|
612 | const bump = await this.getVersion(options);
|
613 | console.log(bump);
|
614 | }
|
615 | |
616 |
|
617 |
|
618 | async changelog(options) {
|
619 | this.logger.verbose.info("Using command: 'changelog'");
|
620 | await this.makeChangelog(options);
|
621 | }
|
622 | |
623 |
|
624 |
|
625 | async runRelease(options = {}) {
|
626 | this.logger.verbose.info("Using command: 'release'");
|
627 | await this.makeRelease(options);
|
628 | }
|
629 |
|
630 |
|
631 | async canary(args = {}) {
|
632 | const options = Object.assign(Object.assign({}, this.getCommandDefault("canary")), args);
|
633 | if (!this.git || !this.release) {
|
634 | throw this.createErrorMessage();
|
635 | }
|
636 | if (!this.hooks.canary.isUsed()) {
|
637 | this.logger.log.warn(endent_1.default `
|
638 | None of the plugins that you are using implement the \`canary\` command!
|
639 |
|
640 | "canary" releases are versions that are used solely to test changes. They make sense on some platforms (ex: npm) but not all!
|
641 |
|
642 | If you think your package manager has the ability to support canaries please file an issue or submit a pull request,
|
643 | `);
|
644 | process.exit(0);
|
645 | }
|
646 | if (!args.dryRun) {
|
647 | await this.checkClean();
|
648 | }
|
649 | let { pr, build } = await this.getPrEnvInfo();
|
650 | pr = options.pr ? String(options.pr) : pr;
|
651 | build = options.build ? String(options.build) : build;
|
652 | this.logger.verbose.info("Canary info found:", { pr, build });
|
653 | const from = (await this.git.shaExists("HEAD^")) ? "HEAD^" : "HEAD";
|
654 | const head = await this.release.getCommitsInRelease(from);
|
655 | const labels = head.map((commit) => commit.labels);
|
656 | let version = semver_3.calculateSemVerBump(labels, this.semVerLabels, this.config);
|
657 | if (version === semver_3.default.noVersion) {
|
658 | if (options.force) {
|
659 | version = semver_3.default.patch;
|
660 | }
|
661 | else {
|
662 | this.logger.log.info("Skipping canary release due to PR being specifying no release. Use `auto canary --force` to override this setting");
|
663 | return;
|
664 | }
|
665 | }
|
666 | let canaryVersion = "";
|
667 | let newVersion = "";
|
668 | if (pr) {
|
669 | canaryVersion = `${canaryVersion}.${pr}`;
|
670 | }
|
671 | if (build) {
|
672 | canaryVersion = `${canaryVersion}.${build}`;
|
673 | }
|
674 | if (!pr || !build) {
|
675 | canaryVersion = `${canaryVersion}.${await this.git.getSha(true)}`;
|
676 | }
|
677 | canaryVersion = `canary${canaryVersion}`;
|
678 | if (options.dryRun) {
|
679 | const lastRelease = await this.git.getLatestRelease();
|
680 | const current = await this.getCurrentVersion(lastRelease);
|
681 | if (semver_1.parse(current)) {
|
682 | const next = determineNextVersion(lastRelease, current, version, canaryVersion);
|
683 | if (options.quiet) {
|
684 | console.log(next);
|
685 | }
|
686 | else {
|
687 | this.logger.log.warn(`Published canary identifier would be: ${next}`);
|
688 | }
|
689 | }
|
690 | else if (options.quiet) {
|
691 | console.log(`-${canaryVersion}`);
|
692 | }
|
693 | else {
|
694 | this.logger.log.warn(`Published canary identifier would be: "-${canaryVersion}"`);
|
695 | }
|
696 | }
|
697 | else {
|
698 | this.logger.verbose.info("Calling canary hook");
|
699 | const result = await this.hooks.canary.promise(version, canaryVersion);
|
700 | if (typeof result === "object" && "error" in result) {
|
701 | this.logger.log.warn(result.error);
|
702 | return;
|
703 | }
|
704 | if (!result) {
|
705 | return;
|
706 | }
|
707 | newVersion = typeof result === "string" ? result : result.newVersion;
|
708 | const messageHeader = (options.message || "📦 Published PR as canary version: %v").replace("%v", !newVersion || newVersion.includes("\n")
|
709 | ? newVersion
|
710 | : `<code>${newVersion}</code>`);
|
711 | if (options.message !== "false" && pr) {
|
712 | const message = typeof result === "string"
|
713 | ? messageHeader
|
714 | : makeDetail(messageHeader, result.details);
|
715 | await this.prBody({
|
716 | pr: Number(pr),
|
717 | context: "canary-version",
|
718 | message,
|
719 | });
|
720 | }
|
721 | this.logger.log.success(`Published canary version${newVersion ? `: ${newVersion}` : ""}`);
|
722 | if (args.quiet) {
|
723 | console.log(newVersion);
|
724 | }
|
725 | await git_reset_1.gitReset();
|
726 | }
|
727 | let latestTag;
|
728 | try {
|
729 | latestTag = await this.git.getLatestTagInBranch();
|
730 | }
|
731 | catch (error) {
|
732 | latestTag = await this.git.getFirstCommit();
|
733 | }
|
734 | const commitsInRelease = await this.release.getCommits(latestTag);
|
735 | return { newVersion, commitsInRelease, context: "canary" };
|
736 | }
|
737 | |
738 |
|
739 |
|
740 |
|
741 | async next(args) {
|
742 | var _a;
|
743 | const options = Object.assign(Object.assign({}, this.getCommandDefault("next")), args);
|
744 | if (!this.git || !this.release) {
|
745 | throw this.createErrorMessage();
|
746 | }
|
747 | if (!this.hooks.next.isUsed()) {
|
748 | this.logger.log.warn(endent_1.default `
|
749 | None of the plugins that you are using implement the \`next\` command!
|
750 |
|
751 | "next" releases are pre-releases such as betas or alphas. They make sense on some platforms (ex: npm) but not all!
|
752 |
|
753 | If you think your package manager has the ability to support "next" releases please file an issue or submit a pull request,
|
754 | `);
|
755 | process.exit(0);
|
756 | }
|
757 | if (!args.dryRun) {
|
758 | await this.checkClean();
|
759 | }
|
760 | await this.setGitUser();
|
761 | this.hooks.onCreateLogParse.tap("Omit merges from master", (logParse) => {
|
762 | logParse.hooks.omitCommit.tap("Omit merges from master", (commit) => {
|
763 | const shouldOmit = commit.subject.match(/^Merge (?:\S+\/)*master/);
|
764 | if (shouldOmit) {
|
765 | this.logger.verbose.info(`Omitting merge commit from master: ${commit.subject}`);
|
766 | return true;
|
767 | }
|
768 | });
|
769 | });
|
770 | const currentBranch = get_current_branch_1.getCurrentBranch();
|
771 | const forkPoints = (await exec_promise_1.default("git", [
|
772 | "rev-list",
|
773 | "--boundary",
|
774 | `${currentBranch}...origin/${this.baseBranch}`,
|
775 | "--left-only",
|
776 | ]))
|
777 | .split("\n")
|
778 | .filter((line) => line.startsWith("-"));
|
779 | const initialForkCommit = (forkPoints[forkPoints.length - 1] || "").slice(1);
|
780 | const lastRelease = initialForkCommit || (await this.git.getLatestRelease());
|
781 | const lastTag = (await this.git.getLastTagNotInBaseBranch(currentBranch)) ||
|
782 | (await this.git.getFirstCommit());
|
783 | const fullReleaseNotes = await this.release.generateReleaseNotes(lastRelease);
|
784 | const commits = await this.release.getCommitsInRelease(lastTag);
|
785 | const releaseNotes = await this.release.generateReleaseNotes(lastTag);
|
786 | const labels = commits.map((commit) => commit.labels);
|
787 | const bump = semver_3.calculateSemVerBump(labels, this.semVerLabels, this.config) ||
|
788 | semver_3.default.patch;
|
789 | if (!args.quiet) {
|
790 | this.logger.log.info("Full Release notes for next release:");
|
791 | console.log(fullReleaseNotes);
|
792 | if (releaseNotes) {
|
793 | this.logger.log.info("Release notes for last change in next release");
|
794 | console.log(releaseNotes);
|
795 | }
|
796 | }
|
797 | if (options.dryRun) {
|
798 | const lastRelease = await this.git.getLatestRelease();
|
799 | const current = await this.getCurrentVersion(lastRelease);
|
800 | if (semver_1.parse(current)) {
|
801 | const prereleaseBranches = (_a = this.config) === null || _a === void 0 ? void 0 : _a.prereleaseBranches;
|
802 | const branch = get_current_branch_1.getCurrentBranch() || "";
|
803 | const prereleaseBranch = prereleaseBranches.includes(branch)
|
804 | ? branch
|
805 | : prereleaseBranches[0];
|
806 | const prerelease = determineNextVersion(lastRelease, current, bump, prereleaseBranch);
|
807 | if (options.quiet) {
|
808 | console.log(prerelease);
|
809 | }
|
810 | else {
|
811 | this.logger.log.success(`Would have created prerelease version: ${prerelease}`);
|
812 | }
|
813 | }
|
814 | else if (options.quiet) {
|
815 |
|
816 | console.log(`${bump} on ${lastTag}`);
|
817 | }
|
818 | else {
|
819 | this.logger.log.success(`Would have created prerelease version with: ${bump} on ${lastTag}`);
|
820 | }
|
821 | return { newVersion: "", commitsInRelease: commits, context: "next" };
|
822 | }
|
823 | this.logger.verbose.info(`Calling "next" hook with: ${bump}`);
|
824 | const result = await this.hooks.next.promise([], bump, {
|
825 | commits,
|
826 | fullReleaseNotes,
|
827 | releaseNotes,
|
828 | });
|
829 | const newVersion = result.join(", ");
|
830 | await Promise.all(result.map(async (prerelease) => {
|
831 | var _a;
|
832 | const release = await ((_a = this.git) === null || _a === void 0 ? void 0 : _a.publish(releaseNotes, prerelease, true));
|
833 | this.logger.verbose.info(release);
|
834 | await this.hooks.afterRelease.promise({
|
835 | lastRelease: lastTag,
|
836 | newVersion: prerelease,
|
837 | commits,
|
838 | releaseNotes,
|
839 | response: release,
|
840 | });
|
841 | }));
|
842 | this.logger.log.success(`Published next version${result.length > 1 ? `s` : ""}: ${newVersion}`);
|
843 | const { pr } = await this.getPrEnvInfo();
|
844 | if (pr) {
|
845 | const message = options.message || "Published prerelease version: %v";
|
846 | if (pr) {
|
847 | await this.prBody({
|
848 | pr: Number(pr),
|
849 | context: "prerelease-version",
|
850 | message: endent_1.default `
|
851 | # Version
|
852 |
|
853 | ${message.replace("%v", result.map((r) => `\`${r}\``).join("\n"))}
|
854 |
|
855 | <details>
|
856 | <summary>Changelog</summary>
|
857 |
|
858 | ${fullReleaseNotes}
|
859 | </details>
|
860 | `,
|
861 | });
|
862 | }
|
863 | }
|
864 | if (options.quiet) {
|
865 | console.log(newVersion);
|
866 | }
|
867 | await git_reset_1.gitReset();
|
868 | return { newVersion, commitsInRelease: commits, context: "next" };
|
869 | }
|
870 |
|
871 | async latest(args = {}) {
|
872 | const options = Object.assign(Object.assign({}, this.getCommandDefault("latest")), args);
|
873 | return this.publishFullRelease(options);
|
874 | }
|
875 | |
876 |
|
877 |
|
878 |
|
879 |
|
880 |
|
881 |
|
882 |
|
883 | async shipit(args = {}) {
|
884 | var _a, _b;
|
885 | const options = Object.assign(Object.assign({}, this.getCommandDefault("shipit")), args);
|
886 | if (!this.git || !this.release) {
|
887 | throw this.createErrorMessage();
|
888 | }
|
889 | this.logger.verbose.info("Using command: 'shipit'");
|
890 | const isPR = "isPr" in env && env.isPr;
|
891 | const from = (await this.git.shaExists("HEAD^")) ? "HEAD^" : "HEAD";
|
892 | const head = await this.release.getCommitsInRelease(from);
|
893 |
|
894 |
|
895 | const currentBranch = get_current_branch_1.getCurrentBranch();
|
896 | const isBaseBranch = !isPR && currentBranch === this.baseBranch;
|
897 | const shouldGraduate = !options.onlyGraduateWithReleaseLabel ||
|
898 | (options.onlyGraduateWithReleaseLabel &&
|
899 | head[0].labels.some((l) => { var _a, _b; return (_b = (_a = this.semVerLabels) === null || _a === void 0 ? void 0 : _a.get("release")) === null || _b === void 0 ? void 0 : _b.includes(l); }));
|
900 | const isPrereleaseBranch = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.prereleaseBranches) === null || _b === void 0 ? void 0 : _b.some((branch) => currentBranch === branch);
|
901 | const publishPrerelease = isPrereleaseBranch ||
|
902 | (currentBranch === this.baseBranch &&
|
903 | options.onlyGraduateWithReleaseLabel);
|
904 | this.logger.veryVerbose.info({
|
905 | currentBranch,
|
906 | isBaseBranch,
|
907 | isPR,
|
908 | shouldGraduate,
|
909 | isPrereleaseBranch,
|
910 | publishPrerelease,
|
911 | });
|
912 | let publishInfo;
|
913 | let releaseType = "canary";
|
914 | if (isBaseBranch && shouldGraduate) {
|
915 | releaseType = "latest";
|
916 | }
|
917 | else if (this.inOldVersionBranch()) {
|
918 | releaseType = "old";
|
919 | }
|
920 | else if (publishPrerelease) {
|
921 | releaseType = "next";
|
922 | }
|
923 | await this.hooks.beforeShipIt.promise({ releaseType });
|
924 | if (releaseType === "latest") {
|
925 | publishInfo = await this.latest(options);
|
926 | }
|
927 | else if (releaseType === "old") {
|
928 | publishInfo = await this.oldRelease(options);
|
929 | }
|
930 | else if (releaseType === "next") {
|
931 | publishInfo = await this.next(options);
|
932 | }
|
933 | else {
|
934 | publishInfo = await this.canary(options);
|
935 | if (options.dryRun && !options.quiet) {
|
936 | this.logger.log.success("Below is what would happen upon merge of the current branch into master");
|
937 | await this.publishFullRelease(options);
|
938 | }
|
939 | }
|
940 | if (!publishInfo) {
|
941 | return;
|
942 | }
|
943 | const { newVersion, commitsInRelease, context } = publishInfo;
|
944 | await this.hooks.afterShipIt.promise(newVersion, commitsInRelease, {
|
945 | context,
|
946 | });
|
947 | }
|
948 |
|
949 | async getCurrentVersion(lastRelease) {
|
950 | this.hooks.getPreviousVersion.tap("None", () => {
|
951 | this.logger.veryVerbose.info("No previous release found, using 0.0.0 as previous version.");
|
952 | return this.prefixRelease("0.0.0");
|
953 | });
|
954 | const lastVersion = await this.hooks.getPreviousVersion.promise();
|
955 | if (semver_1.parse(lastRelease) &&
|
956 | semver_1.parse(lastVersion) &&
|
957 | semver_1.gt(lastRelease, lastVersion)) {
|
958 | this.logger.veryVerbose.info("Using latest release as previous version");
|
959 | return lastRelease;
|
960 | }
|
961 | return lastVersion;
|
962 | }
|
963 | |
964 |
|
965 |
|
966 | checkEnv(pluginName, key) {
|
967 | if (!process.env[key]) {
|
968 | this.logger.log.warn(`${pluginName}: No "${key}" found in environment`);
|
969 | }
|
970 | }
|
971 |
|
972 | async oldRelease(options) {
|
973 | var _a;
|
974 | const latestTag = await ((_a = this.git) === null || _a === void 0 ? void 0 : _a.getLatestTagInBranch());
|
975 | const result = await this.publishFullRelease(Object.assign(Object.assign({}, options), { from: latestTag }));
|
976 | if (result) {
|
977 | result.context = "old";
|
978 | }
|
979 | return result;
|
980 | }
|
981 |
|
982 | async publishFullRelease(options) {
|
983 | if (!this.git || !this.release) {
|
984 | throw this.createErrorMessage();
|
985 | }
|
986 | const version = await this.getVersion(options);
|
987 | this.logger.log.success(`Calculated version bump: ${version || "none"}`);
|
988 | if (version === "") {
|
989 | this.logger.log.info("No version published.");
|
990 | return;
|
991 | }
|
992 | const lastRelease = options.from || (await this.git.getLatestRelease());
|
993 | const commitsInRelease = await this.release.getCommitsInRelease(lastRelease);
|
994 | await this.makeChangelog(Object.assign(Object.assign({}, options), { quiet: undefined, noCommit: options.noChangelog }));
|
995 | if (!options.dryRun) {
|
996 | await this.checkClean();
|
997 | this.logger.verbose.info("Calling version hook");
|
998 | await this.hooks.version.promise(version);
|
999 | this.logger.verbose.info("Calling after version hook");
|
1000 | await this.hooks.afterVersion.promise();
|
1001 | this.logger.verbose.info("Calling publish hook");
|
1002 | await this.hooks.publish.promise(version);
|
1003 | this.logger.verbose.info("Calling after publish hook");
|
1004 | await this.hooks.afterPublish.promise();
|
1005 | }
|
1006 | const newVersion = await this.makeRelease(options);
|
1007 | if (options.dryRun) {
|
1008 | const current = await this.getCurrentVersion(lastRelease);
|
1009 | if (semver_1.parse(current)) {
|
1010 | const next = semver_1.inc(current, version);
|
1011 | if (options.quiet) {
|
1012 | console.log(next);
|
1013 | }
|
1014 | else {
|
1015 | this.logger.log.warn(`Published version would be: ${next}`);
|
1016 | }
|
1017 | }
|
1018 | }
|
1019 | else if (options.quiet) {
|
1020 | console.log(newVersion);
|
1021 | }
|
1022 | return { newVersion, commitsInRelease, context: "latest" };
|
1023 | }
|
1024 |
|
1025 | getPrNumber(command, pr) {
|
1026 | const prNumber = getPrNumberFromEnv(pr);
|
1027 | if (!prNumber) {
|
1028 | this.logger.log.error(endent_1.default `
|
1029 | Could not detect PR number. ${command} must be run from either a PR or have the PR number supplied via the --pr flag.
|
1030 |
|
1031 | In some CIs your branch might be built before you open a PR and posting the canary version will fail. In this case subsequent builds should succeed.
|
1032 | `);
|
1033 | process.exit(1);
|
1034 | }
|
1035 | return prNumber;
|
1036 | }
|
1037 |
|
1038 | startGit(gitOptions) {
|
1039 | if (!gitOptions.owner || !gitOptions.repo || !gitOptions.token) {
|
1040 | throw new Error("Must set owner, repo, and GitHub token.");
|
1041 | }
|
1042 | this.logger.verbose.info("Options contain repo information.");
|
1043 |
|
1044 | const tokenlessArgs = Object.assign(Object.assign({}, gitOptions), { token: `[Token starting with ${gitOptions.token.substring(0, 4)}]` });
|
1045 | this.logger.verbose.info("Initializing GitHub API with:\n", tokenlessArgs);
|
1046 | return new git_1.default({
|
1047 | owner: gitOptions.owner,
|
1048 | repo: gitOptions.repo,
|
1049 | token: gitOptions.token,
|
1050 | baseUrl: gitOptions.baseUrl,
|
1051 | baseBranch: this.baseBranch,
|
1052 | graphqlBaseUrl: gitOptions.graphqlBaseUrl,
|
1053 | agent: gitOptions.agent,
|
1054 | }, this.logger);
|
1055 | }
|
1056 |
|
1057 | async getVersion({ from } = {}) {
|
1058 | if (!this.git || !this.release) {
|
1059 | throw this.createErrorMessage();
|
1060 | }
|
1061 | const isPrerelease = this.inPrereleaseBranch();
|
1062 | const lastRelease = from ||
|
1063 | (isPrerelease && (await this.git.getLatestTagInBranch())) ||
|
1064 | (await this.git.getLatestRelease());
|
1065 | const calculatedBump = await this.release.getSemverBump(lastRelease);
|
1066 | const bump = (isPrerelease && semver_2.preVersionMap.get(calculatedBump)) || calculatedBump;
|
1067 | this.versionBump = bump;
|
1068 | return bump;
|
1069 | }
|
1070 |
|
1071 | async makeChangelog(args = {}) {
|
1072 | const options = Object.assign(Object.assign({}, this.getCommandDefault("changelog")), args);
|
1073 | const { dryRun, from, to, title, message = "Update CHANGELOG.md [skip ci]", noCommit, } = options;
|
1074 | if (!this.release || !this.git) {
|
1075 | throw this.createErrorMessage();
|
1076 | }
|
1077 | await this.setGitUser();
|
1078 | if (title) {
|
1079 | this.release.hooks.createChangelogTitle.tap("Changelog Flag", () => title);
|
1080 | }
|
1081 | const lastRelease = from || (await this.git.getLatestRelease());
|
1082 | const bump = await this.release.getSemverBump(lastRelease, to);
|
1083 | const releaseNotes = await this.release.generateReleaseNotes(lastRelease, to, this.versionBump);
|
1084 | if (dryRun) {
|
1085 | this.logger.log.info("Potential Changelog Addition:\n", releaseNotes);
|
1086 | this.logger.verbose.info("`changelog` dry run complete.");
|
1087 | return;
|
1088 | }
|
1089 | if (args.quiet) {
|
1090 | console.log(releaseNotes);
|
1091 | }
|
1092 | else {
|
1093 | this.logger.log.info("New Release Notes\n", releaseNotes);
|
1094 | }
|
1095 | const currentVersion = await this.getCurrentVersion(lastRelease);
|
1096 | const context = {
|
1097 | bump,
|
1098 | commits: await this.release.getCommits(lastRelease, to || undefined),
|
1099 | releaseNotes,
|
1100 | lastRelease,
|
1101 | currentVersion,
|
1102 | };
|
1103 | if (!noCommit) {
|
1104 | await this.release.addToChangelog(releaseNotes, lastRelease, currentVersion);
|
1105 | await this.hooks.beforeCommitChangelog.promise(context);
|
1106 | await exec_promise_1.default("git", ["commit", "-m", `"${message}"`, "--no-verify"]);
|
1107 | this.logger.verbose.info("Committed new changelog.");
|
1108 | }
|
1109 | await this.hooks.afterAddToChangelog.promise(context);
|
1110 | }
|
1111 |
|
1112 | async makeRelease(args = {}) {
|
1113 | const options = Object.assign(Object.assign({}, this.getCommandDefault("release")), args);
|
1114 | const { dryRun, from, useVersion, prerelease = false } = options;
|
1115 | if (!this.release || !this.git) {
|
1116 | throw this.createErrorMessage();
|
1117 | }
|
1118 |
|
1119 | const [err, latestTag] = await await_to_js_1.default(this.git.getLatestTagInBranch());
|
1120 |
|
1121 |
|
1122 | if ((err === null || err === void 0 ? void 0 : err.message.includes("No names found")) && !args.dryRun) {
|
1123 | this.logger.log.error(endent_1.default `
|
1124 | Could not find any tags in the local repository. Exiting early.
|
1125 |
|
1126 | The "release" command creates GitHub releases for tags that have already been created in your repo.
|
1127 |
|
1128 | If there are no tags there is nothing to release. If you don't use "shipit" ensure you tag your releases with the new version number.
|
1129 | `, "\n");
|
1130 | this.logger.verbose.error(err);
|
1131 | return process.exit(1);
|
1132 | }
|
1133 | const isPrerelease = prerelease || this.inPrereleaseBranch();
|
1134 | let lastRelease = from ||
|
1135 | (isPrerelease && (await this.git.getPreviousTagInBranch())) ||
|
1136 | (await this.git.getLatestRelease());
|
1137 |
|
1138 | this.logger.veryVerbose.info(`Using ${lastRelease} as previous release.`);
|
1139 | if (lastRelease.match(/^\d+\.\d+\.\d+/)) {
|
1140 | lastRelease = this.prefixRelease(lastRelease);
|
1141 | }
|
1142 | this.logger.log.info('Current "Latest Release" on Github:', lastRelease);
|
1143 | const commitsInRelease = await this.release.getCommitsInRelease(lastRelease);
|
1144 | const releaseNotes = await this.release.generateReleaseNotes(lastRelease, undefined, this.versionBump);
|
1145 | this.logger.log.info(`Using release notes:\n${releaseNotes}`);
|
1146 | const rawVersion = useVersion ||
|
1147 | (isPrerelease && latestTag) ||
|
1148 | (await this.getCurrentVersion(lastRelease)) ||
|
1149 | latestTag;
|
1150 | if (!rawVersion) {
|
1151 | this.logger.log.error("Could not calculate next version from last tag.");
|
1152 | return;
|
1153 | }
|
1154 | const newVersion = semver_1.parse(rawVersion)
|
1155 | ? this.prefixRelease(rawVersion)
|
1156 | : rawVersion;
|
1157 | if (!dryRun &&
|
1158 | semver_1.parse(newVersion) &&
|
1159 | semver_1.parse(lastRelease) &&
|
1160 | semver_1.eq(newVersion, lastRelease)) {
|
1161 | this.logger.log.warn(`Nothing released to Github. Version to be released is the same as the latest release on Github: ${newVersion}`);
|
1162 | return;
|
1163 | }
|
1164 | const release = await this.hooks.makeRelease.promise({
|
1165 | dryRun,
|
1166 | from: lastRelease,
|
1167 | isPrerelease,
|
1168 | newVersion,
|
1169 | fullReleaseNotes: releaseNotes,
|
1170 | commits: commitsInRelease,
|
1171 | });
|
1172 | if (release) {
|
1173 | await this.hooks.afterRelease.promise({
|
1174 | lastRelease,
|
1175 | newVersion,
|
1176 | commits: commitsInRelease,
|
1177 | releaseNotes,
|
1178 | response: release,
|
1179 | });
|
1180 | }
|
1181 | return newVersion;
|
1182 | }
|
1183 |
|
1184 | createErrorMessage() {
|
1185 | return new Error(`Auto is not initialized! Make sure the have run Auto.loadConfig`);
|
1186 | }
|
1187 |
|
1188 | async getGitUser() {
|
1189 | try {
|
1190 | return {
|
1191 |
|
1192 | system: true,
|
1193 | email: await exec_promise_1.default("git", ["config", "user.email"]),
|
1194 | name: await exec_promise_1.default("git", ["config", "user.name"]),
|
1195 | };
|
1196 | }
|
1197 | catch (error) {
|
1198 | this.logger.verbose.warn("Could not find git user or email configured in git config");
|
1199 | if (!this.release) {
|
1200 | return;
|
1201 | }
|
1202 | let { email, name } = this.release.config;
|
1203 | this.logger.verbose.warn(`Got author from options: email: ${email}, name ${name}`);
|
1204 | const packageAuthor = await this.hooks.getAuthor.promise();
|
1205 | email = !email && packageAuthor ? packageAuthor.email : email;
|
1206 | name = !name && packageAuthor ? packageAuthor.name : name;
|
1207 | this.logger.verbose.warn(`Using author: ${name} <${email}>`);
|
1208 | return { email, name };
|
1209 | }
|
1210 | }
|
1211 | |
1212 |
|
1213 |
|
1214 | async setGitUser() {
|
1215 | const user = await this.getGitUser();
|
1216 | if (user && !user.system) {
|
1217 | if (!env.isCi) {
|
1218 | this.logger.log.note(endent_1.default `
|
1219 | Detected local environment, will not set git user. This happens automatically in a CI environment.
|
1220 |
|
1221 | If a command fails manually run:
|
1222 |
|
1223 | - git config user.email your@email.com
|
1224 | - git config user.name "Your Name"
|
1225 | `);
|
1226 | return;
|
1227 | }
|
1228 | if (user.email) {
|
1229 | await exec_promise_1.default("git", ["config", "user.email", `"${user.email}"`]);
|
1230 | this.logger.verbose.warn(`Set git email to ${user.email}`);
|
1231 | }
|
1232 | if (user.name) {
|
1233 | await exec_promise_1.default("git", ["config", "user.name", `"${user.name}"`]);
|
1234 | this.logger.verbose.warn(`Set git name to ${user.name}`);
|
1235 | }
|
1236 | }
|
1237 | }
|
1238 |
|
1239 | async getRepo(config) {
|
1240 | if (config.owner && config.repo) {
|
1241 | return config;
|
1242 | }
|
1243 | const author = await this.hooks.getRepository.promise();
|
1244 | if (!author || !author.owner || !author.repo) {
|
1245 | this.logger.log.error(endent_1.default `
|
1246 | Cannot find project owner and repository name!
|
1247 |
|
1248 | You must do one of the following:
|
1249 |
|
1250 | - configure the repo for your package manager (ex: set "repository" in package.json)
|
1251 | - configure your git remote 'origin' to point to your project on GitHub.
|
1252 | `, "");
|
1253 | process.exit(1);
|
1254 | }
|
1255 | return author;
|
1256 | }
|
1257 |
|
1258 | getExtendedLocation(config) {
|
1259 | let extendedLocation;
|
1260 | try {
|
1261 | if (config.extends) {
|
1262 | extendedLocation = require.resolve(config.extends);
|
1263 | }
|
1264 | }
|
1265 | catch (error) {
|
1266 | this.logger.veryVerbose.error(error);
|
1267 | }
|
1268 | return extendedLocation;
|
1269 | }
|
1270 | |
1271 |
|
1272 |
|
1273 | loadPlugins(config) {
|
1274 | config.plugins = config.plugins || [is_binary_1.default() ? "git-tag" : "npm"];
|
1275 | const extendedLocation = this.getExtendedLocation(config);
|
1276 | const pluginsPaths = [
|
1277 | require.resolve("./plugins/filter-non-pull-request"),
|
1278 | ...config.plugins,
|
1279 | ];
|
1280 | pluginsPaths
|
1281 | .map((plugin) =>
|
1282 |
|
1283 | typeof plugin === "string" ? [plugin, {}] : plugin)
|
1284 | .map((plugin) => load_plugins_1.loadPlugin(plugin, this.logger, extendedLocation))
|
1285 | .filter((plugin) => Boolean(plugin))
|
1286 | .forEach((plugin) => {
|
1287 | this.logger.verbose.info(`Using ${plugin.name} Plugin...`);
|
1288 | plugin.apply(this);
|
1289 | });
|
1290 | }
|
1291 |
|
1292 | async getPrEnvInfo() {
|
1293 | var _a, _b, _c, _d, _e, _f;
|
1294 |
|
1295 | let pr;
|
1296 | let build;
|
1297 | if ("pr" in env && "build" in env) {
|
1298 | ({ pr } = env);
|
1299 | ({ build } = env);
|
1300 | }
|
1301 | else if ("pr" in env && "commit" in env) {
|
1302 | ({ pr } = env);
|
1303 | build = env.commit;
|
1304 | }
|
1305 |
|
1306 |
|
1307 | if (env.isCi && !pr && ((_a = this.git) === null || _a === void 0 ? void 0 : _a.options.owner) && ((_b = this.git) === null || _b === void 0 ? void 0 : _b.options.repo)) {
|
1308 | const commit = await this.git.getSha();
|
1309 | const query = match_sha_to_pr_1.buildSearchQuery((_c = this.git) === null || _c === void 0 ? void 0 : _c.options.owner, (_d = this.git) === null || _d === void 0 ? void 0 : _d.options.repo, [commit]);
|
1310 | if (query) {
|
1311 | const result = await this.git.graphql(query);
|
1312 | if (result === null || result === void 0 ? void 0 : result[`hash_${commit}`]) {
|
1313 | const number = (_f = (_e = result[`hash_${commit}`].edges[0]) === null || _e === void 0 ? void 0 : _e.node) === null || _f === void 0 ? void 0 : _f.number;
|
1314 | if (number) {
|
1315 | pr = String(number);
|
1316 | }
|
1317 | }
|
1318 | }
|
1319 | }
|
1320 | return { pr, build };
|
1321 | }
|
1322 |
|
1323 | getCommandDefault(name) {
|
1324 | if (!this.config) {
|
1325 | return {};
|
1326 | }
|
1327 | const commandConfig = this.config[name];
|
1328 | return typeof commandConfig === "object" ? commandConfig : {};
|
1329 | }
|
1330 | }
|
1331 | exports.default = Auto;
|
1332 |
|
1333 | tslib_1.__exportStar(require("./auto-args"), exports);
|
1334 | var init_2 = require("./init");
|
1335 | Object.defineProperty(exports, "InteractiveInit", { enumerable: true, get: function () { return init_2.default; } });
|
1336 | var get_current_branch_2 = require("./utils/get-current-branch");
|
1337 | Object.defineProperty(exports, "getCurrentBranch", { enumerable: true, get: function () { return get_current_branch_2.getCurrentBranch; } });
|
1338 | var validate_config_2 = require("./validate-config");
|
1339 | Object.defineProperty(exports, "validatePluginConfiguration", { enumerable: true, get: function () { return validate_config_2.validatePluginConfiguration; } });
|
1340 | var auto_1 = require("./auto");
|
1341 | Object.defineProperty(exports, "Auto", { enumerable: true, get: function () { return auto_1.default; } });
|
1342 | var semver_4 = require("./semver");
|
1343 | Object.defineProperty(exports, "SEMVER", { enumerable: true, get: function () { return semver_4.default; } });
|
1344 | var exec_promise_2 = require("./utils/exec-promise");
|
1345 | Object.defineProperty(exports, "execPromise", { enumerable: true, get: function () { return exec_promise_2.default; } });
|
1346 | var get_lerna_packages_1 = require("./utils/get-lerna-packages");
|
1347 | Object.defineProperty(exports, "getLernaPackages", { enumerable: true, get: function () { return get_lerna_packages_1.default; } });
|
1348 | var in_folder_1 = require("./utils/in-folder");
|
1349 | Object.defineProperty(exports, "inFolder", { enumerable: true, get: function () { return in_folder_1.default; } });
|
1350 |
|
\ | No newline at end of file |