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

Commit 5fb6949

Browse files
author
sw-yx
committed
merge
2 parents b52a2b5 + 4d24b04 commit 5fb6949

File tree

6 files changed

+112
-51
lines changed

6 files changed

+112
-51
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ netlify functions:create
4545
netlify functions:create hello-world
4646
netlify functions:create --name hello-world
4747
netlify functions:create hello-world --dir
48-
48+
netlify functions:create hello-world --url https://github.com/netlify-labs/all-the-functions/tree/master/functions/9-using-middleware
4949
```
5050

5151
You can just call `netlify functions:create` and the prompts will guide you all the way, however you can also supply a first argument to name the function. By default it creates a single file, however you can also use a `--dir` flag to create a function as a directory.
52+
53+
By passing a URL to a folder in a github repo to the `--url` flag, you can clone new templates. Dependencies are installed inside its own folder. Example: `netlify functions:create hello-world --url https://github.com/netlify-labs/all-the-functions/tree/master/functions/9-using-middleware`

package-lock.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
"netlify": "ssh+git://git@github.com:netlify/js-client-private",
1818
"netlify-rules-proxy": "git+ssh://git@github.com/netlify/netlify-rules-proxy.git",
1919
"safe-join": "^0.1.1",
20+
"node-fetch": "^2.3.0",
21+
"opn": "^5.5.0",
2022
"static-dev-server": "^1.0.0",
2123
"wait-port": "^0.2.2"
2224
},

src/commands/dev/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const waitPort = require('wait-port')
66
const getPort = require('get-port')
77
const { serveFunctions } = require('@netlify/zip-it-and-ship-it')
88
const { serverSettings } = require('../../detect-server')
9-
const openBrowser = require('./openBrowser')
9+
const openBrowser = require('../../utils/openBrowser')
1010
const Command = require('@netlify/cli-utils')
1111
const { getAddons } = require('netlify/src/addons')
1212

src/commands/functions/create.js

Lines changed: 98 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,18 @@ const path = require('path')
33
const { flags } = require('@oclif/command')
44
const Command = require('@netlify/cli-utils')
55
const inquirer = require('inquirer')
6-
6+
const readRepoURL = require('../../utils/readRepoURL')
77
const templatesDir = path.resolve(__dirname, '../../functions-templates')
8+
const http = require('http')
9+
const fetch = require('node-fetch')
10+
const cp = require('child_process')
11+
812
class FunctionsCreateCommand extends Command {
913
async run() {
1014
const { flags, args } = this.parse(FunctionsCreateCommand)
11-
const { config } = this.netlify
12-
let templates = fs.readdirSync(templatesDir).filter(x => path.extname(x) === '.js') // only js templates for now
13-
templates = templates
14-
.map(t => require(path.join(templatesDir, t)))
15-
.sort((a, b) => (a.priority || 999) - (b.priority || 999)) // doesnt scale but will be ok for now
16-
const { templatePath } = await inquirer.prompt([
17-
{
18-
name: 'templatePath',
19-
message: 'pick a template',
20-
type: 'list',
21-
choices: templates.map(t => t.metadata)
22-
}
23-
])
24-
// pull the rest of the metadata from the template
25-
const { onComplete, copyAssets, templateCode } = require(path.join(templatesDir, templatePath))
26-
27-
let template
28-
try {
29-
template = templateCode() // we may pass in args in future to customize the template
30-
} catch (err) {
31-
console.error('an error occurred retrieving template code, please check ' + templatePath, err)
32-
process.exit(0)
33-
}
34-
35-
const name = await getNameFromArgs(args, flags, path.basename(templatePath, '.js'))
36-
37-
this.log(`Creating function ${name}`)
3815

16+
/* get functions dir (and make it if necessary) */
17+
const { config } = this.netlify
3918
const functionsDir = flags.functions || (config.build && config.build.functions)
4019
if (!functionsDir) {
4120
this.log('No functions folder specified in netlify.toml or as an argument')
@@ -48,14 +27,13 @@ class FunctionsCreateCommand extends Command {
4827
console.log(`functions folder ${functionsDir} created`)
4928
}
5029

51-
const functionPath = flags.dir ? path.join(functionsDir, name, name + '.js') : path.join(functionsDir, name + '.js')
52-
if (fs.existsSync(functionPath)) {
53-
this.log(`Function ${functionPath} already exists`)
54-
process.exit(1)
55-
}
56-
57-
if (flags.dir) {
58-
const fnFolder = path.join(functionsDir, name)
30+
/* either download from URL or scaffold from template */
31+
if (flags.url) {
32+
// // --url flag specified, download from there
33+
const folderContents = await readRepoURL(flags.url)
34+
const functionName = flags.url.split('/').slice(-1)[0]
35+
const nameToUse = await getNameFromArgs(args, flags, functionName)
36+
const fnFolder = path.join(functionsDir, nameToUse)
5937
if (fs.existsSync(fnFolder + '.js') && fs.lstatSync(fnFolder + '.js').isFile()) {
6038
this.log(`A single file version of the function ${name} already exists at ${fnFolder}.js`)
6139
process.exit(1)
@@ -66,21 +44,74 @@ class FunctionsCreateCommand extends Command {
6644
} catch (e) {
6745
// Ignore
6846
}
69-
} else if (fs.existsSync(functionPath.replace(/\.js/, ''))) {
70-
this.log(`A folder version of the function ${name} already exists at ${functionPath.replace(/\.js/, '')}`)
71-
process.exit(1)
72-
}
73-
74-
fs.writeFileSync(functionPath, template)
75-
if (copyAssets) {
76-
copyAssets.forEach(src =>
77-
fs.copySync(path.join(templatesDir, 'assets', src), path.join(functionsDir, src), {
78-
overwrite: false,
79-
errorOnExist: false // went with this to make it idempotent, might change in future
47+
await Promise.all(
48+
folderContents.map(({ name, download_url }) => {
49+
return fetch(download_url).then(res => {
50+
const finalName = path.basename(name, '.js') === functionName ? nameToUse + '.js' : name
51+
const dest = fs.createWriteStream(path.join(fnFolder, finalName))
52+
res.body.pipe(dest)
53+
})
8054
})
81-
) // copy assets if specified
55+
)
56+
57+
console.log(`installing dependencies for ${nameToUse}...`)
58+
cp.exec('npm i', { cwd: path.join(functionsDir, nameToUse) }, () => {
59+
console.log(`installing dependencies for ${nameToUse} complete `)
60+
})
61+
} else {
62+
// // no --url flag specified, pick from a provided template
63+
const templatePath = await pickTemplate()
64+
// pull the rest of the metadata from the template
65+
const { onComplete, copyAssets, templateCode } = require(path.join(templatesDir, templatePath))
66+
67+
let template
68+
try {
69+
template = templateCode() // we may pass in args in future to customize the template
70+
} catch (err) {
71+
console.error('an error occurred retrieving template code, please check ' + templatePath, err)
72+
process.exit(0)
73+
}
74+
75+
const name = await getNameFromArgs(args, flags, path.basename(templatePath, '.js'))
76+
77+
this.log(`Creating function ${name}`)
78+
79+
const functionPath = flags.dir
80+
? path.join(functionsDir, name, name + '.js')
81+
: path.join(functionsDir, name + '.js')
82+
if (fs.existsSync(functionPath)) {
83+
this.log(`Function ${functionPath} already exists`)
84+
process.exit(1)
85+
}
86+
87+
if (flags.dir) {
88+
const fnFolder = path.join(functionsDir, name)
89+
if (fs.existsSync(fnFolder + '.js') && fs.lstatSync(fnFolder + '.js').isFile()) {
90+
this.log(`A single file version of the function ${name} already exists at ${fnFolder}.js`)
91+
process.exit(1)
92+
}
93+
94+
try {
95+
fs.mkdirSync(fnFolder, { recursive: true })
96+
} catch (e) {
97+
// Ignore
98+
}
99+
} else if (fs.existsSync(functionPath.replace(/\.js/, ''))) {
100+
this.log(`A folder version of the function ${name} already exists at ${functionPath.replace(/\.js/, '')}`)
101+
process.exit(1)
102+
}
103+
104+
fs.writeFileSync(functionPath, template)
105+
if (copyAssets) {
106+
copyAssets.forEach(src =>
107+
fs.copySync(path.join(templatesDir, 'assets', src), path.join(functionsDir, src), {
108+
overwrite: false,
109+
errorOnExist: false // went with this to make it idempotent, might change in future
110+
})
111+
) // copy assets if specified
112+
}
113+
if (onComplete) onComplete() // do whatever the template wants to do after it is scaffolded
82114
}
83-
if (onComplete) onComplete() // do whatever the template wants to do after it is scaffolded
84115
}
85116
}
86117

@@ -104,6 +135,7 @@ FunctionsCreateCommand.examples = [
104135
FunctionsCreateCommand.flags = {
105136
name: flags.string({ char: 'n', description: 'function name' }),
106137
functions: flags.string({ char: 'f', description: 'functions folder' }),
138+
url: flags.string({ char: 'u', description: 'pull template from URL' }),
107139
dir: flags.boolean({
108140
char: 'd',
109141
description: 'create function as a directory'
@@ -136,3 +168,20 @@ async function getNameFromArgs(args, flags, defaultName) {
136168
}
137169
return name
138170
}
171+
172+
// pick template from our existing templates
173+
async function pickTemplate() {
174+
let templates = fs.readdirSync(templatesDir).filter(x => path.extname(x) === '.js') // only js templates for now
175+
templates = templates
176+
.map(t => require(path.join(templatesDir, t)))
177+
.sort((a, b) => (a.priority || 999) - (b.priority || 999)) // doesnt scale but will be ok for now
178+
const { templatePath } = await inquirer.prompt([
179+
{
180+
name: 'templatePath',
181+
message: 'pick a template',
182+
type: 'list',
183+
choices: templates.map(t => t.metadata)
184+
}
185+
])
186+
return templatePath
187+
}
File renamed without changes.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy