Skip to content
This repository was archived by the owner on Sep 12, 2019. It is now read-only.

Commit 11eb304

Browse files
authored
Merge pull request #74 from netlify/makeAddonInstallLifecycle
Make addon install lifecycle
2 parents 742d15c + 1447b31 commit 11eb304

File tree

6 files changed

+79
-19
lines changed

6 files changed

+79
-19
lines changed

src/commands/dev/exec.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,20 @@
11
const execa = require('execa')
22
const Command = require('@netlify/cli-utils')
3-
const { getAddons } = require('netlify/src/addons')
43

54
class ExecCommand extends Command {
65
async run() {
76
const { site } = this.netlify
8-
97
if (site.id) {
108
const accessToken = await this.authenticate()
11-
const addons = await getAddons(site.id, accessToken)
12-
addons.forEach(addon => {
13-
for (const key in addon.env) {
14-
process.env[key] = addon.env[key]
15-
}
16-
})
9+
const { addEnvVarsFromAddons } = require('../../utils/dev-exec')
10+
await addEnvVarsFromAddons(site, accessToken)
1711
}
1812
execa(this.argv[0], this.argv.slice(1), { env: process.env, stdio: 'inherit' })
1913
}
2014
}
2115

2216
ExecCommand.description = `Exec command
23-
Runs a command within the netlify dev environment
17+
Runs a command within the netlify dev environment, e.g. with env variables from any installed addons
2418
`
2519

2620
ExecCommand.examples = ['$ netlify exec npm run bootstrap']

src/commands/functions/create.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@ async function downloadFromURL(flags, args, functionsDir) {
230230
const fnTemplateFile = path.join(fnFolder, '.netlify-function-template.js')
231231
if (fs.existsSync(fnTemplateFile)) {
232232
const { onComplete, addons = [] } = require(fnTemplateFile)
233-
installAddons.call(this, addons)
233+
234+
await installAddons.call(this, addons, path.resolve(fnFolder))
234235
if (onComplete) onComplete()
235236
fs.unlinkSync(fnTemplateFile) // delete
236237
}
@@ -273,7 +274,7 @@ async function scaffoldFromTemplate(flags, args, functionsDir) {
273274

274275
const name = await getNameFromArgs(args, flags, templateName)
275276
this.log(`Creating function ${name}`)
276-
const functionPath = ensureFunctionPathIsOk(functionsDir, flags, name)
277+
const functionPath = ensureFunctionPathIsOk.call(this, functionsDir, flags, name)
277278

278279
// // SWYX: note to future devs - useful for debugging source to output issues
279280
// this.log('from ', pathToTemplate, ' to ', functionPath)
@@ -298,13 +299,13 @@ async function scaffoldFromTemplate(flags, args, functionsDir) {
298299
this.log(`installing dependencies for ${name} complete `)
299300
})
300301
}
301-
installAddons.call(this, addons)
302+
installAddons.call(this, addons, path.resolve(functionPath))
302303
if (onComplete) onComplete() // do whatever the template wants to do after it is scaffolded
303304
})
304305
}
305306
}
306307

307-
async function installAddons(addons = []) {
308+
async function installAddons(addons = [], fnPath) {
308309
if (addons.length) {
309310
const { api, site } = this.netlify
310311
const siteId = site.id
@@ -314,10 +315,16 @@ async function installAddons(addons = []) {
314315
}
315316
return api.getSite({ siteId }).then(async siteData => {
316317
const accessToken = await this.authenticate()
317-
const arr = addons.map(addonName => {
318+
const arr = addons.map(({ addonName, addonDidInstall }) => {
318319
this.log('installing addon: ' + addonName)
319320
// will prompt for configs if not supplied - we do not yet allow for addon configs supplied by `netlify functions:create` command and may never do so
320-
return createSiteAddon(accessToken, addonName, siteId, siteData, this.log)
321+
return createSiteAddon(accessToken, addonName, siteId, siteData, this.log).then(async addonCreateMsg => {
322+
if (addonCreateMsg && addonDidInstall) {
323+
const { addEnvVarsFromAddons } = require('../../utils/dev-exec')
324+
await addEnvVarsFromAddons(site, accessToken)
325+
addonDidInstall(fnPath)
326+
}
327+
})
321328
})
322329
return Promise.all(arr)
323330
})

src/functions-templates/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,29 @@
22

33
place new templates here and our CLI will pick it up. each template must be in its own folder.
44

5+
## not a long term solution
6+
7+
we dont want people to update their CLI every time we add a template. see https://github.com/netlify/netlify-dev-plugin/issues/42 for how we may solve in future
8+
9+
## template lifecycles
10+
11+
- onComplete
12+
- meant for messages, logging, light cleanup
13+
- onAllAddonsInstalled?
14+
- not implemented yet
15+
- meant for heavier work, but not sure if different from onComplete
16+
17+
## template addons
18+
19+
specify an array of objects of this shape:
20+
21+
```ts
22+
{
23+
addonName: String,
24+
addonDidInstall?: Function // for executing arbitrary postinstall code for a SINGLE addon
25+
}
26+
```
27+
528
## why place templates in a separate folder
629

730
we dont colocate this inside `src/commands/functions` because oclif will think it's a new command.

src/functions-templates/js/fauna-crud/.netlify-function-template.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1+
const execa = require('execa')
12
module.exports = {
23
name: 'fauna-crud',
34
description: 'CRUD function using Fauna DB',
4-
addons: ['fauna'], // in future we'll want to pass/prompt args to addons
5+
addons: [
6+
{
7+
addonName: 'fauna',
8+
addonDidInstall(fnPath) {
9+
require('fs').chmodSync(fnPath + '/create-schema.js', 0o777)
10+
execa.sync(fnPath + '/create-schema.js', undefined, { env: process.env, stdio: 'inherit' })
11+
}
12+
}
13+
],
514
onComplete() {
615
console.log(`fauna-crud function created from template!`)
716
}

src/utils/addons.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const inquirer = require('inquirer')
55
const fetch = require('node-fetch')
66

77
/** main section - shamelessly adapted from CLI. we can extract and dedupe later. */
8-
/** i know, i know. i felt bad too. but we can DRY things up later. */
8+
/** but we can DRY things up later. */
99
module.exports.createSiteAddon = async function createSiteAddon(accessToken, addonName, siteId, siteData, log) {
1010
const addons = await getAddons(siteId, accessToken)
1111
if (typeof addons === 'object' && addons.error) {
@@ -14,8 +14,6 @@ module.exports.createSiteAddon = async function createSiteAddon(accessToken, add
1414
}
1515
// Filter down addons to current args.name
1616
const currentAddon = addons.find(addon => addon.service_path === `/.netlify/${addonName}`)
17-
// // GET flags from `raw` data
18-
// const rawFlags = parseRawFlags(raw)
1917
const rawFlags = {}
2018

2119
if (currentAddon && currentAddon.id) {
@@ -109,6 +107,7 @@ module.exports.createSiteAddon = async function createSiteAddon(accessToken, add
109107
accessToken,
110108
siteData
111109
})
110+
return addonName // we dont really use this right now but may be helpful to know that an addon installation was successful
112111
}
113112

114113
async function actuallyCreateSiteAddon({ addonName, settings, accessToken, siteData }) {

src/utils/dev-exec.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// code extracted from /dev/exec.js so we can reuse it in functions templating
2+
// bit of a hasty abstraction but recommended by oclif
3+
const { getAddons } = require('netlify/src/addons')
4+
5+
/**
6+
* get this data from the `this.netlify` instance in your commands
7+
*
8+
* ```
9+
* // usage example
10+
* const { site } = this.netlify
11+
* if (site.id) {
12+
* const accessToken = await this.authenticate()
13+
* await addEnvVarsFromAddons(site, accessToken)
14+
* }
15+
* ```
16+
*/
17+
async function addEnvVarsFromAddons(site, accessToken) {
18+
const addons = await getAddons(site.id, accessToken)
19+
addons.forEach(addon => {
20+
for (const key in addon.env) {
21+
process.env[key] = addon.env[key]
22+
}
23+
})
24+
}
25+
26+
module.exports = {
27+
addEnvVarsFromAddons
28+
}

0 commit comments

Comments
 (0)