1 | /* eslint no-console: 0 */
|
2 | const { getAddons, createAddon } = require('netlify/src/addons')
|
3 | // const chalk = require("chalk");
|
4 | // const fetch = require("node-fetch");
|
5 |
|
6 | /** main section - shamelessly adapted from CLI. we can extract and dedupe later. */
|
7 | /** but we can DRY things up later. */
|
8 | // eslint-disable-next-line max-params
|
9 | module.exports.createSiteAddon = async function(accessToken, addonName, siteId, siteData, log) {
|
10 | const addons = await getAddons(siteId, accessToken)
|
11 | if (typeof addons === 'object' && addons.error) {
|
12 | log('API Error', addons)
|
13 | return false
|
14 | }
|
15 | // Filter down addons to current args.name
|
16 | const currentAddon = addons.find(addon => addon.service_path === `/.netlify/${addonName}`)
|
17 | const rawFlags = {}
|
18 |
|
19 | if (currentAddon && currentAddon.id) {
|
20 | log(`The "${addonName} add-on" already exists for ${siteData.name}`)
|
21 | // // just exit
|
22 | // log()
|
23 | // const cmd = chalk.cyan(`\`netlify addons:config ${addonName}\``)
|
24 | // log(`- To update this add-on run: ${cmd}`)
|
25 | // const deleteCmd = chalk.cyan(`\`netlify addons:delete ${addonName}\``)
|
26 | // log(`- To remove this add-on run: ${deleteCmd}`)
|
27 | // log()
|
28 | return false
|
29 | }
|
30 |
|
31 | // const manifest = await getAddonManifest(addonName, accessToken);
|
32 |
|
33 | let configValues = rawFlags
|
34 | // if (manifest.config) {
|
35 | // const required = requiredConfigValues(manifest.config);
|
36 | // console.log(`Starting the setup for "${addonName} add-on"`);
|
37 | // console.log();
|
38 |
|
39 | // // const missingValues = missingConfigValues(required, rawFlags);
|
40 | // // if (Object.keys(rawFlags).length) {
|
41 | // // const newConfig = updateConfigValues(manifest.config, {}, rawFlags)
|
42 |
|
43 | // // if (missingValues.length) {
|
44 | // // /* Warn user of missing required values */
|
45 | // // console.log(
|
46 | // // `${chalk.redBright.underline.bold(`Error: Missing required configuration for "${addonName} add-on"`)}`
|
47 | // // )
|
48 | // // console.log()
|
49 | // // render.missingValues(missingValues, manifest)
|
50 | // // console.log()
|
51 | // // const msg = `netlify addons:create ${addonName}`
|
52 | // // console.log(`Please supply the configuration values as CLI flags`)
|
53 | // // console.log()
|
54 | // // console.log(`Alternatively, you can run ${chalk.cyan(msg)} with no flags to walk through the setup steps`)
|
55 | // // console.log()
|
56 | // // return false
|
57 | // // }
|
58 |
|
59 | // // await createSiteAddon({
|
60 | // // addonName,
|
61 | // // settings: {
|
62 | // // siteId: siteId,
|
63 | // // addon: addonName,
|
64 | // // config: newConfig
|
65 | // // },
|
66 | // // accessToken,
|
67 | // // siteData
|
68 | // // })
|
69 | // // return false
|
70 | // // }
|
71 |
|
72 | // const words = `The ${addonName} add-on has the following configurable options:`;
|
73 | // console.log(` ${chalk.yellowBright.bold(words)}`);
|
74 | // render.configValues(addonName, manifest.config);
|
75 | // console.log();
|
76 | // console.log(` ${chalk.greenBright.bold("Lets configure those!")}`);
|
77 |
|
78 | // console.log();
|
79 | // console.log(
|
80 | // ` - Hit ${chalk.white.bold("enter")} to confirm value or set empty value`
|
81 | // );
|
82 | // console.log(
|
83 | // ` - Hit ${chalk.white.bold("ctrl + C")} to cancel & exit configuration`
|
84 | // );
|
85 | // console.log();
|
86 |
|
87 | // const prompts = generatePrompts({
|
88 | // config: manifest.config,
|
89 | // configValues: rawFlags
|
90 | // });
|
91 |
|
92 | // const userInput = await inquirer.prompt(prompts);
|
93 | // // Merge user input with the flags specified
|
94 | // configValues = updateConfigValues(manifest.config, rawFlags, userInput);
|
95 | // const missingRequiredValues = missingConfigValues(required, configValues);
|
96 | // if (missingRequiredValues && missingRequiredValues.length) {
|
97 | // missingRequiredValues.forEach(val => {
|
98 | // console.log(
|
99 | // `Missing required value "${val}". Please run the command again`
|
100 | // );
|
101 | // });
|
102 | // return false;
|
103 | // }
|
104 | // }
|
105 |
|
106 | await actuallyCreateSiteAddon({
|
107 | addonName,
|
108 | settings: {
|
109 | siteId: siteId,
|
110 | addon: addonName,
|
111 | config: configValues
|
112 | },
|
113 | accessToken,
|
114 | siteData
|
115 | })
|
116 | return addonName // we dont really use this right now but may be helpful to know that an addon installation was successful
|
117 | }
|
118 |
|
119 | async function actuallyCreateSiteAddon({ addonName, settings, accessToken, siteData }) {
|
120 | const addonResponse = await createAddon(settings, accessToken)
|
121 |
|
122 | if (addonResponse.code === 404) {
|
123 | console.log(`No add-on "${addonName}" found. Please double check your add-on name and try again`)
|
124 | return false
|
125 | }
|
126 | console.log(`Add-on "${addonName}" created for ${siteData.name}`)
|
127 | if (addonResponse.config && addonResponse.config.message) {
|
128 | console.log()
|
129 | console.log(`${addonResponse.config.message}`)
|
130 | }
|
131 | return addonResponse
|
132 | }
|
133 |
|
134 | /** all the utils used in the main section */
|
135 |
|
136 | // async function getAddonManifest(addonName, netlifyApiToken) {
|
137 | // const url = `https://api.netlify.com/api/v1/services/${addonName}/manifest`;
|
138 | // const response = await fetch(url, {
|
139 | // method: "GET",
|
140 | // headers: {
|
141 | // "Content-Type": "application/json",
|
142 | // Authorization: `Bearer ${netlifyApiToken}`
|
143 | // }
|
144 | // });
|
145 |
|
146 | // const data = await response.json();
|
147 |
|
148 | // if (response.status === 422) {
|
149 | // throw new Error(`Error ${JSON.stringify(data)}`);
|
150 | // }
|
151 |
|
152 | // return data;
|
153 | // }
|
154 |
|
155 | // function requiredConfigValues(config) {
|
156 | // return Object.keys(config).filter(key => {
|
157 | // return config[key].required;
|
158 | // });
|
159 | // }
|
160 |
|
161 | // function missingConfigValues(requiredConfig, providedConfig) {
|
162 | // return requiredConfig.filter(key => {
|
163 | // return !providedConfig[key];
|
164 | // });
|
165 | // }
|
166 |
|
167 | // function missingConfigValues(allowedConfig, currentConfig, newConfig) {
|
168 | // return Object.keys(allowedConfig).reduce((acc, key) => {
|
169 | // if (newConfig[key]) {
|
170 | // acc[key] = newConfig[key];
|
171 | // return acc;
|
172 | // }
|
173 | // acc[key] = currentConfig[key];
|
174 | // return acc;
|
175 | // }, {});
|
176 | // }
|
177 |
|
178 | // const chalk = require('chalk')
|
179 |
|
180 | // /* programmatically generate CLI prompts */
|
181 | // function generatePrompts(settings) {
|
182 | // const { config, configValues } = settings;
|
183 | // const configItems = Object.keys(config);
|
184 |
|
185 | // const prompts = configItems
|
186 | // .map((key, i) => {
|
187 | // const setting = config[key];
|
188 | // // const { type, displayName } = setting
|
189 | // let prompt;
|
190 | // // Tell user to use types
|
191 | // if (!setting.type) {
|
192 | // console.log(
|
193 | // `⚠️ ${chalk.yellowBright(
|
194 | // `Warning: no \`type\` is set for config key: ${configItems[i]}`
|
195 | // )}`
|
196 | // );
|
197 | // console.log(
|
198 | // `It's highly recommended that you type your configuration values. It will help with automatic documentation, sharing of your services, and make your services configurable through a GUI`
|
199 | // );
|
200 | // console.log("");
|
201 | // }
|
202 |
|
203 | // // Handle shorthand config. Probably will be removed. Severly limited + not great UX
|
204 | // if (typeof setting === "string" || typeof setting === "boolean") {
|
205 | // if (typeof setting === "string") {
|
206 | // prompt = {
|
207 | // type: "input",
|
208 | // name: key,
|
209 | // message: `Enter string value for '${key}':`
|
210 | // };
|
211 | // // if current stage value set show as default
|
212 | // if (configValues[key]) {
|
213 | // prompt.default = configValues[key];
|
214 | // }
|
215 | // } else if (typeof setting === "boolean") {
|
216 | // prompt = {
|
217 | // type: "confirm",
|
218 | // name: key,
|
219 | // message: `Do you want '${key}':`
|
220 | // };
|
221 | // }
|
222 | // return prompt;
|
223 | // }
|
224 |
|
225 | // // For future use. Once UX is decided
|
226 | // // const defaultValidation = (setting.required) ? validateRequired : noValidate
|
227 | // const defaultValidation = noValidate;
|
228 | // const validateFunction = setting.pattern
|
229 | // ? validate(setting.pattern)
|
230 | // : defaultValidation;
|
231 | // const isRequiredText = setting.required
|
232 | // ? ` (${chalk.yellow("required")})`
|
233 | // : "";
|
234 | // if (setting.type === "string" || setting.type.match(/string/)) {
|
235 | // prompt = {
|
236 | // type: "input",
|
237 | // name: key,
|
238 | // message:
|
239 | // `${chalk.white(key)}${isRequiredText} - ${setting.displayName}` ||
|
240 | // `Please enter value for ${key}`,
|
241 | // validate: validateFunction
|
242 | // };
|
243 | // // if value previously set show it
|
244 | // if (configValues[key]) {
|
245 | // prompt.default = configValues[key];
|
246 | // // else show default value if provided
|
247 | // } else if (setting.default) {
|
248 | // prompt.default = setting.default;
|
249 | // }
|
250 | // return prompt;
|
251 | // }
|
252 | // return undefined;
|
253 | // })
|
254 | // .filter(item => {
|
255 | // return typeof item !== "undefined";
|
256 | // });
|
257 | // return prompts;
|
258 | // }
|
259 |
|
260 | // function noValidate() {
|
261 | // return true;
|
262 | // }
|
263 |
|
264 | // function validate(pattern) {
|
265 | // return function(value) {
|
266 | // const regex = new RegExp(pattern);
|
267 | // if (value.match(regex)) {
|
268 | // return true;
|
269 | // }
|
270 | // return `Please enter a value matching regex pattern: /${chalk.yellowBright(
|
271 | // pattern
|
272 | // )}/`;
|
273 | // };
|
274 | // }
|
275 |
|
276 | // const chalk = require('chalk')
|
277 | // const AsciiTable = require("ascii-table");
|
278 |
|
279 | // function missingValues(values, manifest) {
|
280 | // const display = values
|
281 | // .map(item => {
|
282 | // const itemDisplay = chalk.redBright.bold(`${item}`);
|
283 | // const niceNameDisplay = manifest.config[item].displayName;
|
284 | // return ` - ${itemDisplay} ${niceNameDisplay}`;
|
285 | // })
|
286 | // .join("\n");
|
287 | // console.log(display);
|
288 | // }
|
289 |
|
290 | // function configValues(addonName, configValues, currentValue) {
|
291 | // const table = new AsciiTable(`${addonName} add-on settings`);
|
292 |
|
293 | // const tableHeader = currentValue
|
294 | // ? ["Setting Name", "Current Value", "Description"]
|
295 | // : ["Setting Name", "Description", "Type", "Required"];
|
296 |
|
297 | // table.setHeading(...tableHeader);
|
298 |
|
299 | // Object.keys(configValues).map(key => {
|
300 | // const { type, displayName, required } = configValues[key];
|
301 | // let requiredText = required ? `true` : `false`;
|
302 | // const typeInfo = type || "";
|
303 | // const description = displayName || "";
|
304 | // if (currentValue) {
|
305 | // const value = currentValue[key] || "Not supplied";
|
306 | // table.addRow(key, value, description);
|
307 | // } else {
|
308 | // table.addRow(key, description, typeInfo, requiredText);
|
309 | // }
|
310 | // });
|
311 | // console.log(table.toString());
|
312 | // }
|