|
1 | 1 | #!/usr/bin/env node
|
2 | 2 | "use strict";
|
3 | 3 |
|
4 |
| -const fs = require("fs"), |
5 |
| - iq = require("inquirer"), |
6 |
| - octonode = require("octonode"), |
7 |
| - gitLabel = require("git-label"), |
8 |
| - readRepo = require("./components/read-repo"), |
9 |
| - cleanup = require("./components/remove-tmp-pkg"), |
10 |
| - mainPrompts = require("./components/main-prompts"), |
11 |
| - customAddPrompts = require("./components/add-prompts"); |
| 4 | +// EXTERNAL DEPENDENCIES |
| 5 | +const fs = require("fs"), |
| 6 | + iq = require("inquirer"), |
| 7 | + gitLabel = require("git-label"); |
| 8 | +// UTILS ARE STANDALONE METHODS WITH NO DEPENDENCIES |
| 9 | +const alertDeletes = require("./utils/alertDeletes"), |
| 10 | + banner = require("./utils/banners"), |
| 11 | + configGitLabel = require("./utils/configGitLabel"), |
| 12 | + filterRemovalLabels = require("./utils/filterRemovalLabels"), |
| 13 | + removeAll = require("./utils/removeAll"), |
| 14 | + validateRemovals = require("./utils/validateRemovals"); |
| 15 | +// PROMPTS ARE THE PROMPTS ARRAYS FOR VARIOUS QUESTIONS |
| 16 | +const prompts = { |
| 17 | + addCustom: require("./prompts/addCustom"), |
| 18 | + deleteConfirm: require("./prompts/deleteConfirm"), |
| 19 | + mainMenu: require("./prompts/mainMenu") |
| 20 | + }; |
| 21 | +// MODULES ARE UTILS WITH DEPENDENCIES |
| 22 | +const doCustomLabelPrompts = require("./modules/doCustomLabelPrompts")(prompts.addCustom), |
| 23 | + readRepo = require("./modules/readRepo"), |
| 24 | + setToken = require("./modules/setToken"), |
| 25 | + fetchToken = require("./modules/fetchToken"), |
| 26 | + isGitRepo = require("./modules/isGitRepo"), |
| 27 | + readGitConfig = require("./modules/readGitConfig"), |
| 28 | + requestLabels = require("./modules/requestLabels"), |
| 29 | + prompt = require("./modules/prompt"), |
| 30 | + validateAddPackages = require("./modules/validateAddPackages"); |
12 | 31 |
|
13 |
| -// TODO: this should be a util |
14 |
| -const replaceAll = (str, find, replace) => str.split(find).join(replace); |
15 | 32 |
|
16 |
| -// Responsible for fetching and returning our config/token |
17 |
| -const fetchToken = () => { |
18 |
| - return new Promise((res, rej)=>{ |
19 |
| - fs.readFile(__dirname+"/.token.json", 'utf8', (e, data) => { |
20 |
| - if (e) rej("No token.json file found!"); |
21 |
| - if (JSON.parse(data).token === "") rej("No token found!"); |
22 |
| - res(JSON.parse(data).token); |
23 |
| - }); |
24 |
| - }); |
25 |
| - }; |
26 |
| -// Responsible for asking the user what their token is, and then storing it |
27 |
| -// executed only if it can't be found! |
28 |
| -const setToken = (done) => { |
29 |
| - iq.prompt([{ |
30 |
| - type: "input", |
31 |
| - name: "token", |
32 |
| - message: "What is your GitHub Access Token?", |
33 |
| - default: "eg: 12345678..." |
34 |
| - }], (answer) => { |
35 |
| - fs.writeFile( __dirname+'/.token.json', JSON.stringify( { "token": answer.token }, null, 2 ), 'utf8', (e)=>{ |
36 |
| - if (e) throw e; |
37 |
| - console.log("Stored new token!"); |
38 |
| - done(answer.token); |
39 |
| - }); |
40 |
| - }); |
41 |
| - }; |
42 |
| -// Recursivly asks if you want to add another new label, then calls a callback when youre all done |
43 |
| -const doCustomLabelPrompts = ( newLabels, done ) => { |
44 |
| - iq.prompt( customAddPrompts, ( answers ) => { |
45 |
| - newLabels.push({ name: answers.labelName, color: answers.labelColor }); |
46 |
| - if ( answers.addAnother ){ |
47 |
| - doCustomLabelPrompts( newLabels, done ); |
48 |
| - }else{ |
49 |
| - done( newLabels ); |
50 |
| - } |
51 |
| - }); |
52 |
| - }; |
| 33 | +// resetToken function |
| 34 | +const resetToken = () => { |
| 35 | + banner.resetToken(); |
| 36 | + return setToken(gitLabelmaker); |
| 37 | +}; |
53 | 38 |
|
54 |
| -const doPackageLabelPrompts = ( done ) => { |
55 |
| - iq.prompt([ |
56 |
| - { |
57 |
| - name: "type", |
58 |
| - type: "list", |
59 |
| - message: "Do you want to use a local package or choose from a list of common label packages?", |
60 |
| - choices: [ "Local", "Packages" ] |
61 |
| - },{ |
62 |
| - name: "pkgs", |
63 |
| - type: "checkbox", |
64 |
| - message: "Which packages would you like to use?", |
65 |
| - choices: [ |
66 |
| - "git-label-packages:cla", |
67 |
| - "git-label-packages:priority", |
68 |
| - "git-label-packages:status", |
69 |
| - "git-label-packages:type" |
70 |
| - ], |
71 |
| - when: (answers) => { |
72 |
| - return answers.type.toLowerCase() === "packages"; |
73 |
| - } |
74 |
| - } |
75 |
| - ], (ans) => { |
76 |
| - console.log(ans); |
77 |
| - // if (ans.) |
78 |
| - // done(); |
79 |
| - }); |
80 |
| - }; |
| 39 | +// addCustom labels function |
| 40 | +const addCustom = (repo, token) => { |
| 41 | + banner.addCustom(); |
| 42 | + return doCustomLabelPrompts( [], (newLabels) => { |
| 43 | + gitLabel.add( configGitLabel(repo, token), newLabels ) |
| 44 | + .then(console.log) |
| 45 | + .catch(console.warn); |
| 46 | + }); |
| 47 | +}; |
81 | 48 |
|
82 |
| -const doRemovePrompts = ( token, repo ) => { |
83 |
| - octonode.client(token).get('/repos/'+repo+'/labels', (e, status, body) => { |
84 |
| - iq.prompt([{ |
85 |
| - name: "removals", |
86 |
| - type: "checkbox", |
87 |
| - message: "Which labels would you like to remove?", |
88 |
| - choices: body.map((label) => label.name), |
89 |
| - filter: (removals) => { |
90 |
| - return body.filter((label) => { |
91 |
| - return removals.indexOf(label.name) > -1 ? { name: label.name, color: label.color } : false; |
92 |
| - }); |
93 |
| - } |
94 |
| - }], (answers) => { |
95 |
| - gitLabel.remove( configGitLabel(repo, token), answers.removals ) |
96 |
| - .then(console.log) |
97 |
| - .catch(console.warn); |
98 |
| - }); |
99 |
| - }); |
100 |
| - }; |
| 49 | +// addFromPackage function |
| 50 | +const addFromPackage = (repo, token, path) => { |
| 51 | + gitLabel.find( removeAll( path, [ "`", '"', "'" ] ) ) |
| 52 | + .then((newLabels)=>{ |
| 53 | + return gitLabel.add( configGitLabel(repo, token), newLabels ) |
| 54 | + }) |
| 55 | + .then(console.log) |
| 56 | + .catch(console.warn); |
| 57 | +}; |
101 | 58 |
|
102 |
| -// Promise-based check to see if we're even in a Git repo |
103 |
| -const isGitRepo = () => { |
104 |
| - return new Promise((res, rej) => { |
105 |
| - fs.readdir(process.cwd()+'/.git/', (e, files) => { |
106 |
| - if (e) rej(false); |
107 |
| - res(true); |
108 |
| - }) |
109 |
| - }); |
110 |
| - }; |
111 |
| -// Promise-based reading the git config to find the repo |
112 |
| -const readGitConfig = () => { |
113 |
| - return new Promise((res, rej)=>{ |
114 |
| - fs.readFile( process.cwd()+'/.git/config', 'utf8', (e, data) => { |
115 |
| - if (e) rej(e); |
116 |
| - res( data );// split it at newlines |
117 |
| - }) |
118 |
| - }); |
119 |
| - }; |
120 |
| -// Returns a config for gitLabel |
121 |
| -const configGitLabel = (repo, token) => { |
122 |
| - return { |
123 |
| - api: 'https://api.github.com', |
124 |
| - repo: repo, |
125 |
| - token: token |
126 |
| - } |
127 |
| - }; |
| 59 | +// removeLabels function |
| 60 | +const removeLabels = (repo, token, answers) => { |
| 61 | + // Tell the user what they're about to lose |
| 62 | + console.log("About to delete the following labels:") |
| 63 | + alertDeletes(answers.removals);// alerts the list of labels to be removed |
| 64 | + // Ya sure ya wanna do this bud? |
| 65 | + prompt(prompts.deleteConfirm) |
| 66 | + .then((confirmRemove)=>{ |
| 67 | + if ( confirmRemove.youSure ) { |
| 68 | + return gitLabel.remove( configGitLabel(repo, token), answers.removals ) |
| 69 | + } |
| 70 | + gitLabelmaker(); |
| 71 | + }) |
| 72 | + .then(console.log) |
| 73 | + .catch(console.warn); |
| 74 | +}; |
128 | 75 |
|
129 |
| -// TODO: could be refactored to return the git.add as a promise..? |
130 |
| -const handleAddPrompts = (repo, token, newLabels) => { |
131 |
| - gitLabel.add( configGitLabel(repo, token), newLabels ) |
132 |
| - .then(console.log) |
133 |
| - .catch(console.warn); |
134 |
| - }; |
| 76 | +// Callback for the main prompts, handles program flow |
| 77 | +const handleMainPrompts = (repo, token, ans) => { |
| 78 | + switch ( ans.main.toLowerCase() ) { |
| 79 | + case "reset token": |
| 80 | + resetToken(); |
| 81 | + break; |
135 | 82 |
|
136 |
| -const handleMainPrompts = (repo, ans) => { |
137 |
| - if ( ans.main.toLowerCase() === "reset token" ){ |
138 |
| - // process will end after new token is set |
139 |
| - return setToken((token) => { |
140 |
| - iq.prompt( mainPrompts, handleMainPrompts.bind(null, repo)); |
141 |
| - }); |
142 |
| - } |
143 |
| - // if it's not to reset the token then we |
144 |
| - fetchToken() |
145 |
| - .then((token)=>{ |
146 |
| - if ( ans.main.toLowerCase() === "add custom labels" ){ |
147 |
| - return doCustomLabelPrompts( [], handleAddPrompts.bind(null, repo, token)); |
148 |
| - } |
149 |
| - if ( ans.main.toLowerCase() === "add labels from package" ){ |
150 |
| - // return doPackageLabelPrompts( handleAddPrompts.bind(null, repo, token) ); |
151 |
| - let packagePath; |
152 |
| - iq.prompt([{ |
153 |
| - name: "path", |
154 |
| - type: "input", |
155 |
| - message: "What is the path & name of the package you want to use? (eg: `packages/my-label-pkg.json`)", |
156 |
| - validate: (path) => { |
157 |
| - try { |
158 |
| - if (path.indexOf(".json") < 0) throw "Not a JSON file"; |
159 |
| - packagePath = path.indexOf("/") === 0 ? path.replace("/","") : path; |
160 |
| - // TODO: make that fn loop over an array of replaces, or make it REMOVEALL and ditch that 3rd param |
161 |
| - packagePath = replaceAll( replaceAll( replaceAll(packagePath, '`', ""), '"', "" ), "'", "" ) |
162 |
| - if ( fs.statSync( process.cwd()+"/"+packagePath ) ){ |
163 |
| - return true; |
164 |
| - } |
165 |
| - } catch (e){ |
166 |
| - return e; |
167 |
| - } |
168 |
| - } |
169 |
| - }], (ans) => { |
170 |
| - gitLabel.find( replaceAll( replaceAll( replaceAll(ans.path, '`', ""), '"', "" ), "'", "" ) ) |
171 |
| - .then((newLabels)=>{ |
172 |
| - return gitLabel.add( configGitLabel(repo, token), newLabels ) |
173 |
| - }) |
174 |
| - .then(console.log) |
175 |
| - .catch(console.warn); |
176 |
| - }); |
177 |
| - } |
178 |
| - if ( ans.main.toLowerCase() === "remove labels" ){ |
179 |
| - doRemovePrompts(token, repo); |
180 |
| - } |
181 |
| - }) |
182 |
| - .catch((msg)=>{ |
183 |
| - console.log(msg); |
184 |
| - setToken((token) => { |
185 |
| - iq.prompt( mainPrompts, handleMainPrompts.bind(null, repo)); |
186 |
| - }); |
187 |
| - }); |
188 |
| - }; |
| 83 | + case "add custom labels": |
| 84 | + addCustom(repo, token); |
| 85 | + break; |
189 | 86 |
|
| 87 | + case "add labels from package": |
| 88 | + banner.addFromPackage(); |
| 89 | + prompt([{ |
| 90 | + name: "path", |
| 91 | + type: "input", |
| 92 | + message: "What is the path & name of the package you want to use? (eg: `packages/my-label-pkg.json`)", |
| 93 | + validate: validateAddPackages |
| 94 | + }]) |
| 95 | + .then((ans)=>{ |
| 96 | + return addFromPackage( repo, token, ans.path ); |
| 97 | + }) |
| 98 | + .catch(console.warn); |
| 99 | + break; |
190 | 100 |
|
191 |
| -// LET'S DO IT |
192 |
| - Promise.all([ isGitRepo(), readGitConfig() ]) |
193 |
| - .then(( values )=>{ |
194 |
| - let repo = readRepo(values[1].split("\n")); |
195 |
| - iq.prompt( mainPrompts, handleMainPrompts.bind(null, repo)); |
196 |
| - }) |
197 |
| - .catch((e)=>{ |
198 |
| - console.warn(e); |
199 |
| - console.warn("Please run git-labelmaker from inside a git repo!") |
| 101 | + case "remove labels": |
| 102 | + banner.removeLabels(); |
| 103 | + requestLabels(repo, token) |
| 104 | + .then((labels)=>{ |
| 105 | + return prompt([{ |
| 106 | + name: "removals", |
| 107 | + type: "checkbox", |
| 108 | + message: "Which labels would you like to remove?", |
| 109 | + choices: labels.map((label) => label.name), |
| 110 | + validate: validateRemovals, |
| 111 | + filter: filterRemovalLabels.bind(null, labels) |
| 112 | + }]); |
| 113 | + }) |
| 114 | + .then((answers)=>{ |
| 115 | + removeLabels(repo, token, answers); |
| 116 | + }) |
| 117 | + .catch(console.warn); |
| 118 | + break; |
| 119 | + |
| 120 | + default: |
| 121 | + gitLabelmaker(); |
| 122 | + }; |
| 123 | + }; |
| 124 | + |
| 125 | +// Kicks things off, named so that it can be called at any time |
| 126 | +const gitLabelmaker = () => { |
| 127 | + // Checks for three things at once, each will return a nice error obj if they fail |
| 128 | + Promise.all([ isGitRepo(), readGitConfig(), fetchToken() ]) |
| 129 | + .then(( values )=>{ |
| 130 | + let repo = readRepo(values[1]); |
| 131 | + let token = values[2]; |
| 132 | + banner.welcome(); |
| 133 | + iq.prompt( prompts.mainMenu, handleMainPrompts.bind(null, repo, token)); |
| 134 | + }) |
| 135 | + .catch((e)=>{ |
| 136 | + console.warn(e.err); |
| 137 | + if (e.id === "TOKEN") { |
| 138 | + setToken(gitLabelmaker); |
| 139 | + } else { |
200 | 140 | process.exit(1);
|
201 |
| - }); |
| 141 | + } |
| 142 | + }); |
| 143 | +}; |
| 144 | + |
| 145 | +gitLabelmaker(); |
0 commit comments