netlify-cli 15.9.1-rc.0 → 15.10.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/npm-shrinkwrap.json +236 -738
- package/package.json +6 -5
- package/src/commands/base-command.mjs +59 -195
- package/src/commands/deploy/deploy.mjs +9 -21
- package/src/commands/dev/dev.mjs +15 -21
- package/src/commands/functions/functions-create.mjs +3 -0
- package/src/commands/functions/functions-invoke.mjs +5 -8
- package/src/commands/init/init.mjs +1 -1
- package/src/commands/link/link.mjs +5 -5
- package/src/commands/serve/serve.mjs +5 -11
- package/src/commands/sites/sites-create-template.mjs +1 -1
- package/src/commands/sites/sites-create.mjs +1 -1
- package/src/functions-templates/typescript/hello-world/package-lock.json +6 -6
- package/src/lib/edge-functions/bootstrap.mjs +1 -1
- package/src/lib/edge-functions/headers.mjs +1 -0
- package/src/lib/edge-functions/internal.mjs +3 -5
- package/src/lib/edge-functions/proxy.mjs +4 -27
- package/src/lib/functions/runtimes/js/index.mjs +1 -1
- package/src/lib/functions/runtimes/js/worker.mjs +1 -1
- package/src/lib/spinner.mjs +1 -1
- package/src/utils/command-helpers.mjs +7 -16
- package/src/utils/detect-server-settings.mjs +198 -147
- package/src/utils/framework-server.mjs +2 -2
- package/src/utils/functions/functions.mjs +0 -7
- 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 +0 -4
- package/src/utils/run-build.mjs +7 -58
- package/src/utils/shell.mjs +3 -14
- package/src/utils/state-config.mjs +1 -5
- package/src/utils/static-server.mjs +0 -4
- package/src/utils/build-info.mjs +0 -19
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.10.0",
|
|
5
5
|
"author": "Netlify Inc.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -44,15 +44,15 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@bugsnag/js": "7.20.2",
|
|
46
46
|
"@fastify/static": "6.10.2",
|
|
47
|
-
"@netlify/build": "29.17.
|
|
48
|
-
"@netlify/build-info": "7.7.
|
|
47
|
+
"@netlify/build": "29.17.3",
|
|
48
|
+
"@netlify/build-info": "7.7.3",
|
|
49
49
|
"@netlify/config": "20.6.4",
|
|
50
|
-
"@netlify/edge-bundler": "8.
|
|
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",
|
|
54
55
|
"@octokit/rest": "19.0.13",
|
|
55
|
-
"@skn0tt/lambda-local": "2.0.3",
|
|
56
56
|
"ansi-escapes": "6.2.0",
|
|
57
57
|
"ansi-styles": "6.2.1",
|
|
58
58
|
"ansi-to-html": "0.7.2",
|
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
"isexe": "2.0.0",
|
|
108
108
|
"jsonwebtoken": "9.0.1",
|
|
109
109
|
"jwt-decode": "3.1.2",
|
|
110
|
+
"lambda-local": "2.1.1",
|
|
110
111
|
"listr": "0.14.3",
|
|
111
112
|
"locate-path": "7.2.0",
|
|
112
113
|
"lodash": "4.17.21",
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
import { join, resolve } from 'path'
|
|
3
2
|
import process from 'process'
|
|
4
3
|
import { format } from 'util'
|
|
5
4
|
|
|
6
|
-
import {
|
|
5
|
+
import { Project } from '@netlify/build-info'
|
|
7
6
|
// eslint-disable-next-line import/extensions, n/no-missing-import
|
|
8
|
-
import { NodeFS
|
|
7
|
+
import { NodeFS } from '@netlify/build-info/node'
|
|
9
8
|
import { resolveConfig } from '@netlify/config'
|
|
10
9
|
import { Command, Option } from 'commander'
|
|
11
10
|
import debug from 'debug'
|
|
12
|
-
import execa from 'execa'
|
|
13
|
-
import inquirer from 'inquirer'
|
|
14
|
-
import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt'
|
|
15
11
|
import merge from 'lodash/merge.js'
|
|
16
12
|
import { NetlifyAPI } from 'netlify'
|
|
17
13
|
|
|
@@ -34,10 +30,8 @@ import getGlobalConfig from '../utils/get-global-config.mjs'
|
|
|
34
30
|
import { getSiteByName } from '../utils/get-site.mjs'
|
|
35
31
|
import openBrowser from '../utils/open-browser.mjs'
|
|
36
32
|
import StateConfig from '../utils/state-config.mjs'
|
|
37
|
-
import { identify,
|
|
33
|
+
import { identify, track } from '../utils/telemetry/index.mjs'
|
|
38
34
|
|
|
39
|
-
// load the autocomplete plugin
|
|
40
|
-
inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
|
|
41
35
|
// Netlify CLI client id. Lives in bot@netlify.com
|
|
42
36
|
// TODO: setup client for multiple environments
|
|
43
37
|
const CLIENT_ID = 'd6f37de6614df7ae58664cfca524744d73807a377f5ee71f1a254f78412e3750'
|
|
@@ -70,73 +64,30 @@ const getDuration = function (startTime) {
|
|
|
70
64
|
}
|
|
71
65
|
|
|
72
66
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* @
|
|
76
|
-
* @
|
|
77
|
-
* @
|
|
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,
|
|
78
81
|
*/
|
|
79
|
-
async function selectWorkspace(project, filter) {
|
|
80
|
-
const selected = project.workspace?.packages.find((pkg) => {
|
|
81
|
-
if (project.relativeBaseDirectory && pkg.path.startsWith(project.relativeBaseDirectory)) {
|
|
82
|
-
return true
|
|
83
|
-
}
|
|
84
|
-
return pkg.name === filter
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
if (!selected) {
|
|
88
|
-
log()
|
|
89
|
-
log(chalk.cyan(`We've detected multiple sites inside your repository!`))
|
|
90
|
-
|
|
91
|
-
const { result } = await inquirer.prompt({
|
|
92
|
-
name: 'result',
|
|
93
|
-
type: 'autocomplete',
|
|
94
|
-
message: 'Select a site you want to work with',
|
|
95
|
-
source: (/** @type {string} */ _, input = '') =>
|
|
96
|
-
(project.workspace?.packages || [])
|
|
97
|
-
.filter((pkg) => pkg.path.includes(input))
|
|
98
|
-
.map((pkg) => ({
|
|
99
|
-
name: `${pkg.name && `${chalk.bold(pkg.name)}`} ${pkg.path} ${
|
|
100
|
-
pkg.name && chalk.dim(`--filter ${pkg.name}`)
|
|
101
|
-
}`,
|
|
102
|
-
value: pkg.path,
|
|
103
|
-
})),
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
return result
|
|
107
|
-
}
|
|
108
|
-
return selected.path
|
|
109
|
-
}
|
|
110
82
|
|
|
111
83
|
/** Base command class that provides tracking and config initialization */
|
|
112
84
|
export default class BaseCommand extends Command {
|
|
113
|
-
/**
|
|
114
|
-
* The netlify object inside each command with the state
|
|
115
|
-
* @type {import('./types.js').NetlifyOptions}
|
|
116
|
-
*/
|
|
85
|
+
/** @type {NetlifyOptions} */
|
|
117
86
|
netlify
|
|
118
87
|
|
|
119
88
|
/** @type {{ startTime: bigint, payload?: any}} */
|
|
120
89
|
analytics = { startTime: process.hrtime.bigint() }
|
|
121
90
|
|
|
122
|
-
/** @type {Project} */
|
|
123
|
-
project
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* The working directory that is used for reading the `netlify.toml` file and storing the state.
|
|
127
|
-
* In a monorepo context this must not be the process working directory and can be an absolute path to the
|
|
128
|
-
* Package/Site that should be worked in.
|
|
129
|
-
*/
|
|
130
|
-
// here we actually want to disable the lint rule as it's value is set
|
|
131
|
-
// eslint-disable-next-line workspace/no-process-cwd
|
|
132
|
-
workingDir = process.cwd()
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* The current workspace package we should execute the commands in
|
|
136
|
-
* @type {string|undefined}
|
|
137
|
-
*/
|
|
138
|
-
workspacePackage
|
|
139
|
-
|
|
140
91
|
/**
|
|
141
92
|
* IMPORTANT this function will be called for each command!
|
|
142
93
|
* Don't do anything expensive in there.
|
|
@@ -179,15 +130,7 @@ export default class BaseCommand extends Command {
|
|
|
179
130
|
process.env.HTTP_PROXY || process.env.HTTPS_PROXY,
|
|
180
131
|
)
|
|
181
132
|
.option('--debug', 'Print debugging information')
|
|
182
|
-
.option('--config <configFilePath>', 'Custom path to a netlify configuration file')
|
|
183
|
-
.option(
|
|
184
|
-
'--filter <app>',
|
|
185
|
-
'Optional name of an application to run the command in.\nThis option is needed for working in Monorepos',
|
|
186
|
-
)
|
|
187
133
|
.hook('preAction', async (_parentCommand, actionCommand) => {
|
|
188
|
-
if (actionCommand.opts()?.debug) {
|
|
189
|
-
process.env.DEBUG = '*'
|
|
190
|
-
}
|
|
191
134
|
debug(`${name}:preAction`)('start')
|
|
192
135
|
this.analytics = { startTime: process.hrtime.bigint() }
|
|
193
136
|
// @ts-ignore cannot type actionCommand as BaseCommand
|
|
@@ -206,7 +149,7 @@ export default class BaseCommand extends Command {
|
|
|
206
149
|
return this
|
|
207
150
|
}
|
|
208
151
|
|
|
209
|
-
/**
|
|
152
|
+
/** The examples list for the command (used inside doc generation and help page) */
|
|
210
153
|
examples = []
|
|
211
154
|
|
|
212
155
|
/**
|
|
@@ -229,7 +172,7 @@ export default class BaseCommand extends Command {
|
|
|
229
172
|
const term =
|
|
230
173
|
this.name() === 'netlify'
|
|
231
174
|
? `${HELP_$} ${command.name()} [COMMAND]`
|
|
232
|
-
: `${HELP_$} ${command.parent
|
|
175
|
+
: `${HELP_$} ${command.parent.name()} ${command.name()} ${command.usage()}`
|
|
233
176
|
|
|
234
177
|
return padLeft(term, HELP_INDENT_WIDTH)
|
|
235
178
|
}
|
|
@@ -394,11 +337,6 @@ export default class BaseCommand extends Command {
|
|
|
394
337
|
}
|
|
395
338
|
}
|
|
396
339
|
|
|
397
|
-
/**
|
|
398
|
-
*
|
|
399
|
-
* @param {string|undefined} tokenFromFlag
|
|
400
|
-
* @returns
|
|
401
|
-
*/
|
|
402
340
|
async authenticate(tokenFromFlag) {
|
|
403
341
|
const [token] = await getToken(tokenFromFlag)
|
|
404
342
|
if (token) {
|
|
@@ -468,10 +406,6 @@ export default class BaseCommand extends Command {
|
|
|
468
406
|
return accessToken
|
|
469
407
|
}
|
|
470
408
|
|
|
471
|
-
/**
|
|
472
|
-
* Adds some data to the analytics payload
|
|
473
|
-
* @param {Record<string, unknown>} payload
|
|
474
|
-
*/
|
|
475
409
|
setAnalyticsPayload(payload) {
|
|
476
410
|
const newPayload = { ...this.analytics.payload, ...payload }
|
|
477
411
|
this.analytics = { ...this.analytics, payload: newPayload }
|
|
@@ -484,45 +418,12 @@ export default class BaseCommand extends Command {
|
|
|
484
418
|
*/
|
|
485
419
|
async init(actionCommand) {
|
|
486
420
|
debug(`${actionCommand.name()}:init`)('start')
|
|
487
|
-
const
|
|
488
|
-
|
|
489
|
-
//
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
// ==================================================
|
|
493
|
-
// Create a Project and run the Heuristics to detect
|
|
494
|
-
// if we are run inside a monorepo or not.
|
|
495
|
-
// ==================================================
|
|
496
|
-
|
|
497
|
-
// retrieve the repository root
|
|
498
|
-
const rootDir = await getRepositoryRoot()
|
|
499
|
-
// Get framework, add to analytics payload for every command, if a framework is set
|
|
500
|
-
const fs = new NodeFS()
|
|
501
|
-
// disable logging inside the project and FS if not in debug mode
|
|
502
|
-
fs.logger = actionCommand.opts()?.debug ? new DefaultLogger('debug') : new NoopLogger()
|
|
503
|
-
this.project = new Project(fs, this.workingDir, rootDir)
|
|
504
|
-
.setEnvironment(process.env)
|
|
505
|
-
.setNodeVersion(process.version)
|
|
506
|
-
// eslint-disable-next-line promise/prefer-await-to-callbacks
|
|
507
|
-
.setReportFn((err, reportConfig) => {
|
|
508
|
-
reportError(err, {
|
|
509
|
-
severity: reportConfig?.severity || 'error',
|
|
510
|
-
metadata: reportConfig?.metadata,
|
|
511
|
-
})
|
|
512
|
-
})
|
|
513
|
-
const frameworks = await this.project.detectFrameworks()
|
|
514
|
-
// check if we have detected multiple projects inside which one we have to perform our operations.
|
|
515
|
-
// only ask to select one if on the workspace root
|
|
516
|
-
if (this.project.workspace?.packages.length && this.project.workspace.isRoot) {
|
|
517
|
-
this.workspacePackage = await selectWorkspace(this.project, actionCommand.opts().filter)
|
|
518
|
-
this.workingDir = join(this.project.jsWorkspaceRoot, this.workspacePackage)
|
|
519
|
-
}
|
|
421
|
+
const options = actionCommand.opts()
|
|
422
|
+
const cwd = options.cwd || process.cwd()
|
|
423
|
+
// Get site id & build state
|
|
424
|
+
const state = new StateConfig(cwd)
|
|
520
425
|
|
|
521
|
-
|
|
522
|
-
// Retrieve Site id and build state from the state.json
|
|
523
|
-
// ==================================================
|
|
524
|
-
const state = new StateConfig(this.workingDir)
|
|
525
|
-
const [token] = await getToken(flags.auth)
|
|
426
|
+
const [token] = await getToken(options.auth)
|
|
526
427
|
|
|
527
428
|
const apiUrlOpts = {
|
|
528
429
|
userAgent: USER_AGENT,
|
|
@@ -536,23 +437,12 @@ export default class BaseCommand extends Command {
|
|
|
536
437
|
process.env.NETLIFY_API_URL === `${apiUrl.protocol}//${apiUrl.host}` ? '/api/v1' : apiUrl.pathname
|
|
537
438
|
}
|
|
538
439
|
|
|
539
|
-
|
|
540
|
-
// Start retrieving the configuration through the
|
|
541
|
-
// configuration file and the API
|
|
542
|
-
// ==================================================
|
|
543
|
-
const cachedConfig = await actionCommand.getConfig({
|
|
544
|
-
cwd: this.workingDir,
|
|
545
|
-
// The config flag needs to be resolved from the actual process working directory
|
|
546
|
-
configFilePath: flags.config ? resolve(flags.config) : undefined,
|
|
547
|
-
state,
|
|
548
|
-
token,
|
|
549
|
-
...apiUrlOpts,
|
|
550
|
-
})
|
|
440
|
+
const cachedConfig = await actionCommand.getConfig({ cwd, state, token, ...apiUrlOpts })
|
|
551
441
|
const { buildDir, config, configPath, repositoryRoot, siteInfo } = cachedConfig
|
|
552
442
|
const normalizedConfig = normalizeConfig(config)
|
|
553
443
|
const agent = await getAgent({
|
|
554
|
-
httpProxy:
|
|
555
|
-
certificateFile:
|
|
444
|
+
httpProxy: options.httpProxy,
|
|
445
|
+
certificateFile: options.httpProxyCertificateFilename,
|
|
556
446
|
})
|
|
557
447
|
const apiOpts = { ...apiUrlOpts, agent }
|
|
558
448
|
const api = new NetlifyAPI(token || '', apiOpts)
|
|
@@ -564,30 +454,28 @@ export default class BaseCommand extends Command {
|
|
|
564
454
|
// options.site as a site name (and not just site id) was introduced for the deploy command, so users could
|
|
565
455
|
// deploy by name along with by id
|
|
566
456
|
let siteData = siteInfo
|
|
567
|
-
if (!siteData.url &&
|
|
568
|
-
siteData = await getSiteByName(api,
|
|
457
|
+
if (!siteData.url && options.site) {
|
|
458
|
+
siteData = await getSiteByName(api, options.site)
|
|
569
459
|
}
|
|
570
460
|
|
|
571
461
|
const globalConfig = await getGlobalConfig()
|
|
572
462
|
|
|
573
|
-
//
|
|
574
|
-
|
|
575
|
-
|
|
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
|
+
|
|
576
468
|
const frameworkIDs = frameworks?.map((framework) => framework.id)
|
|
469
|
+
|
|
577
470
|
if (frameworkIDs?.length !== 0) {
|
|
578
471
|
this.setAnalyticsPayload({ frameworks: frameworkIDs })
|
|
579
472
|
}
|
|
473
|
+
|
|
580
474
|
this.setAnalyticsPayload({
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
buildSystem: this.project.buildSystems.map(({ id }) => id),
|
|
475
|
+
packageManager: project.packageManager?.name,
|
|
476
|
+
buildSystem: project.buildSystems.map(({ id }) => id),
|
|
584
477
|
})
|
|
585
478
|
|
|
586
|
-
// set the project and the netlify api object on the command,
|
|
587
|
-
// to be accessible inside each command.
|
|
588
|
-
actionCommand.project = this.project
|
|
589
|
-
actionCommand.workingDir = this.workingDir
|
|
590
|
-
actionCommand.workspacePackage = this.workspacePackage
|
|
591
479
|
actionCommand.netlify = {
|
|
592
480
|
// api methods
|
|
593
481
|
api,
|
|
@@ -620,36 +508,26 @@ export default class BaseCommand extends Command {
|
|
|
620
508
|
|
|
621
509
|
/**
|
|
622
510
|
* Find and resolve the Netlify configuration
|
|
623
|
-
* @param {
|
|
624
|
-
* @
|
|
625
|
-
* @param {string|null=} config.token
|
|
626
|
-
* @param {*} config.state
|
|
627
|
-
* @param {boolean=} config.offline
|
|
628
|
-
* @param {string=} config.configFilePath An optional path to the netlify configuration file e.g. netlify.toml
|
|
629
|
-
* @param {string=} config.repositoryRoot
|
|
630
|
-
* @param {string=} config.host
|
|
631
|
-
* @param {string=} config.pathPrefix
|
|
632
|
-
* @param {string=} config.scheme
|
|
633
|
-
* @returns {ReturnType<typeof resolveConfig>}
|
|
511
|
+
* @param {*} config
|
|
512
|
+
* @returns {ReturnType<import('@netlify/config/src/main')>}
|
|
634
513
|
*/
|
|
635
514
|
async getConfig(config) {
|
|
636
|
-
|
|
637
|
-
const
|
|
515
|
+
const options = this.opts()
|
|
516
|
+
const { cwd, host, offline = options.offline, pathPrefix, scheme, state, token } = config
|
|
638
517
|
|
|
639
518
|
try {
|
|
640
519
|
return await resolveConfig({
|
|
641
|
-
config: config
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
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,
|
|
648
526
|
mode: 'cli',
|
|
649
|
-
host
|
|
650
|
-
pathPrefix
|
|
651
|
-
scheme
|
|
652
|
-
offline
|
|
527
|
+
host,
|
|
528
|
+
pathPrefix,
|
|
529
|
+
scheme,
|
|
530
|
+
offline,
|
|
653
531
|
siteFeatureFlagPrefix: 'cli',
|
|
654
532
|
})
|
|
655
533
|
} catch (error_) {
|
|
@@ -661,17 +539,17 @@ export default class BaseCommand extends Command {
|
|
|
661
539
|
//
|
|
662
540
|
// @todo Replace this with a mechanism for calling `resolveConfig` with more granularity (i.e. having
|
|
663
541
|
// the option to say that we don't need API data.)
|
|
664
|
-
if (isUserError && !
|
|
665
|
-
if (
|
|
542
|
+
if (isUserError && !offline && token) {
|
|
543
|
+
if (this.opts().debug) {
|
|
666
544
|
error(error_, { exit: false })
|
|
667
545
|
warn('Failed to resolve config, falling back to offline resolution')
|
|
668
546
|
}
|
|
669
|
-
|
|
670
|
-
return this.getConfig({ ...config, offline: true })
|
|
547
|
+
return this.getConfig({ cwd, offline: true, state, token })
|
|
671
548
|
}
|
|
672
549
|
|
|
673
550
|
const message = isUserError ? error_.message : error_.stack
|
|
674
|
-
error(message
|
|
551
|
+
console.error(message)
|
|
552
|
+
exit(1)
|
|
675
553
|
}
|
|
676
554
|
}
|
|
677
555
|
|
|
@@ -680,7 +558,7 @@ export default class BaseCommand extends Command {
|
|
|
680
558
|
* set. The default context is `dev` most of the time, but some commands may
|
|
681
559
|
* wish to override that.
|
|
682
560
|
*
|
|
683
|
-
* @returns {
|
|
561
|
+
* @returns {string}
|
|
684
562
|
*/
|
|
685
563
|
getDefaultContext() {
|
|
686
564
|
if (this.name() === 'serve') {
|
|
@@ -690,17 +568,3 @@ export default class BaseCommand extends Command {
|
|
|
690
568
|
return 'dev'
|
|
691
569
|
}
|
|
692
570
|
}
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* Retrieves the repository root through a git command.
|
|
696
|
-
* Returns undefined if not a git project.
|
|
697
|
-
* @returns {Promise<string|undefined>}
|
|
698
|
-
*/
|
|
699
|
-
async function getRepositoryRoot() {
|
|
700
|
-
try {
|
|
701
|
-
const res = await execa('git', ['rev-parse', '--show-toplevel'], { preferLocal: true })
|
|
702
|
-
return res.stdout
|
|
703
|
-
} catch {
|
|
704
|
-
// noop
|
|
705
|
-
}
|
|
706
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { stat } from 'fs/promises'
|
|
3
3
|
import { basename, resolve } from 'path'
|
|
4
|
-
import { env } from 'process'
|
|
4
|
+
import { cwd, env } from 'process'
|
|
5
5
|
|
|
6
6
|
import { runCoreSteps } from '@netlify/build'
|
|
7
7
|
import { restoreConfig, updateConfig } from '@netlify/config'
|
|
@@ -64,17 +64,16 @@ const triggerDeploy = async ({ api, options, siteData, siteId }) => {
|
|
|
64
64
|
/**
|
|
65
65
|
* g
|
|
66
66
|
* @param {object} config
|
|
67
|
-
* @param {string} config.workingDir The process working directory
|
|
68
67
|
* @param {object} config.config
|
|
69
68
|
* @param {import('commander').OptionValues} config.options
|
|
70
69
|
* @param {object} config.site
|
|
71
70
|
* @param {object} config.siteData
|
|
72
71
|
* @returns {Promise<string>}
|
|
73
72
|
*/
|
|
74
|
-
const getDeployFolder = async ({ config, options, site, siteData
|
|
73
|
+
const getDeployFolder = async ({ config, options, site, siteData }) => {
|
|
75
74
|
let deployFolder
|
|
76
75
|
if (options.dir) {
|
|
77
|
-
deployFolder = resolve(
|
|
76
|
+
deployFolder = resolve(cwd(), options.dir)
|
|
78
77
|
} else if (config?.build?.publish) {
|
|
79
78
|
deployFolder = resolve(site.root, config.build.publish)
|
|
80
79
|
} else if (siteData?.build_settings?.dir) {
|
|
@@ -83,14 +82,14 @@ const getDeployFolder = async ({ config, options, site, siteData, workingDir })
|
|
|
83
82
|
|
|
84
83
|
if (!deployFolder) {
|
|
85
84
|
log('Please provide a publish directory (e.g. "public" or "dist" or "."):')
|
|
86
|
-
log(
|
|
85
|
+
log(cwd())
|
|
87
86
|
const { promptPath } = await inquirer.prompt([
|
|
88
87
|
{
|
|
89
88
|
type: 'input',
|
|
90
89
|
name: 'promptPath',
|
|
91
90
|
message: 'Publish directory',
|
|
92
91
|
default: '.',
|
|
93
|
-
filter: (input) => resolve(
|
|
92
|
+
filter: (input) => resolve(cwd(), input),
|
|
94
93
|
},
|
|
95
94
|
])
|
|
96
95
|
deployFolder = promptPath
|
|
@@ -129,15 +128,14 @@ const validateDeployFolder = async ({ deployFolder }) => {
|
|
|
129
128
|
* @param {import('commander').OptionValues} config.options
|
|
130
129
|
* @param {object} config.site
|
|
131
130
|
* @param {object} config.siteData
|
|
132
|
-
* @param {string} config.workingDir // The process working directory
|
|
133
131
|
* @returns {string}
|
|
134
132
|
*/
|
|
135
|
-
const getFunctionsFolder = ({ config, options, site, siteData
|
|
133
|
+
const getFunctionsFolder = ({ config, options, site, siteData }) => {
|
|
136
134
|
let functionsFolder
|
|
137
135
|
// Support "functions" and "Functions"
|
|
138
136
|
const funcConfig = config.functionsDirectory
|
|
139
137
|
if (options.functions) {
|
|
140
|
-
functionsFolder = resolve(
|
|
138
|
+
functionsFolder = resolve(cwd(), options.functions)
|
|
141
139
|
} else if (funcConfig) {
|
|
142
140
|
functionsFolder = resolve(site.root, funcConfig)
|
|
143
141
|
} else if (siteData?.build_settings?.functions_dir) {
|
|
@@ -180,21 +178,12 @@ const validateFolders = async ({ deployFolder, functionsFolder }) => {
|
|
|
180
178
|
return { deployFolderStat, functionsFolderStat }
|
|
181
179
|
}
|
|
182
180
|
|
|
183
|
-
/**
|
|
184
|
-
* @param {object} config
|
|
185
|
-
* @param {string} config.deployFolder
|
|
186
|
-
* @param {*} config.site
|
|
187
|
-
* @returns
|
|
188
|
-
*/
|
|
189
181
|
const getDeployFilesFilter = ({ deployFolder, site }) => {
|
|
190
182
|
// site.root === deployFolder can happen when users run `netlify deploy --dir .`
|
|
191
183
|
// in that specific case we don't want to publish the repo node_modules
|
|
192
184
|
// when site.root !== deployFolder the behaviour matches our buildbot
|
|
193
185
|
const skipNodeModules = site.root === deployFolder
|
|
194
186
|
|
|
195
|
-
/**
|
|
196
|
-
* @param {string} filename
|
|
197
|
-
*/
|
|
198
187
|
return (filename) => {
|
|
199
188
|
if (filename == null) {
|
|
200
189
|
return false
|
|
@@ -507,7 +496,6 @@ const printResults = ({ deployToProduction, json, results, runBuildCommand }) =>
|
|
|
507
496
|
* @param {import('../base-command.mjs').default} command
|
|
508
497
|
*/
|
|
509
498
|
const deploy = async (options, command) => {
|
|
510
|
-
const { workingDir } = command
|
|
511
499
|
const { api, site, siteInfo } = command.netlify
|
|
512
500
|
const alias = options.alias || options.branch
|
|
513
501
|
|
|
@@ -578,8 +566,8 @@ const deploy = async (options, command) => {
|
|
|
578
566
|
})
|
|
579
567
|
const config = newConfig || command.netlify.config
|
|
580
568
|
|
|
581
|
-
const deployFolder = await getDeployFolder({
|
|
582
|
-
const functionsFolder = getFunctionsFolder({
|
|
569
|
+
const deployFolder = await getDeployFolder({ options, config, site, siteData })
|
|
570
|
+
const functionsFolder = getFunctionsFolder({ options, config, site, siteData })
|
|
583
571
|
const { configPath } = site
|
|
584
572
|
const edgeFunctionsConfig = command.netlify.config.edge_functions
|
|
585
573
|
|
package/src/commands/dev/dev.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import { printBanner } from '../../utils/banner.mjs'
|
|
|
9
9
|
import {
|
|
10
10
|
BANG,
|
|
11
11
|
chalk,
|
|
12
|
+
exit,
|
|
12
13
|
log,
|
|
13
14
|
NETLIFYDEV,
|
|
14
15
|
NETLIFYDEVERR,
|
|
@@ -34,7 +35,7 @@ import { createDevExecCommand } from './dev-exec.mjs'
|
|
|
34
35
|
* @param {object} config
|
|
35
36
|
* @param {*} config.api
|
|
36
37
|
* @param {import('commander').OptionValues} config.options
|
|
37
|
-
* @param {
|
|
38
|
+
* @param {*} config.settings
|
|
38
39
|
* @param {*} config.site
|
|
39
40
|
* @param {*} config.state
|
|
40
41
|
* @returns
|
|
@@ -67,9 +68,6 @@ const handleLiveTunnel = async ({ api, options, settings, site, state }) => {
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
/**
|
|
71
|
-
* @param {string} args
|
|
72
|
-
*/
|
|
73
71
|
const validateShortFlagArgs = (args) => {
|
|
74
72
|
if (args.startsWith('=')) {
|
|
75
73
|
throw new Error(
|
|
@@ -96,10 +94,9 @@ const dev = async (options, command) => {
|
|
|
96
94
|
const { api, cachedConfig, config, repositoryRoot, site, siteInfo, state } = command.netlify
|
|
97
95
|
config.dev = { ...config.dev }
|
|
98
96
|
config.build = { ...config.build }
|
|
99
|
-
/** @type {import('./types
|
|
97
|
+
/** @type {import('./types').DevConfig} */
|
|
100
98
|
const devConfig = {
|
|
101
99
|
framework: '#auto',
|
|
102
|
-
autoLaunch: Boolean(options.open),
|
|
103
100
|
...(config.functionsDirectory && { functions: config.functionsDirectory }),
|
|
104
101
|
...(config.build.publish && { publish: config.build.publish }),
|
|
105
102
|
...config.dev,
|
|
@@ -127,17 +124,20 @@ const dev = async (options, command) => {
|
|
|
127
124
|
siteInfo,
|
|
128
125
|
})
|
|
129
126
|
|
|
130
|
-
/** @type {import('../../utils/types
|
|
131
|
-
let settings
|
|
127
|
+
/** @type {Partial<import('../../utils/types').ServerSettings>} */
|
|
128
|
+
let settings = {}
|
|
132
129
|
try {
|
|
133
|
-
settings = await detectServerSettings(devConfig, options,
|
|
130
|
+
settings = await detectServerSettings(devConfig, options, site.root, {
|
|
131
|
+
site: {
|
|
132
|
+
id: site.id,
|
|
133
|
+
url: siteUrl,
|
|
134
|
+
},
|
|
135
|
+
})
|
|
134
136
|
|
|
135
137
|
cachedConfig.config = getConfigWithPlugins(cachedConfig.config, settings)
|
|
136
138
|
} catch (error_) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
process.exit(1)
|
|
139
|
+
log(NETLIFYDEVERR, error_.message)
|
|
140
|
+
exit(1)
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
command.setAnalyticsPayload({ live: options.live })
|
|
@@ -154,7 +154,6 @@ const dev = async (options, command) => {
|
|
|
154
154
|
cachedConfig,
|
|
155
155
|
options,
|
|
156
156
|
settings,
|
|
157
|
-
projectDir: command.workingDir,
|
|
158
157
|
site,
|
|
159
158
|
env: {
|
|
160
159
|
URL: url,
|
|
@@ -189,11 +188,8 @@ const dev = async (options, command) => {
|
|
|
189
188
|
|
|
190
189
|
// TODO: We should consolidate this with the existing config watcher.
|
|
191
190
|
const getUpdatedConfig = async () => {
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
offline: true,
|
|
195
|
-
state,
|
|
196
|
-
})
|
|
191
|
+
const cwd = options.cwd || process.cwd()
|
|
192
|
+
const { config: newConfig } = await command.getConfig({ cwd, offline: true, state })
|
|
197
193
|
const normalizedNewConfig = normalizeConfig(newConfig)
|
|
198
194
|
|
|
199
195
|
return normalizedNewConfig
|
|
@@ -206,7 +202,6 @@ const dev = async (options, command) => {
|
|
|
206
202
|
config,
|
|
207
203
|
configPath: configPathOverride,
|
|
208
204
|
debug: options.debug,
|
|
209
|
-
projectDir: command.workingDir,
|
|
210
205
|
env,
|
|
211
206
|
getUpdatedConfig,
|
|
212
207
|
inspectSettings,
|
|
@@ -253,7 +248,6 @@ export const createDevCommand = (program) => {
|
|
|
253
248
|
.argParser((value) => Number.parseInt(value))
|
|
254
249
|
.hideHelp(true),
|
|
255
250
|
)
|
|
256
|
-
.addOption(new Option('--no-open', 'disables the automatic opening of a browser window'))
|
|
257
251
|
.option('--target-port <port>', 'port of target app server', (value) => Number.parseInt(value))
|
|
258
252
|
.option('--framework <name>', 'framework to use. Defaults to #auto which automatically detects a framework')
|
|
259
253
|
.option('-d ,--dir <path>', 'dir with static files')
|
|
@@ -12,6 +12,7 @@ import copyTemplateDirOriginal from 'copy-template-dir'
|
|
|
12
12
|
import { findUp } from 'find-up'
|
|
13
13
|
import fuzzy from 'fuzzy'
|
|
14
14
|
import inquirer from 'inquirer'
|
|
15
|
+
import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt'
|
|
15
16
|
import fetch from 'node-fetch'
|
|
16
17
|
import ora from 'ora'
|
|
17
18
|
|
|
@@ -171,6 +172,8 @@ const pickTemplate = async function ({ language: languageFromFlag }, funcType) {
|
|
|
171
172
|
language = languageFromPrompt
|
|
172
173
|
}
|
|
173
174
|
|
|
175
|
+
inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt)
|
|
176
|
+
|
|
174
177
|
let templatesForLanguage
|
|
175
178
|
|
|
176
179
|
try {
|