netlify-cli 8.0.7 → 8.1.0-rc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/run +81 -3
- package/npm-shrinkwrap.json +305 -2105
- package/package.json +10 -33
- package/src/commands/addons/addons-auth.js +50 -0
- package/src/commands/addons/addons-config.js +180 -0
- package/src/commands/addons/addons-create.js +129 -0
- package/src/commands/addons/addons-delete.js +59 -0
- package/src/commands/addons/addons-list.js +62 -0
- package/src/commands/addons/addons.js +49 -0
- package/src/commands/addons/index.js +3 -24
- package/src/commands/api/api.js +83 -0
- package/src/commands/api/index.js +5 -0
- package/src/commands/base-command.js +322 -0
- package/src/commands/build/build.js +58 -0
- package/src/commands/build/index.js +3 -61
- package/src/commands/completion/completion.js +18 -0
- package/src/commands/completion/index.js +5 -0
- package/src/commands/{deploy.js → deploy/deploy.js} +306 -278
- package/src/commands/deploy/index.js +5 -0
- package/src/commands/dev/dev-exec.js +39 -0
- package/src/commands/dev/dev-trace.js +50 -0
- package/src/commands/dev/dev.js +349 -0
- package/src/commands/dev/index.js +3 -335
- package/src/commands/env/env-get.js +51 -0
- package/src/commands/env/env-import.js +93 -0
- package/src/commands/env/env-list.js +63 -0
- package/src/commands/env/env-set.js +67 -0
- package/src/commands/env/env-unset.js +66 -0
- package/src/commands/env/env.js +47 -0
- package/src/commands/env/index.js +3 -23
- package/src/commands/functions/functions-build.js +59 -0
- package/src/commands/functions/{create.js → functions-create.js} +133 -94
- package/src/commands/functions/functions-invoke.js +276 -0
- package/src/commands/functions/functions-list.js +107 -0
- package/src/commands/functions/functions-serve.js +63 -0
- package/src/commands/functions/functions.js +53 -0
- package/src/commands/functions/index.js +3 -45
- package/src/commands/index.js +5 -0
- package/src/commands/init/index.js +6 -0
- package/src/commands/{init.js → init/init.js} +79 -68
- package/src/commands/link/index.js +6 -0
- package/src/{utils/link/link-by-prompt.js → commands/link/link.js} +153 -14
- package/src/commands/lm/index.js +3 -19
- package/src/commands/lm/lm-info.js +42 -0
- package/src/commands/lm/lm-install.js +36 -0
- package/src/commands/lm/lm-setup.js +106 -0
- package/src/commands/lm/lm-uninstall.js +25 -0
- package/src/commands/lm/lm.js +39 -0
- package/src/commands/login/index.js +6 -0
- package/src/commands/login/login.js +52 -0
- package/src/commands/logout/index.js +5 -0
- package/src/commands/logout/logout.js +43 -0
- package/src/commands/main.js +117 -0
- package/src/commands/open/index.js +3 -39
- package/src/commands/open/open-admin.js +56 -0
- package/src/commands/open/open-site.js +49 -0
- package/src/commands/open/open.js +42 -0
- package/src/commands/sites/index.js +5 -20
- package/src/commands/sites/sites-create.js +184 -0
- package/src/commands/sites/sites-delete.js +108 -0
- package/src/commands/sites/sites-list.js +89 -0
- package/src/commands/sites/sites.js +36 -0
- package/src/commands/status/index.js +3 -118
- package/src/commands/status/status-hooks.js +73 -0
- package/src/commands/status/status.js +125 -0
- package/src/commands/switch/index.js +5 -0
- package/src/commands/switch/switch.js +50 -0
- package/src/commands/unlink/index.js +5 -0
- package/src/commands/unlink/unlink.js +48 -0
- package/src/commands/watch/index.js +5 -0
- package/src/commands/watch/watch.js +121 -0
- package/src/lib/build.js +21 -7
- package/src/lib/exec-fetcher.js +5 -3
- package/src/lib/fs.js +54 -36
- package/src/lib/functions/background.js +1 -1
- package/src/lib/functions/form-submissions-handler.js +2 -1
- package/src/lib/functions/local-proxy.js +2 -1
- package/src/lib/functions/netlify-function.js +4 -1
- package/src/lib/functions/registry.js +4 -6
- package/src/lib/functions/runtimes/go/index.js +2 -1
- package/src/lib/functions/runtimes/js/builders/netlify-lambda.js +6 -4
- package/src/lib/functions/runtimes/js/builders/zisi.js +3 -3
- package/src/lib/functions/runtimes/rust/index.js +4 -3
- package/src/lib/functions/server.js +2 -3
- package/src/lib/functions/synchronous.js +2 -1
- package/src/lib/functions/utils.js +2 -3
- package/src/lib/functions/watcher.js +1 -0
- package/src/lib/http-agent.js +3 -5
- package/src/lib/log.js +2 -1
- package/src/lib/spinner.js +22 -0
- package/src/utils/addons/diffs/index.js +1 -0
- package/src/utils/addons/diffs/options.js +3 -1
- package/src/utils/addons/prepare.js +13 -6
- package/src/utils/addons/prompts.js +2 -1
- package/src/utils/addons/render.js +3 -1
- package/src/utils/command-helpers.js +156 -43
- package/src/utils/create-stream-promise.js +5 -5
- package/src/utils/deferred.js +1 -0
- package/src/utils/deploy/deploy-site.js +1 -1
- package/src/utils/deploy/index.js +4 -0
- package/src/utils/detect-server-settings.js +10 -12
- package/src/utils/dev.js +18 -10
- package/src/utils/dot-env.js +4 -2
- package/src/utils/{edge-handlers.js → functions/edge-handlers.js} +8 -7
- package/src/utils/functions/functions.js +36 -0
- package/src/utils/{get-functions.js → functions/get-functions.js} +2 -1
- package/src/utils/functions/index.js +8 -26
- package/src/utils/get-global-config.js +3 -2
- package/src/utils/get-repo-data.js +1 -0
- package/src/utils/gh-auth.js +1 -0
- package/src/utils/gitignore.js +7 -5
- package/src/utils/header.js +2 -2
- package/src/utils/headers.js +1 -2
- package/src/utils/index.js +42 -0
- package/src/utils/init/config-github.js +12 -5
- package/src/utils/init/config-manual.js +9 -2
- package/src/utils/init/config.js +13 -7
- package/src/utils/init/frameworks.js +1 -0
- package/src/utils/init/node-version.js +4 -2
- package/src/utils/init/plugins.js +1 -0
- package/src/utils/init/utils.js +10 -6
- package/src/utils/live-tunnel.js +3 -4
- package/src/utils/lm/install.js +10 -15
- package/src/utils/lm/requirements.js +3 -1
- package/src/utils/lm/steps.js +1 -1
- package/src/utils/lm/ui.js +7 -3
- package/src/utils/open-browser.js +8 -2
- package/src/utils/parse-raw-flags.js +4 -4
- package/src/utils/proxy.js +6 -5
- package/src/utils/read-repo-url.js +1 -0
- package/src/utils/redirects.js +2 -2
- package/src/utils/rules-proxy.js +2 -1
- package/src/utils/state-config.js +1 -1
- package/src/utils/telemetry/index.js +2 -113
- package/src/utils/telemetry/request.js +3 -1
- package/src/utils/telemetry/telemetry.js +117 -0
- package/src/utils/telemetry/validation.js +13 -12
- package/src/utils/traffic-mesh.js +3 -3
- package/oclif.manifest.json +0 -1
- package/src/commands/addons/auth.js +0 -42
- package/src/commands/addons/config.js +0 -177
- package/src/commands/addons/create.js +0 -127
- package/src/commands/addons/delete.js +0 -69
- package/src/commands/addons/list.js +0 -54
- package/src/commands/api.js +0 -84
- package/src/commands/dev/exec.js +0 -32
- package/src/commands/dev/trace.js +0 -61
- package/src/commands/env/get.js +0 -44
- package/src/commands/env/import.js +0 -90
- package/src/commands/env/list.js +0 -49
- package/src/commands/env/set.js +0 -64
- package/src/commands/env/unset.js +0 -58
- package/src/commands/functions/build.js +0 -60
- package/src/commands/functions/invoke.js +0 -277
- package/src/commands/functions/list.js +0 -102
- package/src/commands/functions/serve.js +0 -70
- package/src/commands/link.js +0 -133
- package/src/commands/lm/info.js +0 -36
- package/src/commands/lm/install.js +0 -30
- package/src/commands/lm/setup.js +0 -107
- package/src/commands/lm/uninstall.js +0 -17
- package/src/commands/login.js +0 -54
- package/src/commands/logout.js +0 -37
- package/src/commands/open/admin.js +0 -51
- package/src/commands/open/site.js +0 -43
- package/src/commands/sites/create.js +0 -191
- package/src/commands/sites/delete.js +0 -116
- package/src/commands/sites/list.js +0 -84
- package/src/commands/status/hooks.js +0 -60
- package/src/commands/switch.js +0 -44
- package/src/commands/unlink.js +0 -38
- package/src/commands/watch.js +0 -115
- package/src/hooks/init.js +0 -46
- package/src/index.js +0 -25
- package/src/lib/help.js +0 -26
- package/src/utils/chalk.js +0 -16
- package/src/utils/check-command-inputs.js +0 -21
- package/src/utils/command.js +0 -262
- package/src/utils/detect-functions-builder.js +0 -25
- package/src/utils/difference.js +0 -4
- package/src/utils/logo.js +0 -11
- package/src/utils/show-help.js +0 -5
- package/src/utils/telemetry/tracked-command.js +0 -51
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const AsciiTable = require('ascii-table')
|
|
3
|
+
|
|
4
|
+
// TODO: use static `import` after migrating this repository to pure ES modules
|
|
5
|
+
const jsClient = import('netlify')
|
|
6
|
+
|
|
7
|
+
const { chalk, error, exit, generateDescriptionHelp, generateExamplesHelp, log, logJson } = require('../../utils')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The api command
|
|
11
|
+
* @param {string} apiMethod
|
|
12
|
+
* @param {import('commander').OptionValues} options
|
|
13
|
+
* @param {import('../base-command').BaseCommand} command
|
|
14
|
+
*/
|
|
15
|
+
const apiCommand = async (apiMethod, options, command) => {
|
|
16
|
+
const { api } = command.netlify
|
|
17
|
+
|
|
18
|
+
if (options.list) {
|
|
19
|
+
const table = new AsciiTable(`Netlify API Methods`)
|
|
20
|
+
table.setHeading('API Method', 'Docs Link')
|
|
21
|
+
const { methods } = await jsClient
|
|
22
|
+
methods.forEach((method) => {
|
|
23
|
+
const { operationId } = method
|
|
24
|
+
table.addRow(operationId, `https://open-api.netlify.com/#operation/${operationId}`)
|
|
25
|
+
})
|
|
26
|
+
log(table.toString())
|
|
27
|
+
log()
|
|
28
|
+
log('Above is a list of available API methods')
|
|
29
|
+
log(`To run a method use "${chalk.cyanBright('netlify api methodName')}"`)
|
|
30
|
+
exit()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!apiMethod) {
|
|
34
|
+
error(`You must provide an API method. Run "netlify api --list" to see available methods`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!api[apiMethod] || typeof api[apiMethod] !== 'function') {
|
|
38
|
+
error(`"${apiMethod}"" is not a valid api method. Run "netlify api --list" to see available methods`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let payload
|
|
42
|
+
if (options.data) {
|
|
43
|
+
payload = typeof options.data === 'string' ? JSON.parse(options.data) : options.data
|
|
44
|
+
} else {
|
|
45
|
+
payload = {}
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const apiResponse = await api[apiMethod](payload)
|
|
49
|
+
logJson(apiResponse)
|
|
50
|
+
} catch (error_) {
|
|
51
|
+
error(error_)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Creates the `netlify api` command
|
|
57
|
+
* @param {import('../base-command').BaseCommand} program
|
|
58
|
+
* @returns
|
|
59
|
+
*/
|
|
60
|
+
const createApiCommand = (program) =>
|
|
61
|
+
program
|
|
62
|
+
.command('api')
|
|
63
|
+
.argument('[method]', 'Open API method to run')
|
|
64
|
+
.option('-d, --data <data>', 'Data to use')
|
|
65
|
+
.option('--list', 'List out available API methods', false)
|
|
66
|
+
.addHelpText(
|
|
67
|
+
'after',
|
|
68
|
+
generateDescriptionHelp(
|
|
69
|
+
`For more information on available methods checkout https://open-api.netlify.com/ or run '${chalk.grey(
|
|
70
|
+
'netlify api --list',
|
|
71
|
+
)}'`,
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
.addHelpText(
|
|
75
|
+
'after',
|
|
76
|
+
generateExamplesHelp([
|
|
77
|
+
'netlify api --list',
|
|
78
|
+
`netlify api getSite --data '${chalk.grey('{ "site_id": "123456"}')}'`,
|
|
79
|
+
]),
|
|
80
|
+
)
|
|
81
|
+
.action(apiCommand)
|
|
82
|
+
|
|
83
|
+
module.exports = { createApiCommand }
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const process = require('process')
|
|
3
|
+
const { format } = require('util')
|
|
4
|
+
|
|
5
|
+
const resolveConfig = require('@netlify/config')
|
|
6
|
+
const { Command } = require('commander')
|
|
7
|
+
const debug = require('debug')
|
|
8
|
+
const merge = require('lodash/merge')
|
|
9
|
+
|
|
10
|
+
// TODO: use static `import` after migrating this repository to pure ES modules
|
|
11
|
+
const jsClient = import('netlify')
|
|
12
|
+
|
|
13
|
+
const { getAgent } = require('../lib/http-agent')
|
|
14
|
+
const {
|
|
15
|
+
StateConfig,
|
|
16
|
+
USER_AGENT,
|
|
17
|
+
chalk,
|
|
18
|
+
error,
|
|
19
|
+
exit,
|
|
20
|
+
getGlobalConfig,
|
|
21
|
+
getToken,
|
|
22
|
+
identify,
|
|
23
|
+
log,
|
|
24
|
+
normalizeConfig,
|
|
25
|
+
openBrowser,
|
|
26
|
+
pollForToken,
|
|
27
|
+
track,
|
|
28
|
+
} = require('../utils')
|
|
29
|
+
|
|
30
|
+
// Netlify CLI client id. Lives in bot@netlify.com
|
|
31
|
+
// TODO: setup client for multiple environments
|
|
32
|
+
const CLIENT_ID = 'd6f37de6614df7ae58664cfca524744d73807a377f5ee71f1a254f78412e3750'
|
|
33
|
+
|
|
34
|
+
const NANO_SECS_TO_MSECS = 1e6
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the duration between a start time and the current time
|
|
38
|
+
* @param {bigint} startTime
|
|
39
|
+
* @returns
|
|
40
|
+
*/
|
|
41
|
+
const getDuration = function (startTime) {
|
|
42
|
+
const durationNs = process.hrtime.bigint() - startTime
|
|
43
|
+
return Math.round(Number(durationNs / BigInt(NANO_SECS_TO_MSECS)))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The netlify object inside each command with the state
|
|
48
|
+
* @typedef NetlifyOptions
|
|
49
|
+
* @type {object}
|
|
50
|
+
* @property {import('netlify').NetlifyAPI} api
|
|
51
|
+
* @property {*} repositoryRoot
|
|
52
|
+
* @property {object} site
|
|
53
|
+
* @property {*} site.root
|
|
54
|
+
* @property {*} site.configPath
|
|
55
|
+
* @property {*} site.id
|
|
56
|
+
* @property {*} siteInfo
|
|
57
|
+
* @property {*} config
|
|
58
|
+
* @property {*} cachedConfig
|
|
59
|
+
* @property {*} globalConfig
|
|
60
|
+
* @property {StateConfig} state,
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/** Base command class that provides tracking and config initialization */
|
|
64
|
+
class BaseCommand extends Command {
|
|
65
|
+
/** @type {NetlifyOptions} */
|
|
66
|
+
netlify
|
|
67
|
+
|
|
68
|
+
/** @type {{ startTime: bigint, payload?: any}} */
|
|
69
|
+
analytics = { startTime: process.hrtime.bigint() }
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* IMPORTANT this function will be called for each command!
|
|
73
|
+
* Don't do anything expensive in there.
|
|
74
|
+
* @param {string} name The command name
|
|
75
|
+
* @returns
|
|
76
|
+
*/
|
|
77
|
+
createCommand(name) {
|
|
78
|
+
return (
|
|
79
|
+
new BaseCommand(name)
|
|
80
|
+
// If --silent or --json flag passed disable logger
|
|
81
|
+
.option('--json')
|
|
82
|
+
.option('--cwd <cwd>', 'Pass a current working directory.')
|
|
83
|
+
.option('-o, --offline')
|
|
84
|
+
|
|
85
|
+
// Allow hidden flags like
|
|
86
|
+
// --json,
|
|
87
|
+
// --silent,
|
|
88
|
+
// --offline, -o
|
|
89
|
+
// --cwd <cwd> Pass a current working directory.
|
|
90
|
+
|
|
91
|
+
// this disables the suggestions
|
|
92
|
+
// .allowUnknownOption(true)
|
|
93
|
+
|
|
94
|
+
.option('--debug', 'Print debugging information')
|
|
95
|
+
.option(
|
|
96
|
+
'--httpProxy',
|
|
97
|
+
'Proxy server address to route requests through',
|
|
98
|
+
process.env.HTTP_PROXY || process.env.HTTPS_PROXY,
|
|
99
|
+
)
|
|
100
|
+
.option(
|
|
101
|
+
'--httpProxyCertificateFilename',
|
|
102
|
+
'Certificate file to use when connecting using a proxy server',
|
|
103
|
+
process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME,
|
|
104
|
+
)
|
|
105
|
+
.hook('preAction', async (_parentCommand, actionCommand) => {
|
|
106
|
+
debug(`${name}:preAction`)('start')
|
|
107
|
+
this.analytics = { startTime: process.hrtime.bigint() }
|
|
108
|
+
// @ts-ignore cannot type actionCommand as BaseCommand
|
|
109
|
+
await this.init(actionCommand)
|
|
110
|
+
debug(`${name}:preAction`)('end')
|
|
111
|
+
})
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Will be called on the end of an action to track the metrics
|
|
117
|
+
* @param {*} [error_]
|
|
118
|
+
*/
|
|
119
|
+
async onEnd(error_) {
|
|
120
|
+
const { payload, startTime } = this.analytics
|
|
121
|
+
const duration = getDuration(startTime)
|
|
122
|
+
const status = error_ === undefined ? 'success' : 'error'
|
|
123
|
+
|
|
124
|
+
debug(`${this.name()}:onEnd`)(`Status: ${status}`)
|
|
125
|
+
debug(`${this.name()}:onEnd`)(`Duration: ${duration}ms`)
|
|
126
|
+
|
|
127
|
+
await track('command', {
|
|
128
|
+
...payload,
|
|
129
|
+
command: this.name(),
|
|
130
|
+
duration,
|
|
131
|
+
status,
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
if (error_ !== undefined) {
|
|
135
|
+
error(error_ instanceof Error ? error_ : format(error_), { exit: false })
|
|
136
|
+
exit(1)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async authenticate(tokenFromFlag) {
|
|
141
|
+
const [token] = await getToken(tokenFromFlag)
|
|
142
|
+
if (token) {
|
|
143
|
+
return token
|
|
144
|
+
}
|
|
145
|
+
return this.expensivelyAuthenticate()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async expensivelyAuthenticate() {
|
|
149
|
+
const webUI = process.env.NETLIFY_WEB_UI || 'https://app.netlify.com'
|
|
150
|
+
log(`Logging into your Netlify account...`)
|
|
151
|
+
|
|
152
|
+
// Create ticket for auth
|
|
153
|
+
// @ts-ignore Types from api are wrong and they don't recognize `createTicket`
|
|
154
|
+
const ticket = await this.netlify.api.createTicket({
|
|
155
|
+
clientId: CLIENT_ID,
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// Open browser for authentication
|
|
159
|
+
const authLink = `${webUI}/authorize?response_type=ticket&ticket=${ticket.id}`
|
|
160
|
+
|
|
161
|
+
log(`Opening ${authLink}`)
|
|
162
|
+
await openBrowser({ url: authLink })
|
|
163
|
+
|
|
164
|
+
const accessToken = await pollForToken({
|
|
165
|
+
api: this.netlify.api,
|
|
166
|
+
ticket,
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
// @ts-ignore Types from api are wrong and they don't recognize `getCurrentUser`
|
|
170
|
+
const { email, full_name: name, id: userId } = await this.netlify.api.getCurrentUser()
|
|
171
|
+
|
|
172
|
+
const userData = merge(this.netlify.globalConfig.get(`users.${userId}`), {
|
|
173
|
+
id: userId,
|
|
174
|
+
name,
|
|
175
|
+
email,
|
|
176
|
+
auth: {
|
|
177
|
+
token: accessToken,
|
|
178
|
+
github: {
|
|
179
|
+
user: undefined,
|
|
180
|
+
token: undefined,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
})
|
|
184
|
+
// Set current userId
|
|
185
|
+
this.netlify.globalConfig.set('userId', userId)
|
|
186
|
+
// Set user data
|
|
187
|
+
this.netlify.globalConfig.set(`users.${userId}`, userData)
|
|
188
|
+
|
|
189
|
+
await identify({
|
|
190
|
+
name,
|
|
191
|
+
email,
|
|
192
|
+
userId,
|
|
193
|
+
})
|
|
194
|
+
await track('user_login', {
|
|
195
|
+
email,
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
// Log success
|
|
199
|
+
log()
|
|
200
|
+
log(`${chalk.greenBright('You are now logged into your Netlify account!')}`)
|
|
201
|
+
log()
|
|
202
|
+
log(`Run ${chalk.cyanBright('netlify status')} for account details`)
|
|
203
|
+
log()
|
|
204
|
+
log(`To see all available commands run: ${chalk.cyanBright('netlify help')}`)
|
|
205
|
+
log()
|
|
206
|
+
return accessToken
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
setAnalyticsPayload(payload) {
|
|
210
|
+
this.analytics = { ...this.analytics, payload }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Initializes the options and parses the configuration needs to be called on start of a command function
|
|
215
|
+
* @param {BaseCommand} actionCommand The command of the action that is run (`this.` gets the parent command)
|
|
216
|
+
*/
|
|
217
|
+
async init(actionCommand) {
|
|
218
|
+
debug(`${actionCommand.name()}:init`)('start')
|
|
219
|
+
const options = actionCommand.opts()
|
|
220
|
+
const cwd = options.cwd || process.cwd()
|
|
221
|
+
// Get site id & build state
|
|
222
|
+
const state = new StateConfig(cwd)
|
|
223
|
+
|
|
224
|
+
const [token] = await getToken(options.auth)
|
|
225
|
+
|
|
226
|
+
const apiUrlOpts = {
|
|
227
|
+
userAgent: USER_AGENT,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (process.env.NETLIFY_API_URL) {
|
|
231
|
+
const apiUrl = new URL(process.env.NETLIFY_API_URL)
|
|
232
|
+
apiUrlOpts.scheme = apiUrl.protocol.slice(0, -1)
|
|
233
|
+
apiUrlOpts.host = apiUrl.host
|
|
234
|
+
apiUrlOpts.pathPrefix =
|
|
235
|
+
process.env.NETLIFY_API_URL === `${apiUrl.protocol}//${apiUrl.host}` ? '/api/v1' : apiUrl.pathname
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const cachedConfig = await actionCommand.getConfig({ cwd, state, token, ...apiUrlOpts })
|
|
239
|
+
const { buildDir, config, configPath, repositoryRoot, siteInfo } = cachedConfig
|
|
240
|
+
const normalizedConfig = normalizeConfig(config)
|
|
241
|
+
|
|
242
|
+
const agent = await getAgent({
|
|
243
|
+
httpProxy: options.httpProxy,
|
|
244
|
+
certificateFile: options.httpProxyCertificateFilename,
|
|
245
|
+
})
|
|
246
|
+
const apiOpts = { ...apiUrlOpts, agent }
|
|
247
|
+
const globalConfig = await getGlobalConfig()
|
|
248
|
+
const { NetlifyAPI } = await jsClient
|
|
249
|
+
|
|
250
|
+
actionCommand.netlify = {
|
|
251
|
+
// api methods
|
|
252
|
+
api: new NetlifyAPI(token || '', apiOpts),
|
|
253
|
+
repositoryRoot,
|
|
254
|
+
// current site context
|
|
255
|
+
site: {
|
|
256
|
+
root: buildDir,
|
|
257
|
+
configPath,
|
|
258
|
+
get id() {
|
|
259
|
+
return state.get('siteId')
|
|
260
|
+
},
|
|
261
|
+
set id(id) {
|
|
262
|
+
state.set('siteId', id)
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
// Site information retrieved using the API
|
|
266
|
+
siteInfo,
|
|
267
|
+
// Configuration from netlify.[toml/yml]
|
|
268
|
+
config: normalizedConfig,
|
|
269
|
+
// Used to avoid calling @netlify/config again
|
|
270
|
+
cachedConfig,
|
|
271
|
+
// global cli config
|
|
272
|
+
globalConfig,
|
|
273
|
+
// state of current site dir
|
|
274
|
+
state,
|
|
275
|
+
}
|
|
276
|
+
debug(`${this.name()}:init`)('end')
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Find and resolve the Netlify configuration
|
|
281
|
+
* @param {*} config
|
|
282
|
+
* @returns {ReturnType<import('@netlify/config/src/main')>}
|
|
283
|
+
*/
|
|
284
|
+
async getConfig(config) {
|
|
285
|
+
const options = this.opts()
|
|
286
|
+
const { cwd, host, offline = options.offline, pathPrefix, scheme, state, token } = config
|
|
287
|
+
|
|
288
|
+
try {
|
|
289
|
+
return await resolveConfig({
|
|
290
|
+
config: options.config,
|
|
291
|
+
cwd,
|
|
292
|
+
context: options.context || this.name(),
|
|
293
|
+
debug: this.opts().debug,
|
|
294
|
+
siteId: options.siteId || (typeof options.site === 'string' && options.site) || state.get('siteId'),
|
|
295
|
+
token,
|
|
296
|
+
mode: 'cli',
|
|
297
|
+
host,
|
|
298
|
+
pathPrefix,
|
|
299
|
+
scheme,
|
|
300
|
+
offline,
|
|
301
|
+
})
|
|
302
|
+
} catch (error_) {
|
|
303
|
+
const isUserError = error_.customErrorInfo !== undefined && error_.customErrorInfo.type === 'resolveConfig'
|
|
304
|
+
|
|
305
|
+
// If we're failing due to an error thrown by us, it might be because the token we're using is invalid.
|
|
306
|
+
// To account for that, we try to retrieve the config again, this time without a token, to avoid making
|
|
307
|
+
// any API calls.
|
|
308
|
+
//
|
|
309
|
+
// @todo Replace this with a mechanism for calling `resolveConfig` with more granularity (i.e. having
|
|
310
|
+
// the option to say that we don't need API data.)
|
|
311
|
+
if (isUserError && !offline && token) {
|
|
312
|
+
return this.getConfig({ cwd, offline: true, state, token })
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const message = isUserError ? error_.message : error_.stack
|
|
316
|
+
console.error(message)
|
|
317
|
+
exit(1)
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
module.exports = { BaseCommand }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const { getBuildOptions, runBuild } = require('../../lib/build')
|
|
3
|
+
const { error, exit, generateExamplesHelp, getToken } = require('../../utils')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {import('../../lib/build').BuildConfig} options
|
|
7
|
+
*/
|
|
8
|
+
const checkOptions = ({ cachedConfig: { siteInfo = {} }, token }) => {
|
|
9
|
+
if (!siteInfo.id) {
|
|
10
|
+
error('Could not find the site ID. Please run netlify link.')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!token) {
|
|
14
|
+
error('Could not find the access token. Please run netlify login.')
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The build command
|
|
20
|
+
* @param {import('commander').OptionValues} options
|
|
21
|
+
* @param {import('../base-command').BaseCommand} command
|
|
22
|
+
*/
|
|
23
|
+
const build = async (options, command) => {
|
|
24
|
+
command.setAnalyticsPayload({ dry: options.dry })
|
|
25
|
+
|
|
26
|
+
// Retrieve Netlify Build options
|
|
27
|
+
const [token] = await getToken()
|
|
28
|
+
|
|
29
|
+
const buildOptions = await getBuildOptions({
|
|
30
|
+
cachedConfig: command.netlify.cachedConfig,
|
|
31
|
+
token,
|
|
32
|
+
options,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
if (!options.offline) {
|
|
36
|
+
checkOptions(buildOptions)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const { exitCode } = await runBuild(buildOptions)
|
|
40
|
+
exit(exitCode)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Creates the `netlify build` command
|
|
45
|
+
* @param {import('../base-command').BaseCommand} program
|
|
46
|
+
* @returns
|
|
47
|
+
*/
|
|
48
|
+
const createBuildCommand = (program) =>
|
|
49
|
+
program
|
|
50
|
+
.command('build')
|
|
51
|
+
.description('(Beta) Build on your local machine')
|
|
52
|
+
.option('--dry', 'Dry run: show instructions without running them', false)
|
|
53
|
+
.option('--context [context]', 'Build context')
|
|
54
|
+
.option('-o, --offline', 'disables any features that require network access', false)
|
|
55
|
+
.addHelpText('after', generateExamplesHelp(['netlify build']))
|
|
56
|
+
.action(build)
|
|
57
|
+
|
|
58
|
+
module.exports = { createBuildCommand }
|
|
@@ -1,63 +1,5 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { createBuildCommand } = require('./build')
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const { error, exit, getToken } = require('../../utils/command-helpers')
|
|
6
|
-
|
|
7
|
-
const checkOptions = ({ cachedConfig: { siteInfo = {} }, token }) => {
|
|
8
|
-
if (!siteInfo.id) {
|
|
9
|
-
error('Could not find the site ID. Please run netlify link.', { exit: 1 })
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
if (!token) {
|
|
13
|
-
error('Could not find the access token. Please run netlify login.', { exit: 1 })
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
class BuildCommand extends Command {
|
|
18
|
-
// Run Netlify Build
|
|
19
|
-
async run() {
|
|
20
|
-
const { flags } = this.parse(BuildCommand)
|
|
21
|
-
|
|
22
|
-
this.setAnalyticsPayload({ dry: flags.dry })
|
|
23
|
-
|
|
24
|
-
// Retrieve Netlify Build options
|
|
25
|
-
const [token] = await getToken()
|
|
26
|
-
|
|
27
|
-
const options = await getBuildOptions({
|
|
28
|
-
context: this,
|
|
29
|
-
token,
|
|
30
|
-
flags,
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
if (!flags.offline) {
|
|
34
|
-
checkOptions(options)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const { exitCode } = await runBuild(options)
|
|
38
|
-
exit(exitCode)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Netlify Build programmatic options
|
|
43
|
-
BuildCommand.flags = {
|
|
44
|
-
dry: flagsLib.boolean({
|
|
45
|
-
description: 'Dry run: show instructions without running them',
|
|
46
|
-
default: false,
|
|
47
|
-
}),
|
|
48
|
-
context: flagsLib.string({
|
|
49
|
-
description: 'Build context',
|
|
50
|
-
}),
|
|
51
|
-
offline: flagsLib.boolean({
|
|
52
|
-
char: 'o',
|
|
53
|
-
description: 'disables any features that require network access',
|
|
54
|
-
default: false,
|
|
55
|
-
}),
|
|
56
|
-
...BuildCommand.flags,
|
|
3
|
+
module.exports = {
|
|
4
|
+
createBuildCommand,
|
|
57
5
|
}
|
|
58
|
-
|
|
59
|
-
BuildCommand.description = `(Beta) Build on your local machine`
|
|
60
|
-
|
|
61
|
-
BuildCommand.examples = ['netlify build']
|
|
62
|
-
|
|
63
|
-
module.exports = BuildCommand
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The completion command
|
|
3
|
+
* @param {import('commander').OptionValues} options
|
|
4
|
+
* @param {import('../base-command').BaseCommand} command
|
|
5
|
+
*/
|
|
6
|
+
const completion = (options, command) => {
|
|
7
|
+
console.log('completion command with options', options, command.name())
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates the `netlify completion` command
|
|
12
|
+
* @param {import('../base-command').BaseCommand} program
|
|
13
|
+
* @returns
|
|
14
|
+
*/
|
|
15
|
+
const createCompletionCommand = (program) =>
|
|
16
|
+
program.command('completion').description('(Beta) Generate shell completion script').action(completion)
|
|
17
|
+
|
|
18
|
+
module.exports = { createCompletionCommand }
|