netlify-cli 15.9.0 → 15.9.1-rc.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 +749 -147
- package/package.json +6 -7
- package/scripts/postinstall.mjs +8 -8
- package/src/commands/base-command.mjs +195 -59
- package/src/commands/deploy/deploy.mjs +21 -9
- package/src/commands/dev/dev.mjs +21 -15
- package/src/commands/functions/functions-build.mjs +2 -2
- package/src/commands/functions/functions-create.mjs +0 -3
- package/src/commands/functions/functions-invoke.mjs +8 -5
- package/src/commands/init/init.mjs +1 -1
- package/src/commands/link/link.mjs +5 -5
- package/src/commands/main.mjs +1 -1
- package/src/commands/serve/serve.mjs +11 -5
- package/src/commands/sites/sites-create-template.mjs +1 -1
- package/src/commands/sites/sites-create.mjs +1 -1
- package/src/lib/completion/generate-autocompletion.mjs +4 -4
- package/src/lib/edge-functions/bootstrap.mjs +1 -1
- package/src/lib/edge-functions/internal.mjs +5 -3
- package/src/lib/edge-functions/proxy.mjs +30 -5
- package/src/lib/functions/registry.mjs +1 -3
- package/src/lib/functions/runtimes/js/builders/zisi.mjs +3 -8
- package/src/lib/functions/server.mjs +6 -6
- package/src/lib/spinner.mjs +1 -1
- package/src/recipes/vscode/index.mjs +1 -1
- package/src/utils/build-info.mjs +19 -0
- package/src/utils/command-helpers.mjs +16 -7
- package/src/utils/deploy/hash-fns.mjs +1 -2
- package/src/utils/detect-server-settings.mjs +148 -200
- package/src/utils/execa.mjs +4 -2
- package/src/utils/framework-server.mjs +2 -2
- package/src/utils/functions/functions.mjs +7 -0
- package/src/utils/functions/get-functions.mjs +2 -2
- package/src/utils/get-repo-data.mjs +5 -6
- package/src/utils/init/config-github.mjs +2 -2
- package/src/utils/init/config-manual.mjs +24 -7
- package/src/utils/init/utils.mjs +62 -63
- package/src/utils/proxy-server.mjs +7 -4
- package/src/utils/proxy.mjs +4 -0
- package/src/utils/run-build.mjs +58 -7
- package/src/utils/shell.mjs +14 -3
- package/src/utils/state-config.mjs +5 -1
- package/src/utils/static-server.mjs +4 -0
- package/src/utils/telemetry/report-error.mjs +8 -4
- package/src/utils/init/frameworks.mjs +0 -23
|
@@ -5,7 +5,12 @@ import { exit, log } from '../command-helpers.mjs'
|
|
|
5
5
|
|
|
6
6
|
import { createDeployKey, getBuildSettings, saveNetlifyToml, setupSite } from './utils.mjs'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Prompts for granting the netlify ssh public key access to your repo
|
|
10
|
+
* @param {object} deployKey
|
|
11
|
+
* @param {string} deployKey.public_key
|
|
12
|
+
*/
|
|
13
|
+
const addDeployKey = async (deployKey) => {
|
|
9
14
|
log('\nGive this Netlify SSH public key access to your repository:\n')
|
|
10
15
|
log(`\n${deployKey.public_key}\n\n`)
|
|
11
16
|
|
|
@@ -23,6 +28,11 @@ const addDeployKey = async ({ deployKey }) => {
|
|
|
23
28
|
}
|
|
24
29
|
}
|
|
25
30
|
|
|
31
|
+
/**
|
|
32
|
+
* @param {object} config
|
|
33
|
+
* @param {Awaited<ReturnType<import('../../utils/get-repo-data.mjs').default>>} config.repoData
|
|
34
|
+
* @returns {Promise<string>}
|
|
35
|
+
*/
|
|
26
36
|
const getRepoPath = async ({ repoData }) => {
|
|
27
37
|
const { repoPath } = await inquirer.prompt([
|
|
28
38
|
{
|
|
@@ -30,6 +40,9 @@ const getRepoPath = async ({ repoData }) => {
|
|
|
30
40
|
name: 'repoPath',
|
|
31
41
|
message: 'The SSH URL of the remote git repo:',
|
|
32
42
|
default: repoData.url,
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} url
|
|
45
|
+
*/
|
|
33
46
|
validate: (url) => SSH_URL_REGEXP.test(url) || 'The URL provided does not use the SSH protocol',
|
|
34
47
|
},
|
|
35
48
|
])
|
|
@@ -37,7 +50,11 @@ const getRepoPath = async ({ repoData }) => {
|
|
|
37
50
|
return repoPath
|
|
38
51
|
}
|
|
39
52
|
|
|
40
|
-
|
|
53
|
+
/**
|
|
54
|
+
* @param {string} deployHook
|
|
55
|
+
* @returns
|
|
56
|
+
*/
|
|
57
|
+
const addDeployHook = async (deployHook) => {
|
|
41
58
|
log('\nConfigure the following webhook for your repository:\n')
|
|
42
59
|
log(`\n${deployHook}\n\n`)
|
|
43
60
|
const { deployHookAdded } = await inquirer.prompt([
|
|
@@ -55,14 +72,14 @@ const addDeployHook = async ({ deployHook }) => {
|
|
|
55
72
|
/**
|
|
56
73
|
* @param {object} config
|
|
57
74
|
* @param {import('../../commands/base-command.mjs').default} config.command
|
|
58
|
-
* @param {
|
|
75
|
+
* @param {Awaited<ReturnType<import('../../utils/get-repo-data.mjs').default>>} config.repoData
|
|
59
76
|
* @param {string} config.siteId
|
|
60
77
|
*/
|
|
61
78
|
export default async function configManual({ command, repoData, siteId }) {
|
|
62
79
|
const { netlify } = command
|
|
63
80
|
const {
|
|
64
81
|
api,
|
|
65
|
-
cachedConfig: { configPath
|
|
82
|
+
cachedConfig: { configPath },
|
|
66
83
|
config,
|
|
67
84
|
repositoryRoot,
|
|
68
85
|
site: { root: siteRoot },
|
|
@@ -72,12 +89,12 @@ export default async function configManual({ command, repoData, siteId }) {
|
|
|
72
89
|
repositoryRoot,
|
|
73
90
|
siteRoot,
|
|
74
91
|
config,
|
|
75
|
-
|
|
92
|
+
command,
|
|
76
93
|
})
|
|
77
94
|
await saveNetlifyToml({ repositoryRoot, config, configPath, baseDir, buildCmd, buildDir, functionsDir })
|
|
78
95
|
|
|
79
96
|
const deployKey = await createDeployKey({ api })
|
|
80
|
-
await addDeployKey(
|
|
97
|
+
await addDeployKey(deployKey)
|
|
81
98
|
|
|
82
99
|
const repoPath = await getRepoPath({ repoData })
|
|
83
100
|
const repo = {
|
|
@@ -99,7 +116,7 @@ export default async function configManual({ command, repoData, siteId }) {
|
|
|
99
116
|
configPlugins: config.plugins,
|
|
100
117
|
pluginsToInstall,
|
|
101
118
|
})
|
|
102
|
-
const deployHookAdded = await addDeployHook(
|
|
119
|
+
const deployHookAdded = await addDeployHook(updatedSite.deploy_hook)
|
|
103
120
|
if (!deployHookAdded) {
|
|
104
121
|
exit()
|
|
105
122
|
}
|
package/src/utils/init/utils.mjs
CHANGED
|
@@ -1,64 +1,72 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { writeFile } from 'fs/promises'
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import process from 'process'
|
|
5
4
|
|
|
6
5
|
import cleanDeep from 'clean-deep'
|
|
7
6
|
import inquirer from 'inquirer'
|
|
8
7
|
|
|
9
8
|
import { fileExistsAsync } from '../../lib/fs.mjs'
|
|
10
9
|
import { normalizeBackslash } from '../../lib/path.mjs'
|
|
10
|
+
import { detectBuildSettings } from '../build-info.mjs'
|
|
11
11
|
import { chalk, error as failAndExit, log, warn } from '../command-helpers.mjs'
|
|
12
12
|
|
|
13
|
-
import { getFrameworkInfo } from './frameworks.mjs'
|
|
14
|
-
import { detectNodeVersion } from './node-version.mjs'
|
|
15
13
|
import { getRecommendPlugins, getUIPlugins } from './plugins.mjs'
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
15
|
+
// these plugins represent runtimes that are
|
|
16
|
+
// expected to be "automatically" installed. Even though
|
|
17
|
+
// they can be installed on package/toml, we always
|
|
18
|
+
// want them installed in the site settings. When installed
|
|
19
|
+
// there our build will automatically install the latest without
|
|
20
|
+
// user management of the versioning.
|
|
21
|
+
const pluginsToAlwaysInstall = new Set(['@netlify/plugin-nextjs'])
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Retrieve a list of plugins to auto install
|
|
25
|
+
* @param {string[]=} pluginsInstalled
|
|
26
|
+
* @param {string[]=} pluginsRecommended
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
29
|
+
export const getPluginsToAutoInstall = (pluginsInstalled = [], pluginsRecommended = []) =>
|
|
30
|
+
pluginsRecommended.reduce(
|
|
31
|
+
(acc, plugin) =>
|
|
32
|
+
pluginsInstalled.includes(plugin) && !pluginsToAlwaysInstall.has(plugin) ? acc : [...acc, plugin],
|
|
33
|
+
|
|
34
|
+
/** @type {string[]} */ ([]),
|
|
35
|
+
)
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const recommendedPlugins = getRecommendPlugins(
|
|
41
|
-
const {
|
|
42
|
-
command: defaultBuildCmd = frameworkBuildCommand,
|
|
43
|
-
functions: defaultFunctionsDir,
|
|
44
|
-
publish: defaultBuildDir = frameworkBuildDir,
|
|
45
|
-
} = config.build
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param {Partial<import('@netlify/build-info').Settings>} settings
|
|
40
|
+
* @param {*} config
|
|
41
|
+
* @param {import('../../commands/base-command.mjs').default} command
|
|
42
|
+
*/
|
|
43
|
+
const normalizeSettings = (settings, config, command) => {
|
|
44
|
+
const plugins = getPluginsToAutoInstall(settings.plugins_from_config_file, settings.plugins_recommended)
|
|
45
|
+
const recommendedPlugins = getRecommendPlugins(plugins, config)
|
|
46
46
|
|
|
47
47
|
return {
|
|
48
|
-
defaultBaseDir:
|
|
49
|
-
defaultBuildCmd,
|
|
50
|
-
defaultBuildDir:
|
|
51
|
-
defaultFunctionsDir:
|
|
48
|
+
defaultBaseDir: settings.baseDirectory ?? command.project.relativeBaseDirectory ?? '',
|
|
49
|
+
defaultBuildCmd: config.build.command || settings.buildCommand,
|
|
50
|
+
defaultBuildDir: settings.dist,
|
|
51
|
+
defaultFunctionsDir: config.build.functions || 'netlify/functions',
|
|
52
52
|
recommendedPlugins,
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @param {object} param0
|
|
59
|
+
* @param {string} param0.defaultBaseDir
|
|
60
|
+
* @param {string} param0.defaultBuildCmd
|
|
61
|
+
* @param {string=} param0.defaultBuildDir
|
|
62
|
+
* @returns
|
|
63
|
+
*/
|
|
56
64
|
const getPromptInputs = ({ defaultBaseDir, defaultBuildCmd, defaultBuildDir }) => {
|
|
57
65
|
const inputs = [
|
|
58
66
|
defaultBaseDir !== undefined && {
|
|
59
67
|
type: 'input',
|
|
60
68
|
name: 'baseDir',
|
|
61
|
-
message: 'Base directory (
|
|
69
|
+
message: 'Base directory `(blank for current dir):',
|
|
62
70
|
default: defaultBaseDir,
|
|
63
71
|
},
|
|
64
72
|
{
|
|
@@ -79,34 +87,22 @@ const getPromptInputs = ({ defaultBaseDir, defaultBuildCmd, defaultBuildDir }) =
|
|
|
79
87
|
return inputs.filter(Boolean)
|
|
80
88
|
}
|
|
81
89
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
frameworkPlugins = [],
|
|
94
|
-
} = await getFrameworkInfo({
|
|
95
|
-
baseDirectory,
|
|
96
|
-
nodeVersion,
|
|
97
|
-
})
|
|
90
|
+
/**
|
|
91
|
+
* @param {object} param0
|
|
92
|
+
* @param {*} param0.config
|
|
93
|
+
* @param {import('../../commands/base-command.mjs').default} param0.command
|
|
94
|
+
*/
|
|
95
|
+
export const getBuildSettings = async ({ command, config }) => {
|
|
96
|
+
const settings = await detectBuildSettings(command)
|
|
97
|
+
// TODO: add prompt for asking to choose the build command
|
|
98
|
+
/** @type {Partial<import('@netlify/build-info').Settings>} */
|
|
99
|
+
// eslint-disable-next-line unicorn/explicit-length-check
|
|
100
|
+
const setting = settings.length > 0 ? settings[0] : {}
|
|
98
101
|
const { defaultBaseDir, defaultBuildCmd, defaultBuildDir, defaultFunctionsDir, recommendedPlugins } =
|
|
99
|
-
await
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
frameworkBuildCommand,
|
|
104
|
-
frameworkBuildDir,
|
|
105
|
-
frameworkPlugins,
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
if (recommendedPlugins.length !== 0) {
|
|
109
|
-
log(`Configuring ${formatTitle(frameworkName)} runtime...`)
|
|
102
|
+
await normalizeSettings(setting, config, command)
|
|
103
|
+
|
|
104
|
+
if (recommendedPlugins.length !== 0 && setting.framework?.name) {
|
|
105
|
+
log(`Configuring ${formatTitle(setting.framework?.name)} runtime...`)
|
|
110
106
|
log()
|
|
111
107
|
}
|
|
112
108
|
|
|
@@ -199,6 +195,9 @@ export const formatErrorMessage = ({ error, message }) => {
|
|
|
199
195
|
return `${message} with error: ${chalk.red(errorMessage)}`
|
|
200
196
|
}
|
|
201
197
|
|
|
198
|
+
/**
|
|
199
|
+
* @param {string} title
|
|
200
|
+
*/
|
|
202
201
|
const formatTitle = (title) => chalk.cyan(title)
|
|
203
202
|
|
|
204
203
|
export const createDeployKey = async ({ api }) => {
|
|
@@ -36,19 +36,21 @@ export const generateInspectSettings = (edgeInspect, edgeInspectBrk) => {
|
|
|
36
36
|
/**
|
|
37
37
|
*
|
|
38
38
|
* @param {object} params
|
|
39
|
+
* @param {string=} params.accountId
|
|
39
40
|
* @param {*} params.addonsUrls
|
|
40
|
-
* @param {import('../commands/
|
|
41
|
+
* @param {import('../commands/types.js').NetlifyOptions["config"]} params.config
|
|
41
42
|
* @param {string} [params.configPath] An override for the Netlify config path
|
|
42
43
|
* @param {boolean} params.debug
|
|
43
|
-
* @param {import('../commands/
|
|
44
|
+
* @param {import('../commands/types.js').NetlifyOptions["cachedConfig"]['env']} params.env
|
|
44
45
|
* @param {InspectSettings} params.inspectSettings
|
|
45
46
|
* @param {() => Promise<object>} params.getUpdatedConfig
|
|
46
47
|
* @param {string} params.geolocationMode
|
|
47
48
|
* @param {string} params.geoCountry
|
|
48
49
|
* @param {*} params.settings
|
|
49
50
|
* @param {boolean} params.offline
|
|
50
|
-
* @param {
|
|
51
|
+
* @param {object} params.site
|
|
51
52
|
* @param {*} params.siteInfo
|
|
53
|
+
* @param {string} params.projectDir
|
|
52
54
|
* @param {import('./state-config.mjs').default} params.state
|
|
53
55
|
* @returns
|
|
54
56
|
*/
|
|
@@ -64,6 +66,7 @@ export const startProxyServer = async ({
|
|
|
64
66
|
getUpdatedConfig,
|
|
65
67
|
inspectSettings,
|
|
66
68
|
offline,
|
|
69
|
+
projectDir,
|
|
67
70
|
settings,
|
|
68
71
|
site,
|
|
69
72
|
siteInfo,
|
|
@@ -80,7 +83,7 @@ export const startProxyServer = async ({
|
|
|
80
83
|
getUpdatedConfig,
|
|
81
84
|
inspectSettings,
|
|
82
85
|
offline,
|
|
83
|
-
projectDir
|
|
86
|
+
projectDir,
|
|
84
87
|
settings,
|
|
85
88
|
state,
|
|
86
89
|
siteInfo,
|
package/src/utils/proxy.mjs
CHANGED
|
@@ -599,6 +599,10 @@ const onRequest = async (
|
|
|
599
599
|
proxy.web(req, res, options)
|
|
600
600
|
}
|
|
601
601
|
|
|
602
|
+
/**
|
|
603
|
+
* @param {import('./types.js').ServerSettings} settings
|
|
604
|
+
* @returns
|
|
605
|
+
*/
|
|
602
606
|
export const getProxyUrl = function (settings) {
|
|
603
607
|
const scheme = settings.https ? 'https' : 'http'
|
|
604
608
|
return `${scheme}://localhost:${settings.port}`
|
package/src/utils/run-build.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { promises as fs } from 'fs'
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import process from 'process'
|
|
5
4
|
|
|
6
5
|
import { INTERNAL_EDGE_FUNCTIONS_FOLDER } from '../lib/edge-functions/consts.mjs'
|
|
7
6
|
import { getPathInProject } from '../lib/settings.mjs'
|
|
@@ -12,8 +11,13 @@ import { INTERNAL_FUNCTIONS_FOLDER } from './functions/index.mjs'
|
|
|
12
11
|
|
|
13
12
|
const netlifyBuildPromise = import('@netlify/build')
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Copies `netlify.toml`, if one is defined, into the `.netlify` internal
|
|
16
|
+
* directory and returns the path to its new location.
|
|
17
|
+
* @param {object} config
|
|
18
|
+
* @param {string} config.configPath
|
|
19
|
+
* @param {string} config.siteRoot
|
|
20
|
+
*/
|
|
17
21
|
const copyConfig = async ({ configPath, siteRoot }) => {
|
|
18
22
|
const newConfigPath = path.resolve(siteRoot, getPathInProject(['netlify.toml']))
|
|
19
23
|
|
|
@@ -26,6 +30,9 @@ const copyConfig = async ({ configPath, siteRoot }) => {
|
|
|
26
30
|
return newConfigPath
|
|
27
31
|
}
|
|
28
32
|
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} basePath
|
|
35
|
+
*/
|
|
29
36
|
const cleanInternalDirectory = async (basePath) => {
|
|
30
37
|
const ops = [INTERNAL_FUNCTIONS_FOLDER, INTERNAL_EDGE_FUNCTIONS_FOLDER, 'netlify.toml'].map((name) => {
|
|
31
38
|
const fullPath = path.resolve(basePath, getPathInProject([name]))
|
|
@@ -36,9 +43,26 @@ const cleanInternalDirectory = async (basePath) => {
|
|
|
36
43
|
await Promise.all(ops)
|
|
37
44
|
}
|
|
38
45
|
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @param {object} config
|
|
49
|
+
* @param {string} config.projectDir
|
|
50
|
+
* @param {*} config.cachedConfig
|
|
51
|
+
* @param {object} config.options
|
|
52
|
+
* @param {string} config.options.configPath
|
|
53
|
+
* @param {*} config.options.context
|
|
54
|
+
* @param {string=} config.options.cwd
|
|
55
|
+
* @param {boolean} config.options.debug
|
|
56
|
+
* @param {boolean} config.options.dry
|
|
57
|
+
* @param {boolean} config.options.offline
|
|
58
|
+
* @param {boolean} config.options.quiet
|
|
59
|
+
* @param {boolean} config.options.saveConfig
|
|
60
|
+
* @returns
|
|
61
|
+
*/
|
|
39
62
|
const getBuildOptions = ({
|
|
40
63
|
cachedConfig,
|
|
41
|
-
options: { configPath, context,
|
|
64
|
+
options: { configPath, context, debug, dry, offline, quiet, saveConfig },
|
|
65
|
+
projectDir,
|
|
42
66
|
}) => ({
|
|
43
67
|
cachedConfig,
|
|
44
68
|
configPath,
|
|
@@ -51,14 +75,35 @@ const getBuildOptions = ({
|
|
|
51
75
|
telemetry: false,
|
|
52
76
|
buffer: false,
|
|
53
77
|
offline,
|
|
54
|
-
cwd,
|
|
78
|
+
cwd: projectDir,
|
|
55
79
|
quiet,
|
|
56
80
|
saveConfig,
|
|
57
81
|
})
|
|
58
82
|
|
|
59
|
-
|
|
83
|
+
/**
|
|
84
|
+
*
|
|
85
|
+
* @param {object} config
|
|
86
|
+
* @param {*} config.cachedConfig
|
|
87
|
+
* @param {NodeJS.ProcessEnv} config.env
|
|
88
|
+
* @param {*} config.options The flags of the command
|
|
89
|
+
* @param {string} config.projectDir
|
|
90
|
+
* @param {import('./types.js').ServerSettings} config.settings
|
|
91
|
+
* @param {*} config.site
|
|
92
|
+
* @param {'build' | 'dev'} config.timeline
|
|
93
|
+
* @returns
|
|
94
|
+
*/
|
|
95
|
+
export const runNetlifyBuild = async ({
|
|
96
|
+
cachedConfig,
|
|
97
|
+
env,
|
|
98
|
+
options,
|
|
99
|
+
projectDir,
|
|
100
|
+
settings,
|
|
101
|
+
site,
|
|
102
|
+
timeline = 'build',
|
|
103
|
+
}) => {
|
|
60
104
|
const { default: buildSite, startDev } = await netlifyBuildPromise
|
|
61
105
|
const sharedOptions = getBuildOptions({
|
|
106
|
+
projectDir,
|
|
62
107
|
cachedConfig,
|
|
63
108
|
options,
|
|
64
109
|
})
|
|
@@ -118,13 +163,19 @@ const runNetlifyBuild = async ({ cachedConfig, env, options, settings, site, tim
|
|
|
118
163
|
// Run Netlify Build using the `startDev` entry point.
|
|
119
164
|
const { error: startDevError, success } = await startDev(devCommand, startDevOptions)
|
|
120
165
|
|
|
121
|
-
if (!success) {
|
|
166
|
+
if (!success && startDevError) {
|
|
122
167
|
error(`Could not start local development server\n\n${startDevError.message}\n\n${startDevError.stack}`)
|
|
123
168
|
}
|
|
124
169
|
|
|
125
170
|
return {}
|
|
126
171
|
}
|
|
127
172
|
|
|
173
|
+
/**
|
|
174
|
+
* @param {Omit<Parameters<typeof runNetlifyBuild>[0], 'timeline'>} options
|
|
175
|
+
*/
|
|
128
176
|
export const runDevTimeline = (options) => runNetlifyBuild({ ...options, timeline: 'dev' })
|
|
129
177
|
|
|
178
|
+
/**
|
|
179
|
+
* @param {Omit<Parameters<typeof runNetlifyBuild>[0], 'timeline'>} options
|
|
180
|
+
*/
|
|
130
181
|
export const runBuildTimeline = (options) => runNetlifyBuild({ ...options, timeline: 'build' })
|
package/src/utils/shell.mjs
CHANGED
|
@@ -48,7 +48,11 @@ export const runCommand = (command, env = {}, spinner = null) => {
|
|
|
48
48
|
preferLocal: true,
|
|
49
49
|
// we use reject=false to avoid rejecting synchronously when the command doesn't exist
|
|
50
50
|
reject: false,
|
|
51
|
-
env
|
|
51
|
+
env: {
|
|
52
|
+
// we want always colorful terminal outputs
|
|
53
|
+
FORCE_COLOR: 'true',
|
|
54
|
+
...env,
|
|
55
|
+
},
|
|
52
56
|
// windowsHide needs to be false for child process to terminate properly on Windows
|
|
53
57
|
windowsHide: false,
|
|
54
58
|
})
|
|
@@ -90,7 +94,7 @@ export const runCommand = (command, env = {}, spinner = null) => {
|
|
|
90
94
|
? `${NETLIFYDEVERR} ${result.shortMessage}`
|
|
91
95
|
: `${NETLIFYDEVWARN} "${command}" exited with code ${result.exitCode}`
|
|
92
96
|
|
|
93
|
-
log(
|
|
97
|
+
log(`\n\n${errorMessage}. Shutting down Netlify Dev server`)
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
return await cleanupBeforeExit({ exitCode: 1 })
|
|
@@ -100,6 +104,13 @@ export const runCommand = (command, env = {}, spinner = null) => {
|
|
|
100
104
|
return commandProcess
|
|
101
105
|
}
|
|
102
106
|
|
|
107
|
+
/**
|
|
108
|
+
*
|
|
109
|
+
* @param {object} config
|
|
110
|
+
* @param {string} config.command
|
|
111
|
+
* @param {*} config.error
|
|
112
|
+
* @returns
|
|
113
|
+
*/
|
|
103
114
|
const isNonExistingCommandError = ({ command, error: commandError }) => {
|
|
104
115
|
// `ENOENT` is only returned for non Windows systems
|
|
105
116
|
// See https://github.com/sindresorhus/execa/pull/447
|
|
@@ -108,7 +119,7 @@ const isNonExistingCommandError = ({ command, error: commandError }) => {
|
|
|
108
119
|
}
|
|
109
120
|
|
|
110
121
|
// if the command is a package manager we let it report the error
|
|
111
|
-
if (['yarn', 'npm'].includes(command)) {
|
|
122
|
+
if (['yarn', 'npm', 'pnpm'].includes(command)) {
|
|
112
123
|
return false
|
|
113
124
|
}
|
|
114
125
|
|
|
@@ -11,7 +11,11 @@ import { getPathInProject } from '../lib/settings.mjs'
|
|
|
11
11
|
const STATE_PATH = getPathInProject(['state.json'])
|
|
12
12
|
const permissionError = "You don't have access to this file."
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Finds location of `.netlify/state.json`
|
|
16
|
+
* @param {string} cwd
|
|
17
|
+
* @returns {string}
|
|
18
|
+
*/
|
|
15
19
|
const findStatePath = (cwd) => {
|
|
16
20
|
const statePath = findUpSync([STATE_PATH], { cwd })
|
|
17
21
|
|
|
@@ -6,6 +6,10 @@ import Fastify from 'fastify'
|
|
|
6
6
|
|
|
7
7
|
import { log, NETLIFYDEVLOG } from './command-helpers.mjs'
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @param {object} config
|
|
11
|
+
* @param {import('./types.js').ServerSettings} config.settings
|
|
12
|
+
*/
|
|
9
13
|
export const startStaticServer = async ({ settings }) => {
|
|
10
14
|
const server = Fastify()
|
|
11
15
|
const rootPath = path.resolve(settings.dist)
|
|
@@ -25,15 +25,19 @@ export const reportError = async function (error, config = {}) {
|
|
|
25
25
|
return
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// convert a NotifiableError to an error class
|
|
29
|
+
// eslint-disable-next-line unicorn/no-nested-ternary
|
|
30
|
+
const err = error instanceof Error ? error : typeof error === 'string' ? new Error(error) : error
|
|
31
|
+
|
|
28
32
|
const globalConfig = await getGlobalConfig()
|
|
29
33
|
|
|
30
34
|
const options = JSON.stringify({
|
|
31
35
|
type: 'error',
|
|
32
36
|
data: {
|
|
33
|
-
message:
|
|
34
|
-
name:
|
|
35
|
-
stack:
|
|
36
|
-
cause:
|
|
37
|
+
message: err.message,
|
|
38
|
+
name: err.name,
|
|
39
|
+
stack: err.stack,
|
|
40
|
+
cause: err.cause,
|
|
37
41
|
severity: config.severity,
|
|
38
42
|
user: {
|
|
39
43
|
id: globalConfig.get('userId'),
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
import { listFrameworks } from '@netlify/framework-info'
|
|
3
|
-
|
|
4
|
-
export const getFrameworkInfo = async ({ baseDirectory, nodeVersion }) => {
|
|
5
|
-
const frameworks = await listFrameworks({ projectDir: baseDirectory, nodeVersion })
|
|
6
|
-
// several frameworks can be detected - first one has highest priority
|
|
7
|
-
if (frameworks.length !== 0) {
|
|
8
|
-
const [
|
|
9
|
-
{
|
|
10
|
-
build: { commands, directory },
|
|
11
|
-
name,
|
|
12
|
-
plugins,
|
|
13
|
-
},
|
|
14
|
-
] = frameworks
|
|
15
|
-
return {
|
|
16
|
-
frameworkName: name,
|
|
17
|
-
frameworkBuildCommand: commands[0],
|
|
18
|
-
frameworkBuildDir: directory,
|
|
19
|
-
frameworkPlugins: plugins,
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return {}
|
|
23
|
-
}
|