UNPKG

11.9 kBJavaScriptView Raw
1"use strict";
2/* eslint-disable no-await-in-loop, @typescript-eslint/ban-ts-ignore */
3Object.defineProperty(exports, "__esModule", { value: true });
4const tslib_1 = require("tslib");
5const endent_1 = tslib_1.__importDefault(require("endent"));
6const enquirer_1 = require("enquirer");
7const make_hooks_1 = require("./utils/make-hooks");
8const release_1 = require("./release");
9const semver_1 = tslib_1.__importDefault(require("./semver"));
10const load_plugins_1 = require("./utils/load-plugins");
11const fs_1 = require("fs");
12/** Get label configuration from the user. */
13async function getLabel(label) {
14 const response = await enquirer_1.prompt({
15 type: "snippet",
16 name: "value",
17 message: label ? `Edit "${label.name}" label:` : "Add a label:",
18 template: label
19 ? endent_1.default `{
20 name: #{name:${label.name}},
21 ${label.changelogTitle
22 ? `changelogTitle: #{changelogTitle:${label.changelogTitle}},`
23 : ""}
24 description: #{description:${label.description}},
25 releaseType: #{releaseType:${label.releaseType}}
26 }`
27 : endent_1.default `{
28 name: #{name},
29 changelogTitle: #{changelogTitle},
30 description: #{description},
31 releaseType: #{releaseType}
32 }`,
33 // @ts-ignore
34 validate: (state) => {
35 if (!state.values.name) {
36 return "name is required for new label";
37 }
38 const releaseTypes = [
39 semver_1.default.major,
40 semver_1.default.minor,
41 semver_1.default.patch,
42 "none",
43 "skip",
44 "release",
45 ];
46 if (state.values.releaseType &&
47 !releaseTypes.includes(state.values.releaseType)) {
48 return `Release type can only be one of the following: ${releaseTypes.join(", ")}`;
49 }
50 return true;
51 },
52 });
53 return response.value.values[0];
54}
55/** Get any custom labels from the user */
56async function getAdditionalLabels() {
57 const labels = [];
58 let addLabels = await enquirer_1.prompt({
59 type: "confirm",
60 name: "confirmed",
61 message: "Would you like to add more labels?",
62 initial: "no",
63 });
64 while (addLabels.confirmed) {
65 labels.push(await getLabel());
66 addLabels = await enquirer_1.prompt({
67 type: "confirm",
68 name: "confirmed",
69 message: "Would you like to add another label?",
70 initial: "no",
71 });
72 }
73 return labels;
74}
75/** Get default label overrides */
76async function getCustomizedDefaultLabels() {
77 const labels = [];
78 const addLabels = await enquirer_1.prompt({
79 type: "confirm",
80 name: "confirmed",
81 message: "Would you like to use customize the default labels?",
82 initial: "no",
83 });
84 if (addLabels.confirmed) {
85 await release_1.defaultLabels.reduce(async (last, defaultLabel) => {
86 await last;
87 const newLabel = await getLabel(defaultLabel);
88 if (JSON.stringify(newLabel) !== JSON.stringify(defaultLabel)) {
89 labels.push(Object.assign(Object.assign({}, newLabel), { overwrite: true }));
90 }
91 }, Promise.resolve());
92 }
93 return labels;
94}
95/** Get the plugins the user wants to use */
96async function getPlugins() {
97 const releasePlugins = {
98 "Chrome Web Store": "chrome",
99 "Rust Crate": "crates",
100 "Git Tag": "git-tag",
101 "npm Package": "npm",
102 Maven: "maven",
103 };
104 const releasePlugin = await enquirer_1.prompt({
105 type: "select",
106 name: "value",
107 required: true,
108 message: "What package manager plugin would you like to publish your project with?",
109 choices: Object.keys(releasePlugins),
110 });
111 const featurePlugin = await enquirer_1.prompt({
112 type: "multiselect",
113 name: "value",
114 required: true,
115 message: "What other plugins would you like to use?",
116 choices: [
117 {
118 name: "all-contributors",
119 message: "All Contributors - Automatically add contributors as changelogs are produced",
120 },
121 {
122 name: "conventional-commits",
123 message: "Conventional Commits - Parse conventional commit messages",
124 },
125 {
126 name: "first-time-contributor",
127 message: "First Time Contributor - Thank first time contributors for their work right in your release notes",
128 },
129 {
130 name: "jira",
131 message: "Jira - Include Jira story information",
132 },
133 {
134 name: "released",
135 message: "Released - Mark PRs as released",
136 },
137 {
138 name: "slack",
139 message: "Slack - Post your release notes to a slack channel",
140 },
141 {
142 name: "twitter",
143 message: "Twitter - Post tweets after a release is made",
144 },
145 ],
146 });
147 return [
148 releasePlugins[releasePlugin.value],
149 ...featurePlugin.value,
150 ];
151}
152/** Get env vars, create .env file, add to .gitignore */
153async function createEnv(hook) {
154 let currentEnv;
155 try {
156 currentEnv = fs_1.readFileSync(".env", { encoding: "utf8" });
157 }
158 catch (error) {
159 currentEnv = "";
160 }
161 const env = (await hook.promise([])).filter((envVar) => !currentEnv.includes(envVar.variable));
162 if (env.length === 0) {
163 return;
164 }
165 const shouldCreateEnv = await enquirer_1.prompt({
166 type: "confirm",
167 name: "confirmed",
168 message: "Would you like to create an .env file? This makes it easy to test and use auto locally.",
169 initial: "yes",
170 });
171 if (!shouldCreateEnv.confirmed) {
172 return;
173 }
174 // Get user input for each variable
175 await env.reduce(async (last, envVar) => {
176 await last;
177 const token = await enquirer_1.prompt({
178 type: "input",
179 name: "value",
180 message: envVar.message,
181 required: true,
182 });
183 currentEnv += `${envVar.variable}=${token.value}\n`;
184 }, Promise.resolve());
185 fs_1.writeFileSync(".env", currentEnv);
186 let gitIgnore;
187 try {
188 gitIgnore = fs_1.readFileSync(".env", { encoding: "utf8" });
189 }
190 catch (error) {
191 gitIgnore = "";
192 }
193 // Add env to gitignore if not already there
194 if (!gitIgnore.includes(".env")) {
195 fs_1.writeFileSync(".env", gitIgnore ? `${gitIgnore}\n.env` : ".env");
196 }
197}
198/**
199 * Parse the gitlog for commits that are PRs and attach their labels.
200 * This class can also be tapped into via plugin to parse commits
201 * in other ways (ex: conventional-commits)
202 */
203class InteractiveInit {
204 /** Initialize the the init prompter and tap the default functionality */
205 constructor(options) {
206 this.hooks = make_hooks_1.makeInteractiveInitHooks();
207 this.logger = options.logger;
208 }
209 /** Run a prompt to get the author information */
210 async getAuthorInformation() {
211 const response = await enquirer_1.prompt({
212 type: "snippet",
213 name: "author",
214 message: `What git user would you like to make commits with?`,
215 required: true,
216 template: endent_1.default `
217 Name: #{name}
218 Email: #{email}`,
219 });
220 return response.author.values;
221 }
222 /** Run a prompt to get the repo information */
223 async getRepoInformation() {
224 const response = await enquirer_1.prompt({
225 type: "snippet",
226 name: "repoInfo",
227 message: `What GitHub project you would like to publish?`,
228 required: true,
229 template: endent_1.default `#{owner}/#{repo}`,
230 });
231 console.log(response);
232 return response.repoInfo.values;
233 }
234 /** Load the default behavior */
235 tapDefaults() {
236 this.hooks.getRepo.tapPromise("Init Default", this.getRepoInformation);
237 this.hooks.getAuthor.tapPromise("Init Default", this.getAuthorInformation);
238 this.hooks.createEnv.tap("Init Default", (vars) => [
239 ...vars,
240 {
241 variable: "GH_TOKEN",
242 message: `Enter a personal access token for the GitHub API https://github.com/settings/tokens/new`,
243 },
244 ]);
245 this.hooks.writeRcFile.tap("Init Default", (rc) => {
246 const filename = ".autorc";
247 fs_1.writeFileSync(filename, JSON.stringify(rc, null, 2));
248 this.logger.log.success(`Wrote configuration to: ${filename}`);
249 });
250 }
251 /** Run the initialization. */
252 async run() {
253 let autoRc = {};
254 const plugins = await getPlugins();
255 if (plugins) {
256 plugins
257 .map((name) => load_plugins_1.loadPlugin([name, {}], this.logger))
258 .forEach((plugin) => {
259 if (plugin === null || plugin === void 0 ? void 0 : plugin.init) {
260 plugin.init(this);
261 }
262 });
263 autoRc.plugins = await plugins.reduce(async (last, plugin) => {
264 return [
265 ...(await last),
266 (await this.hooks.configurePlugin.promise(plugin)) || plugin,
267 ];
268 }, Promise.resolve([]));
269 }
270 this.tapDefaults();
271 const repoInfo = await this.hooks.getRepo.promise();
272 if (typeof repoInfo === "object") {
273 autoRc = Object.assign(Object.assign({}, autoRc), repoInfo);
274 }
275 const author = await this.hooks.getAuthor.promise();
276 if (typeof author === "object") {
277 autoRc = Object.assign(Object.assign({}, autoRc), author);
278 }
279 const onlyPublishWithReleaseLabel = await enquirer_1.prompt({
280 type: "confirm",
281 name: "confirmed",
282 message: 'Only make releases if "release" label is on pull request?',
283 initial: "no",
284 });
285 if (onlyPublishWithReleaseLabel.confirmed) {
286 autoRc = Object.assign(Object.assign({}, autoRc), { onlyPublishWithReleaseLabel: true });
287 }
288 const isEnterprise = await enquirer_1.prompt({
289 type: "confirm",
290 name: "confirmed",
291 message: "Are you using an enterprise instance of GitHub?",
292 initial: "no",
293 });
294 if (isEnterprise.confirmed) {
295 const response = await enquirer_1.prompt({
296 type: "snippet",
297 name: "repoInfo",
298 message: `What are the api URLs for your GitHub enterprise instance?`,
299 required: true,
300 // @ts-ignore
301 template: endent_1.default `
302 GitHub API: #{githubApi}
303 Graphql API: #{githubGraphqlApi}`,
304 });
305 autoRc = Object.assign(Object.assign({}, autoRc), response.repoInfo.values);
306 }
307 await createEnv(this.hooks.createEnv);
308 const newLabels = [
309 ...(await getCustomizedDefaultLabels()),
310 ...(await getAdditionalLabels()),
311 ];
312 if (newLabels.length > 0) {
313 autoRc.labels = [...(autoRc.labels || []), ...newLabels];
314 }
315 await this.hooks.writeRcFile.promise(autoRc);
316 this.logger.log.note(endent_1.default `
317 Next steps:
318
319 - Run "auto create-labels" to create your labels on GitHub
320 - Add your environment variables to your CI builds
321 - Add "auto shipit" at the end of you build/release process\n
322 `);
323 }
324}
325exports.default = InteractiveInit;
326//# sourceMappingURL=init.js.map
\No newline at end of file