UNPKG

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