netlify-cli 15.10.0-rc.1 → 15.11.0
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.mjs +5 -6
- package/npm-shrinkwrap.json +3 -6
- package/package.json +2 -1
- package/src/commands/base-command.mjs +116 -295
- package/src/commands/build/build.mjs +1 -9
- package/src/commands/deploy/deploy.mjs +9 -23
- package/src/commands/dev/dev.mjs +17 -22
- package/src/commands/functions/functions-create.mjs +89 -118
- package/src/commands/functions/functions-invoke.mjs +7 -10
- package/src/commands/functions/functions-list.mjs +2 -2
- package/src/commands/init/init.mjs +1 -1
- package/src/commands/link/link.mjs +5 -5
- package/src/commands/serve/serve.mjs +6 -10
- package/src/commands/sites/sites-create-template.mjs +1 -1
- package/src/commands/sites/sites-create.mjs +1 -1
- package/src/lib/edge-functions/internal.mjs +3 -5
- package/src/lib/edge-functions/proxy.mjs +3 -27
- package/src/lib/functions/netlify-function.mjs +26 -1
- package/src/lib/functions/registry.mjs +14 -26
- package/src/lib/functions/runtimes/js/worker.mjs +1 -1
- package/src/lib/spinner.mjs +1 -1
- package/src/recipes/vscode/index.mjs +6 -24
- package/src/utils/command-helpers.mjs +7 -16
- package/src/utils/detect-server-settings.mjs +245 -133
- package/src/utils/framework-server.mjs +5 -6
- package/src/utils/functions/functions.mjs +5 -8
- package/src/utils/get-repo-data.mjs +6 -5
- package/src/utils/init/config-github.mjs +2 -2
- package/src/utils/init/config-manual.mjs +7 -24
- package/src/utils/init/frameworks.mjs +23 -0
- package/src/utils/init/utils.mjs +63 -62
- package/src/utils/proxy-server.mjs +4 -7
- package/src/utils/proxy.mjs +3 -4
- package/src/utils/read-repo-url.mjs +0 -4
- package/src/utils/run-build.mjs +32 -58
- package/src/utils/shell.mjs +7 -24
- package/src/utils/state-config.mjs +1 -5
- package/src/utils/static-server.mjs +0 -4
- package/src/utils/build-info.mjs +0 -100
package/bin/run.mjs
CHANGED
|
@@ -4,7 +4,6 @@ import { argv } from 'process'
|
|
|
4
4
|
import updateNotifier from 'update-notifier'
|
|
5
5
|
|
|
6
6
|
import { createMainCommand } from '../src/commands/index.mjs'
|
|
7
|
-
import { error } from '../src/utils/command-helpers.mjs'
|
|
8
7
|
import getPackageJson from '../src/utils/get-package-json.mjs'
|
|
9
8
|
|
|
10
9
|
// 12 hours
|
|
@@ -16,9 +15,9 @@ try {
|
|
|
16
15
|
pkg,
|
|
17
16
|
updateCheckInterval: UPDATE_CHECK_INTERVAL,
|
|
18
17
|
}).notify()
|
|
19
|
-
} catch (
|
|
20
|
-
|
|
21
|
-
error
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.log('Error checking for updates:')
|
|
20
|
+
console.log(error)
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
const program = createMainCommand()
|
|
@@ -26,6 +25,6 @@ const program = createMainCommand()
|
|
|
26
25
|
try {
|
|
27
26
|
await program.parseAsync(argv)
|
|
28
27
|
program.onEnd()
|
|
29
|
-
} catch (
|
|
30
|
-
program.onEnd(
|
|
28
|
+
} catch (error) {
|
|
29
|
+
program.onEnd(error)
|
|
31
30
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.11.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "netlify-cli",
|
|
9
|
-
"version": "15.
|
|
9
|
+
"version": "15.11.0",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"@netlify/build-info": "7.7.3",
|
|
17
17
|
"@netlify/config": "20.6.4",
|
|
18
18
|
"@netlify/edge-bundler": "8.17.1",
|
|
19
|
+
"@netlify/framework-info": "9.8.10",
|
|
19
20
|
"@netlify/local-functions-proxy": "1.1.1",
|
|
20
21
|
"@netlify/serverless-functions-api": "1.5.2",
|
|
21
22
|
"@netlify/zip-it-and-ship-it": "9.13.1",
|
|
@@ -14676,10 +14677,6 @@
|
|
|
14676
14677
|
"engines": {
|
|
14677
14678
|
"node": ">= 10"
|
|
14678
14679
|
}
|
|
14679
|
-
},
|
|
14680
|
-
"tools/lint-rules": {
|
|
14681
|
-
"name": "eslint-plugin-workspace",
|
|
14682
|
-
"extraneous": true
|
|
14683
14680
|
}
|
|
14684
14681
|
},
|
|
14685
14682
|
"dependencies": {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "netlify-cli",
|
|
3
3
|
"description": "Netlify command line tool",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.11.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"@netlify/build-info": "7.7.3",
|
|
49
49
|
"@netlify/config": "20.6.4",
|
|
50
50
|
"@netlify/edge-bundler": "8.17.1",
|
|
51
|
+
"@netlify/framework-info": "9.8.10",
|
|
51
52
|
"@netlify/local-functions-proxy": "1.1.1",
|
|
52
53
|
"@netlify/serverless-functions-api": "1.5.2",
|
|
53
54
|
"@netlify/zip-it-and-ship-it": "9.13.1",
|
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
import { existsSync } from 'fs'
|
|
3
|
-
import { join, relative, resolve } from 'path'
|
|
4
2
|
import process from 'process'
|
|
5
3
|
import { format } from 'util'
|
|
6
4
|
|
|
7
|
-
import {
|
|
5
|
+
import { Project } from '@netlify/build-info'
|
|
8
6
|
// eslint-disable-next-line import/extensions, n/no-missing-import
|
|
9
|
-
import { NodeFS
|
|
7
|
+
import { NodeFS } from '@netlify/build-info/node'
|
|
10
8
|
import { resolveConfig } from '@netlify/config'
|
|
11
9
|
import { Command, Option } from 'commander'
|
|
12
10
|
import debug from 'debug'
|
|
13
|
-
import { findUp } from 'find-up'
|
|
14
|
-
import inquirer from 'inquirer'
|
|
15
|
-
import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt'
|
|
16
11
|
import merge from 'lodash/merge.js'
|
|
17
12
|
import { NetlifyAPI } from 'netlify'
|
|
18
13
|
|
|
@@ -35,31 +30,22 @@ import getGlobalConfig from '../utils/get-global-config.mjs'
|
|
|
35
30
|
import { getSiteByName } from '../utils/get-site.mjs'
|
|
36
31
|
import openBrowser from '../utils/open-browser.mjs'
|
|
37
32
|
import StateConfig from '../utils/state-config.mjs'
|
|
38
|
-
import { identify,
|
|
33
|
+
import { identify, track } from '../utils/telemetry/index.mjs'
|
|
39
34
|
|
|
40
|
-
//
|
|
41
|
-
inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
|
|
42
|
-
/** Netlify CLI client id. Lives in bot@netlify.com */
|
|
35
|
+
// Netlify CLI client id. Lives in bot@netlify.com
|
|
43
36
|
// TODO: setup client for multiple environments
|
|
44
37
|
const CLIENT_ID = 'd6f37de6614df7ae58664cfca524744d73807a377f5ee71f1a254f78412e3750'
|
|
45
38
|
|
|
46
39
|
const NANO_SECS_TO_MSECS = 1e6
|
|
47
|
-
|
|
40
|
+
// The fallback width for the help terminal
|
|
48
41
|
const FALLBACK_HELP_CMD_WIDTH = 80
|
|
49
42
|
|
|
50
43
|
const HELP_$ = NETLIFY_CYAN('$')
|
|
51
|
-
|
|
44
|
+
// indent on commands or description on the help page
|
|
52
45
|
const HELP_INDENT_WIDTH = 2
|
|
53
|
-
|
|
46
|
+
// separator width between term and description
|
|
54
47
|
const HELP_SEPARATOR_WIDTH = 5
|
|
55
48
|
|
|
56
|
-
/**
|
|
57
|
-
* A list of commands where we don't have to perform the workspace selection at.
|
|
58
|
-
* Those commands work with the system or are not writing any config files that need to be
|
|
59
|
-
* workspace aware.
|
|
60
|
-
*/
|
|
61
|
-
const COMMANDS_WITHOUT_WORKSPACE_OPTIONS = new Set(['recipes', 'completion', 'status', 'switch', 'login', 'lm'])
|
|
62
|
-
|
|
63
49
|
/**
|
|
64
50
|
* Formats a help list correctly with the correct indent
|
|
65
51
|
* @param {string[]} textArray
|
|
@@ -78,83 +64,30 @@ const getDuration = function (startTime) {
|
|
|
78
64
|
}
|
|
79
65
|
|
|
80
66
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* @
|
|
84
|
-
* @
|
|
85
|
-
* @
|
|
67
|
+
* The netlify object inside each command with the state
|
|
68
|
+
* @typedef NetlifyOptions
|
|
69
|
+
* @type {object}
|
|
70
|
+
* @property {import('netlify').NetlifyAPI} api
|
|
71
|
+
* @property {*} repositoryRoot
|
|
72
|
+
* @property {object} site
|
|
73
|
+
* @property {*} site.root
|
|
74
|
+
* @property {*} site.configPath
|
|
75
|
+
* @property {*} site.id
|
|
76
|
+
* @property {*} siteInfo
|
|
77
|
+
* @property {*} config
|
|
78
|
+
* @property {*} cachedConfig
|
|
79
|
+
* @property {*} globalConfig
|
|
80
|
+
* @property {import('../../utils/state-config.mjs').default} state,
|
|
86
81
|
*/
|
|
87
|
-
async function selectWorkspace(project, filter) {
|
|
88
|
-
const selected = project.workspace?.packages.find((pkg) => {
|
|
89
|
-
if (
|
|
90
|
-
project.relativeBaseDirectory &&
|
|
91
|
-
project.relativeBaseDirectory.length !== 0 &&
|
|
92
|
-
pkg.path.startsWith(project.relativeBaseDirectory)
|
|
93
|
-
) {
|
|
94
|
-
return true
|
|
95
|
-
}
|
|
96
|
-
return (pkg.name && pkg.name === filter) || pkg.path === filter
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
if (!selected) {
|
|
100
|
-
log()
|
|
101
|
-
log(chalk.cyan(`We've detected multiple sites inside your repository!`))
|
|
102
|
-
|
|
103
|
-
const { result } = await inquirer.prompt({
|
|
104
|
-
name: 'result',
|
|
105
|
-
type: 'autocomplete',
|
|
106
|
-
message: 'Select a site you want to work with',
|
|
107
|
-
source: (/** @type {string} */ _, input = '') =>
|
|
108
|
-
(project.workspace?.packages || [])
|
|
109
|
-
.filter((pkg) => pkg.path.includes(input))
|
|
110
|
-
.map((pkg) => ({
|
|
111
|
-
name: `${pkg.name ? `${chalk.bold(pkg.name)} ` : ''}${pkg.path} ${chalk.dim(
|
|
112
|
-
`--filter ${pkg.name || pkg.path}`,
|
|
113
|
-
)}`,
|
|
114
|
-
value: pkg.path,
|
|
115
|
-
})),
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
return result
|
|
119
|
-
}
|
|
120
|
-
return selected.path
|
|
121
|
-
}
|
|
122
82
|
|
|
123
83
|
/** Base command class that provides tracking and config initialization */
|
|
124
84
|
export default class BaseCommand extends Command {
|
|
125
|
-
/**
|
|
126
|
-
* The netlify object inside each command with the state
|
|
127
|
-
* @type {import('./types.js').NetlifyOptions}
|
|
128
|
-
*/
|
|
85
|
+
/** @type {NetlifyOptions} */
|
|
129
86
|
netlify
|
|
130
87
|
|
|
131
88
|
/** @type {{ startTime: bigint, payload?: any}} */
|
|
132
89
|
analytics = { startTime: process.hrtime.bigint() }
|
|
133
90
|
|
|
134
|
-
/** @type {Project} */
|
|
135
|
-
project
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* The working directory that is used for reading the `netlify.toml` file and storing the state.
|
|
139
|
-
* In a monorepo context this must not be the process working directory and can be an absolute path to the
|
|
140
|
-
* Package/Site that should be worked in.
|
|
141
|
-
*/
|
|
142
|
-
// here we actually want to disable the lint rule as it's value is set
|
|
143
|
-
// eslint-disable-next-line workspace/no-process-cwd
|
|
144
|
-
workingDir = process.cwd()
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* The workspace root if inside a mono repository.
|
|
148
|
-
* Must not be the repository root!
|
|
149
|
-
* @type {string|undefined}
|
|
150
|
-
*/
|
|
151
|
-
jsWorkspaceRoot
|
|
152
|
-
/**
|
|
153
|
-
* The current workspace package we should execute the commands in
|
|
154
|
-
* @type {string|undefined}
|
|
155
|
-
*/
|
|
156
|
-
workspacePackage
|
|
157
|
-
|
|
158
91
|
/**
|
|
159
92
|
* IMPORTANT this function will be called for each command!
|
|
160
93
|
* Don't do anything expensive in there.
|
|
@@ -162,61 +95,49 @@ export default class BaseCommand extends Command {
|
|
|
162
95
|
* @returns
|
|
163
96
|
*/
|
|
164
97
|
createCommand(name) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
'Old, prefer --http-proxy-certificate-filename. Certificate file to use when connecting using a proxy server.',
|
|
98
|
+
return (
|
|
99
|
+
new BaseCommand(name)
|
|
100
|
+
// If --silent or --json flag passed disable logger
|
|
101
|
+
.addOption(new Option('--json', 'Output return values as JSON').hideHelp(true))
|
|
102
|
+
.addOption(new Option('--silent', 'Silence CLI output').hideHelp(true))
|
|
103
|
+
.addOption(new Option('--cwd <cwd>').hideHelp(true))
|
|
104
|
+
.addOption(new Option('-o, --offline').hideHelp(true))
|
|
105
|
+
.addOption(new Option('--auth <token>', 'Netlify auth token').hideHelp(true))
|
|
106
|
+
.addOption(
|
|
107
|
+
new Option(
|
|
108
|
+
'--httpProxy [address]',
|
|
109
|
+
'Old, prefer --http-proxy. Proxy server address to route requests through.',
|
|
110
|
+
)
|
|
111
|
+
.default(process.env.HTTP_PROXY || process.env.HTTPS_PROXY)
|
|
112
|
+
.hideHelp(true),
|
|
181
113
|
)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
114
|
+
.addOption(
|
|
115
|
+
new Option(
|
|
116
|
+
'--httpProxyCertificateFilename [file]',
|
|
117
|
+
'Old, prefer --http-proxy-certificate-filename. Certificate file to use when connecting using a proxy server.',
|
|
118
|
+
)
|
|
119
|
+
.default(process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME)
|
|
120
|
+
.hideHelp(true),
|
|
121
|
+
)
|
|
122
|
+
.option(
|
|
187
123
|
'--http-proxy-certificate-filename [file]',
|
|
188
124
|
'Certificate file to use when connecting using a proxy server',
|
|
125
|
+
process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME,
|
|
189
126
|
)
|
|
190
|
-
.default(process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME)
|
|
191
|
-
.hideHelp(true),
|
|
192
|
-
)
|
|
193
|
-
.addOption(
|
|
194
|
-
new Option('--httpProxy [address]', 'Proxy server address to route requests through.')
|
|
195
|
-
.default(process.env.HTTP_PROXY || process.env.HTTPS_PROXY)
|
|
196
|
-
.hideHelp(true),
|
|
197
|
-
)
|
|
198
|
-
.option('--debug', 'Print debugging information')
|
|
199
|
-
|
|
200
|
-
// only add the `--config` or `--filter` option to commands that are workspace aware
|
|
201
|
-
if (!COMMANDS_WITHOUT_WORKSPACE_OPTIONS.has(name)) {
|
|
202
|
-
base
|
|
203
|
-
.option('--config <configFilePath>', 'Custom path to a netlify configuration file')
|
|
204
127
|
.option(
|
|
205
|
-
'--
|
|
206
|
-
'
|
|
128
|
+
'--http-proxy [address]',
|
|
129
|
+
'Proxy server address to route requests through.',
|
|
130
|
+
process.env.HTTP_PROXY || process.env.HTTPS_PROXY,
|
|
207
131
|
)
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
await this.init(actionCommand)
|
|
218
|
-
debug(`${name}:preAction`)('end')
|
|
219
|
-
})
|
|
132
|
+
.option('--debug', 'Print debugging information')
|
|
133
|
+
.hook('preAction', async (_parentCommand, actionCommand) => {
|
|
134
|
+
debug(`${name}:preAction`)('start')
|
|
135
|
+
this.analytics = { startTime: process.hrtime.bigint() }
|
|
136
|
+
// @ts-ignore cannot type actionCommand as BaseCommand
|
|
137
|
+
await this.init(actionCommand)
|
|
138
|
+
debug(`${name}:preAction`)('end')
|
|
139
|
+
})
|
|
140
|
+
)
|
|
220
141
|
}
|
|
221
142
|
|
|
222
143
|
/** @private */
|
|
@@ -228,7 +149,7 @@ export default class BaseCommand extends Command {
|
|
|
228
149
|
return this
|
|
229
150
|
}
|
|
230
151
|
|
|
231
|
-
/**
|
|
152
|
+
/** The examples list for the command (used inside doc generation and help page) */
|
|
232
153
|
examples = []
|
|
233
154
|
|
|
234
155
|
/**
|
|
@@ -251,27 +172,23 @@ export default class BaseCommand extends Command {
|
|
|
251
172
|
const term =
|
|
252
173
|
this.name() === 'netlify'
|
|
253
174
|
? `${HELP_$} ${command.name()} [COMMAND]`
|
|
254
|
-
: `${HELP_$} ${command.parent
|
|
175
|
+
: `${HELP_$} ${command.parent.name()} ${command.name()} ${command.usage()}`
|
|
255
176
|
|
|
256
177
|
return padLeft(term, HELP_INDENT_WIDTH)
|
|
257
178
|
}
|
|
258
179
|
|
|
259
|
-
/**
|
|
260
|
-
* @param {BaseCommand} command
|
|
261
|
-
*/
|
|
262
180
|
const getCommands = (command) => {
|
|
263
181
|
const parentCommand = this.name() === 'netlify' ? command : command.parent
|
|
264
|
-
return (
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
)
|
|
182
|
+
return parentCommand.commands.filter((cmd) => {
|
|
183
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
184
|
+
if (cmd._hidden) return false
|
|
185
|
+
// the root command
|
|
186
|
+
if (this.name() === 'netlify') {
|
|
187
|
+
// don't include subcommands on the main page
|
|
188
|
+
return !cmd.name().includes(':')
|
|
189
|
+
}
|
|
190
|
+
return cmd.name().startsWith(`${command.name()}:`)
|
|
191
|
+
})
|
|
275
192
|
}
|
|
276
193
|
|
|
277
194
|
/**
|
|
@@ -364,8 +281,9 @@ export default class BaseCommand extends Command {
|
|
|
364
281
|
}
|
|
365
282
|
|
|
366
283
|
// Aliases
|
|
367
|
-
|
|
284
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
368
285
|
if (command._aliases.length !== 0) {
|
|
286
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
369
287
|
const aliases = command._aliases.map((alias) => formatItem(`${parentCommand.name()} ${alias}`, null, true))
|
|
370
288
|
output = [...output, chalk.bold('ALIASES'), formatHelpList(aliases), '']
|
|
371
289
|
}
|
|
@@ -419,11 +337,6 @@ export default class BaseCommand extends Command {
|
|
|
419
337
|
}
|
|
420
338
|
}
|
|
421
339
|
|
|
422
|
-
/**
|
|
423
|
-
*
|
|
424
|
-
* @param {string|undefined} tokenFromFlag
|
|
425
|
-
* @returns
|
|
426
|
-
*/
|
|
427
340
|
async authenticate(tokenFromFlag) {
|
|
428
341
|
const [token] = await getToken(tokenFromFlag)
|
|
429
342
|
if (token) {
|
|
@@ -493,10 +406,6 @@ export default class BaseCommand extends Command {
|
|
|
493
406
|
return accessToken
|
|
494
407
|
}
|
|
495
408
|
|
|
496
|
-
/**
|
|
497
|
-
* Adds some data to the analytics payload
|
|
498
|
-
* @param {Record<string, unknown>} payload
|
|
499
|
-
*/
|
|
500
409
|
setAnalyticsPayload(payload) {
|
|
501
410
|
const newPayload = { ...this.analytics.payload, ...payload }
|
|
502
411
|
this.analytics = { ...this.analytics, payload: newPayload }
|
|
@@ -509,58 +418,12 @@ export default class BaseCommand extends Command {
|
|
|
509
418
|
*/
|
|
510
419
|
async init(actionCommand) {
|
|
511
420
|
debug(`${actionCommand.name()}:init`)('start')
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
//
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
// ==================================================
|
|
518
|
-
// Create a Project and run the Heuristics to detect
|
|
519
|
-
// if we are run inside a monorepo or not.
|
|
520
|
-
// ==================================================
|
|
521
|
-
|
|
522
|
-
// retrieve the repository root
|
|
523
|
-
const rootDir = await getRepositoryRoot()
|
|
524
|
-
// Get framework, add to analytics payload for every command, if a framework is set
|
|
525
|
-
const fs = new NodeFS()
|
|
526
|
-
// disable logging inside the project and FS if not in debug mode
|
|
527
|
-
fs.logger = actionCommand.opts()?.debug ? new DefaultLogger('debug') : new NoopLogger()
|
|
528
|
-
this.project = new Project(fs, this.workingDir, rootDir)
|
|
529
|
-
.setEnvironment(process.env)
|
|
530
|
-
.setNodeVersion(process.version)
|
|
531
|
-
// eslint-disable-next-line promise/prefer-await-to-callbacks
|
|
532
|
-
.setReportFn((err, reportConfig) => {
|
|
533
|
-
reportError(err, {
|
|
534
|
-
severity: reportConfig?.severity || 'error',
|
|
535
|
-
metadata: reportConfig?.metadata,
|
|
536
|
-
})
|
|
537
|
-
})
|
|
538
|
-
const frameworks = await this.project.detectFrameworks()
|
|
539
|
-
/** @type { string|undefined} */
|
|
540
|
-
let packageConfig = flags.config ? resolve(flags.config) : undefined
|
|
541
|
-
// check if we have detected multiple projects inside which one we have to perform our operations.
|
|
542
|
-
// only ask to select one if on the workspace root
|
|
543
|
-
if (
|
|
544
|
-
!COMMANDS_WITHOUT_WORKSPACE_OPTIONS.has(actionCommand.name()) &&
|
|
545
|
-
this.project.workspace?.packages.length &&
|
|
546
|
-
this.project.workspace.isRoot
|
|
547
|
-
) {
|
|
548
|
-
this.workspacePackage = await selectWorkspace(this.project, actionCommand.opts().filter)
|
|
549
|
-
this.workingDir = join(this.project.jsWorkspaceRoot, this.workspacePackage)
|
|
550
|
-
}
|
|
421
|
+
const options = actionCommand.opts()
|
|
422
|
+
const cwd = options.cwd || process.cwd()
|
|
423
|
+
// Get site id & build state
|
|
424
|
+
const state = new StateConfig(cwd)
|
|
551
425
|
|
|
552
|
-
|
|
553
|
-
// detect if a toml exists in this package.
|
|
554
|
-
const tomlFile = join(this.workingDir, 'netlify.toml')
|
|
555
|
-
if (!packageConfig && existsSync(tomlFile)) {
|
|
556
|
-
packageConfig = tomlFile
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// ==================================================
|
|
560
|
-
// Retrieve Site id and build state from the state.json
|
|
561
|
-
// ==================================================
|
|
562
|
-
const state = new StateConfig(this.workingDir)
|
|
563
|
-
const [token] = await getToken(flags.auth)
|
|
426
|
+
const [token] = await getToken(options.auth)
|
|
564
427
|
|
|
565
428
|
const apiUrlOpts = {
|
|
566
429
|
userAgent: USER_AGENT,
|
|
@@ -574,24 +437,12 @@ export default class BaseCommand extends Command {
|
|
|
574
437
|
process.env.NETLIFY_API_URL === `${apiUrl.protocol}//${apiUrl.host}` ? '/api/v1' : apiUrl.pathname
|
|
575
438
|
}
|
|
576
439
|
|
|
577
|
-
|
|
578
|
-
// Start retrieving the configuration through the
|
|
579
|
-
// configuration file and the API
|
|
580
|
-
// ==================================================
|
|
581
|
-
const cachedConfig = await actionCommand.getConfig({
|
|
582
|
-
cwd: this.jsWorkspaceRoot || this.workingDir,
|
|
583
|
-
repositoryRoot: rootDir,
|
|
584
|
-
// The config flag needs to be resolved from the actual process working directory
|
|
585
|
-
configFilePath: packageConfig,
|
|
586
|
-
state,
|
|
587
|
-
token,
|
|
588
|
-
...apiUrlOpts,
|
|
589
|
-
})
|
|
440
|
+
const cachedConfig = await actionCommand.getConfig({ cwd, state, token, ...apiUrlOpts })
|
|
590
441
|
const { buildDir, config, configPath, repositoryRoot, siteInfo } = cachedConfig
|
|
591
442
|
const normalizedConfig = normalizeConfig(config)
|
|
592
443
|
const agent = await getAgent({
|
|
593
|
-
httpProxy:
|
|
594
|
-
certificateFile:
|
|
444
|
+
httpProxy: options.httpProxy,
|
|
445
|
+
certificateFile: options.httpProxyCertificateFilename,
|
|
595
446
|
})
|
|
596
447
|
const apiOpts = { ...apiUrlOpts, agent }
|
|
597
448
|
const api = new NetlifyAPI(token || '', apiOpts)
|
|
@@ -603,44 +454,33 @@ export default class BaseCommand extends Command {
|
|
|
603
454
|
// options.site as a site name (and not just site id) was introduced for the deploy command, so users could
|
|
604
455
|
// deploy by name along with by id
|
|
605
456
|
let siteData = siteInfo
|
|
606
|
-
if (!siteData.url &&
|
|
607
|
-
siteData = await getSiteByName(api,
|
|
457
|
+
if (!siteData.url && options.site) {
|
|
458
|
+
siteData = await getSiteByName(api, options.site)
|
|
608
459
|
}
|
|
609
460
|
|
|
610
461
|
const globalConfig = await getGlobalConfig()
|
|
611
462
|
|
|
612
|
-
//
|
|
613
|
-
|
|
614
|
-
|
|
463
|
+
// Get framework, add to analytics payload for every command, if a framework is set
|
|
464
|
+
const fs = new NodeFS()
|
|
465
|
+
const project = new Project(fs, buildDir)
|
|
466
|
+
const frameworks = await project.detectFrameworks()
|
|
467
|
+
|
|
615
468
|
const frameworkIDs = frameworks?.map((framework) => framework.id)
|
|
469
|
+
|
|
616
470
|
if (frameworkIDs?.length !== 0) {
|
|
617
471
|
this.setAnalyticsPayload({ frameworks: frameworkIDs })
|
|
618
472
|
}
|
|
473
|
+
|
|
619
474
|
this.setAnalyticsPayload({
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
buildSystem: this.project.buildSystems.map(({ id }) => id),
|
|
475
|
+
packageManager: project.packageManager?.name,
|
|
476
|
+
buildSystem: project.buildSystems.map(({ id }) => id),
|
|
623
477
|
})
|
|
624
478
|
|
|
625
|
-
// set the project and the netlify api object on the command,
|
|
626
|
-
// to be accessible inside each command.
|
|
627
|
-
actionCommand.project = this.project
|
|
628
|
-
actionCommand.workingDir = this.workingDir
|
|
629
|
-
actionCommand.workspacePackage = this.workspacePackage
|
|
630
|
-
actionCommand.jsWorkspaceRoot = this.jsWorkspaceRoot
|
|
631
|
-
|
|
632
|
-
// Either an existing configuration file from `@netlify/config` or a file path
|
|
633
|
-
// that should be used for creating it.
|
|
634
|
-
const configFilePath = configPath || join(this.workingDir, 'netlify.toml')
|
|
635
|
-
|
|
636
479
|
actionCommand.netlify = {
|
|
637
480
|
// api methods
|
|
638
481
|
api,
|
|
639
482
|
apiOpts,
|
|
640
|
-
// The Absolute Repository root (detected through @netlify/config)
|
|
641
483
|
repositoryRoot,
|
|
642
|
-
configFilePath,
|
|
643
|
-
relConfigFilePath: relative(repositoryRoot, configFilePath),
|
|
644
484
|
// current site context
|
|
645
485
|
site: {
|
|
646
486
|
root: buildDir,
|
|
@@ -668,36 +508,26 @@ export default class BaseCommand extends Command {
|
|
|
668
508
|
|
|
669
509
|
/**
|
|
670
510
|
* Find and resolve the Netlify configuration
|
|
671
|
-
* @param {
|
|
672
|
-
* @
|
|
673
|
-
* @param {string|null=} config.token
|
|
674
|
-
* @param {*} config.state
|
|
675
|
-
* @param {boolean=} config.offline
|
|
676
|
-
* @param {string=} config.configFilePath An optional path to the netlify configuration file e.g. netlify.toml
|
|
677
|
-
* @param {string=} config.repositoryRoot
|
|
678
|
-
* @param {string=} config.host
|
|
679
|
-
* @param {string=} config.pathPrefix
|
|
680
|
-
* @param {string=} config.scheme
|
|
681
|
-
* @returns {ReturnType<typeof resolveConfig>}
|
|
511
|
+
* @param {*} config
|
|
512
|
+
* @returns {ReturnType<import('@netlify/config/src/main')>}
|
|
682
513
|
*/
|
|
683
514
|
async getConfig(config) {
|
|
684
|
-
|
|
685
|
-
const
|
|
515
|
+
const options = this.opts()
|
|
516
|
+
const { cwd, host, offline = options.offline, pathPrefix, scheme, state, token } = config
|
|
686
517
|
|
|
687
518
|
try {
|
|
688
519
|
return await resolveConfig({
|
|
689
|
-
config: config
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
token: config.token,
|
|
520
|
+
config: options.config,
|
|
521
|
+
cwd,
|
|
522
|
+
context: options.context || process.env.CONTEXT || this.getDefaultContext(),
|
|
523
|
+
debug: this.opts().debug,
|
|
524
|
+
siteId: options.siteId || (typeof options.site === 'string' && options.site) || state.get('siteId'),
|
|
525
|
+
token,
|
|
696
526
|
mode: 'cli',
|
|
697
|
-
host
|
|
698
|
-
pathPrefix
|
|
699
|
-
scheme
|
|
700
|
-
offline
|
|
527
|
+
host,
|
|
528
|
+
pathPrefix,
|
|
529
|
+
scheme,
|
|
530
|
+
offline,
|
|
701
531
|
siteFeatureFlagPrefix: 'cli',
|
|
702
532
|
})
|
|
703
533
|
} catch (error_) {
|
|
@@ -709,17 +539,17 @@ export default class BaseCommand extends Command {
|
|
|
709
539
|
//
|
|
710
540
|
// @todo Replace this with a mechanism for calling `resolveConfig` with more granularity (i.e. having
|
|
711
541
|
// the option to say that we don't need API data.)
|
|
712
|
-
if (isUserError && !
|
|
713
|
-
if (
|
|
542
|
+
if (isUserError && !offline && token) {
|
|
543
|
+
if (this.opts().debug) {
|
|
714
544
|
error(error_, { exit: false })
|
|
715
545
|
warn('Failed to resolve config, falling back to offline resolution')
|
|
716
546
|
}
|
|
717
|
-
|
|
718
|
-
return this.getConfig({ ...config, offline: true })
|
|
547
|
+
return this.getConfig({ cwd, offline: true, state, token })
|
|
719
548
|
}
|
|
720
549
|
|
|
721
550
|
const message = isUserError ? error_.message : error_.stack
|
|
722
|
-
error(message
|
|
551
|
+
console.error(message)
|
|
552
|
+
exit(1)
|
|
723
553
|
}
|
|
724
554
|
}
|
|
725
555
|
|
|
@@ -728,22 +558,13 @@ export default class BaseCommand extends Command {
|
|
|
728
558
|
* set. The default context is `dev` most of the time, but some commands may
|
|
729
559
|
* wish to override that.
|
|
730
560
|
*
|
|
731
|
-
* @returns {
|
|
561
|
+
* @returns {string}
|
|
732
562
|
*/
|
|
733
563
|
getDefaultContext() {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
}
|
|
564
|
+
if (this.name() === 'serve') {
|
|
565
|
+
return 'production'
|
|
566
|
+
}
|
|
737
567
|
|
|
738
|
-
|
|
739
|
-
* Retrieves the repository root through a git command.
|
|
740
|
-
* Returns undefined if not a git project.
|
|
741
|
-
* @param {string} [cwd] The optional current working directory
|
|
742
|
-
* @returns {Promise<string|undefined>}
|
|
743
|
-
*/
|
|
744
|
-
async function getRepositoryRoot(cwd) {
|
|
745
|
-
const res = await findUp('.git', { cwd, type: 'directory' })
|
|
746
|
-
if (res) {
|
|
747
|
-
return join(res, '..')
|
|
568
|
+
return 'dev'
|
|
748
569
|
}
|
|
749
570
|
}
|