netlify-cli 15.11.0 → 16.0.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 +6 -5
- package/npm-shrinkwrap.json +795 -118
- package/package.json +4 -5
- package/src/commands/base-command.mjs +295 -118
- package/src/commands/build/build.mjs +9 -1
- package/src/commands/deploy/deploy.mjs +47 -20
- package/src/commands/dev/dev.mjs +22 -17
- package/src/commands/functions/functions-create.mjs +118 -89
- package/src/commands/functions/functions-invoke.mjs +10 -7
- package/src/commands/functions/functions-list.mjs +3 -3
- package/src/commands/functions/functions-serve.mjs +1 -0
- package/src/commands/init/init.mjs +1 -1
- package/src/commands/link/link.mjs +5 -5
- package/src/commands/serve/serve.mjs +10 -6
- package/src/commands/sites/sites-create-template.mjs +1 -1
- package/src/commands/sites/sites-create.mjs +1 -1
- package/src/functions-templates/javascript/google-analytics/package.json +1 -1
- package/src/functions-templates/typescript/scheduled-function/package.json +1 -1
- package/src/lib/edge-functions/deploy.mjs +11 -4
- package/src/lib/edge-functions/internal.mjs +5 -3
- package/src/lib/edge-functions/proxy.mjs +29 -5
- package/src/lib/functions/runtimes/js/builders/zisi.mjs +20 -3
- package/src/lib/functions/server.mjs +3 -2
- package/src/lib/spinner.mjs +1 -1
- package/src/recipes/vscode/index.mjs +24 -6
- package/src/utils/build-info.mjs +100 -0
- package/src/utils/command-helpers.mjs +16 -7
- package/src/utils/deploy/deploy-site.mjs +4 -4
- package/src/utils/deploy/hash-fns.mjs +2 -2
- package/src/utils/detect-server-settings.mjs +133 -245
- package/src/utils/framework-server.mjs +6 -5
- package/src/utils/functions/functions.mjs +8 -5
- 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 +68 -68
- package/src/utils/proxy-server.mjs +7 -4
- package/src/utils/proxy.mjs +4 -3
- package/src/utils/read-repo-url.mjs +4 -0
- package/src/utils/run-build.mjs +58 -32
- package/src/utils/shell.mjs +23 -6
- package/src/utils/state-config.mjs +5 -1
- package/src/utils/static-server.mjs +4 -0
- 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,66 +1,75 @@
|
|
|
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
|
-
defaultBaseDir !== undefined &&
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
defaultBaseDir !== undefined &&
|
|
67
|
+
defaultBaseDir !== '' && {
|
|
68
|
+
type: 'input',
|
|
69
|
+
name: 'baseDir',
|
|
70
|
+
message: 'Base directory `(blank for current dir):',
|
|
71
|
+
default: defaultBaseDir,
|
|
72
|
+
},
|
|
64
73
|
{
|
|
65
74
|
type: 'input',
|
|
66
75
|
name: 'buildCmd',
|
|
@@ -79,34 +88,22 @@ const getPromptInputs = ({ defaultBaseDir, defaultBuildCmd, defaultBuildDir }) =
|
|
|
79
88
|
return inputs.filter(Boolean)
|
|
80
89
|
}
|
|
81
90
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
frameworkPlugins = [],
|
|
94
|
-
} = await getFrameworkInfo({
|
|
95
|
-
baseDirectory,
|
|
96
|
-
nodeVersion,
|
|
97
|
-
})
|
|
91
|
+
/**
|
|
92
|
+
* @param {object} param0
|
|
93
|
+
* @param {*} param0.config
|
|
94
|
+
* @param {import('../../commands/base-command.mjs').default} param0.command
|
|
95
|
+
*/
|
|
96
|
+
export const getBuildSettings = async ({ command, config }) => {
|
|
97
|
+
const settings = await detectBuildSettings(command)
|
|
98
|
+
// TODO: add prompt for asking to choose the build command
|
|
99
|
+
/** @type {Partial<import('@netlify/build-info').Settings>} */
|
|
100
|
+
// eslint-disable-next-line unicorn/explicit-length-check
|
|
101
|
+
const setting = settings.length > 0 ? settings[0] : {}
|
|
98
102
|
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...`)
|
|
103
|
+
await normalizeSettings(setting, config, command)
|
|
104
|
+
|
|
105
|
+
if (recommendedPlugins.length !== 0 && setting.framework?.name) {
|
|
106
|
+
log(`Configuring ${formatTitle(setting.framework?.name)} runtime...`)
|
|
110
107
|
log()
|
|
111
108
|
}
|
|
112
109
|
|
|
@@ -199,6 +196,9 @@ export const formatErrorMessage = ({ error, message }) => {
|
|
|
199
196
|
return `${message} with error: ${chalk.red(errorMessage)}`
|
|
200
197
|
}
|
|
201
198
|
|
|
199
|
+
/**
|
|
200
|
+
* @param {string} title
|
|
201
|
+
*/
|
|
202
202
|
const formatTitle = (title) => chalk.cyan(title)
|
|
203
203
|
|
|
204
204
|
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
|
@@ -375,7 +375,6 @@ const initializeProxy = async function ({ configPath, distDir, env, host, port,
|
|
|
375
375
|
proxy.before('web', 'stream', (req) => {
|
|
376
376
|
// See https://github.com/http-party/node-http-proxy/issues/1219#issuecomment-511110375
|
|
377
377
|
if (req.headers.expect) {
|
|
378
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
379
378
|
req.__expectHeader = req.headers.expect
|
|
380
379
|
delete req.headers.expect
|
|
381
380
|
}
|
|
@@ -402,9 +401,7 @@ const initializeProxy = async function ({ configPath, distDir, env, host, port,
|
|
|
402
401
|
handleProxyRequest(req, proxyReq)
|
|
403
402
|
}
|
|
404
403
|
|
|
405
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
406
404
|
if (req.__expectHeader) {
|
|
407
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
408
405
|
proxyReq.setHeader('Expect', req.__expectHeader)
|
|
409
406
|
}
|
|
410
407
|
if (req.originalBody) {
|
|
@@ -599,6 +596,10 @@ const onRequest = async (
|
|
|
599
596
|
proxy.web(req, res, options)
|
|
600
597
|
}
|
|
601
598
|
|
|
599
|
+
/**
|
|
600
|
+
* @param {import('./types.js').ServerSettings} settings
|
|
601
|
+
* @returns
|
|
602
|
+
*/
|
|
602
603
|
export const getProxyUrl = function (settings) {
|
|
603
604
|
const scheme = settings.https ? 'https' : 'http'
|
|
604
605
|
return `${scheme}://localhost:${settings.port}`
|
|
@@ -7,6 +7,7 @@ import fetch from 'node-fetch'
|
|
|
7
7
|
const GITHUB = 'GitHub'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
+
* @param {string} _url
|
|
10
11
|
* Takes a url like https://github.com/netlify-labs/all-the-functions/tree/master/functions/9-using-middleware
|
|
11
12
|
* and returns https://api.github.com/repos/netlify-labs/all-the-functions/contents/functions/9-using-middleware
|
|
12
13
|
*/
|
|
@@ -36,6 +37,9 @@ const getRepoURLContents = async function (repoHost, ownerAndRepo, contentsPath)
|
|
|
36
37
|
throw new Error('unsupported host ', repoHost)
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
* @param {string} _url
|
|
42
|
+
*/
|
|
39
43
|
export const validateRepoURL = function (_url) {
|
|
40
44
|
// TODO: use `url.URL()` instead
|
|
41
45
|
// eslint-disable-next-line n/no-deprecated-api
|
package/src/utils/run-build.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import { promises as fs } from 'fs'
|
|
3
|
-
import path from 'path'
|
|
4
|
-
import process from 'process'
|
|
3
|
+
import path, { join } from 'path'
|
|
5
4
|
|
|
6
5
|
import { INTERNAL_EDGE_FUNCTIONS_FOLDER } from '../lib/edge-functions/consts.mjs'
|
|
7
6
|
import { getPathInProject } from '../lib/settings.mjs'
|
|
@@ -12,10 +11,14 @@ import { INTERNAL_FUNCTIONS_FOLDER } from './functions/index.mjs'
|
|
|
12
11
|
|
|
13
12
|
const netlifyBuildPromise = import('@netlify/build')
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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 {string} configPath
|
|
18
|
+
* @param {string} destinationFolder The folder where it should be copied to. Either the root of the repo or a package inside a monorepo
|
|
19
|
+
*/
|
|
20
|
+
const copyConfig = async (configPath, destinationFolder) => {
|
|
21
|
+
const newConfigPath = path.resolve(destinationFolder, getPathInProject(['netlify.toml']))
|
|
19
22
|
|
|
20
23
|
try {
|
|
21
24
|
await fs.copyFile(configPath, newConfigPath)
|
|
@@ -26,6 +29,9 @@ const copyConfig = async ({ configPath, siteRoot }) => {
|
|
|
26
29
|
return newConfigPath
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} basePath
|
|
34
|
+
*/
|
|
29
35
|
const cleanInternalDirectory = async (basePath) => {
|
|
30
36
|
const ops = [INTERNAL_FUNCTIONS_FOLDER, INTERNAL_EDGE_FUNCTIONS_FOLDER, 'netlify.toml'].map((name) => {
|
|
31
37
|
const fullPath = path.resolve(basePath, getPathInProject([name]))
|
|
@@ -36,38 +42,52 @@ const cleanInternalDirectory = async (basePath) => {
|
|
|
36
42
|
await Promise.all(ops)
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
buffer: false,
|
|
53
|
-
offline,
|
|
54
|
-
cwd,
|
|
55
|
-
quiet,
|
|
56
|
-
saveConfig,
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
const runNetlifyBuild = async ({ cachedConfig, env, options, settings, site, timeline = 'build' }) => {
|
|
45
|
+
/**
|
|
46
|
+
* @param {object} params
|
|
47
|
+
* @param {import('../commands/base-command.mjs').default} params.command
|
|
48
|
+
* @param {import('../commands/base-command.mjs').default} params.command
|
|
49
|
+
* @param {*} params.options The flags of the command
|
|
50
|
+
* @param {import('./types.js').ServerSettings} params.settings
|
|
51
|
+
* @param {NodeJS.ProcessEnv} [params.env]
|
|
52
|
+
* @param {'build' | 'dev'} [params.timeline]
|
|
53
|
+
* @returns
|
|
54
|
+
*/
|
|
55
|
+
export const runNetlifyBuild = async ({ command, env = {}, options, settings, timeline = 'build' }) => {
|
|
56
|
+
const { cachedConfig, site } = command.netlify
|
|
57
|
+
|
|
60
58
|
const { default: buildSite, startDev } = await netlifyBuildPromise
|
|
61
|
-
|
|
59
|
+
|
|
60
|
+
const sharedOptions = {
|
|
62
61
|
cachedConfig,
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
configPath: cachedConfig.configPath,
|
|
63
|
+
siteId: cachedConfig.siteInfo.id,
|
|
64
|
+
token: cachedConfig.token,
|
|
65
|
+
dry: options.dry,
|
|
66
|
+
debug: options.debug,
|
|
67
|
+
context: options.context,
|
|
68
|
+
mode: 'cli',
|
|
69
|
+
telemetry: false,
|
|
70
|
+
buffer: false,
|
|
71
|
+
offline: options.offline,
|
|
72
|
+
packagePath: command.workspacePackage,
|
|
73
|
+
cwd: cachedConfig.buildDir,
|
|
74
|
+
quiet: options.quiet,
|
|
75
|
+
saveConfig: options.saveConfig,
|
|
76
|
+
}
|
|
77
|
+
|
|
65
78
|
const devCommand = async (settingsOverrides = {}) => {
|
|
79
|
+
let cwd = command.workingDir
|
|
80
|
+
|
|
81
|
+
if (command.project.workspace?.packages.length) {
|
|
82
|
+
cwd = join(command.project.jsWorkspaceRoot, settings.baseDirectory || '')
|
|
83
|
+
}
|
|
84
|
+
|
|
66
85
|
const { ipVersion } = await startFrameworkServer({
|
|
67
86
|
settings: {
|
|
68
87
|
...settings,
|
|
69
88
|
...settingsOverrides,
|
|
70
89
|
},
|
|
90
|
+
cwd,
|
|
71
91
|
})
|
|
72
92
|
|
|
73
93
|
settings.frameworkHost = ipVersion === 6 ? '::1' : '127.0.0.1'
|
|
@@ -80,7 +100,7 @@ const runNetlifyBuild = async ({ cachedConfig, env, options, settings, site, tim
|
|
|
80
100
|
|
|
81
101
|
// Copy `netlify.toml` into the internal directory. This will be the new
|
|
82
102
|
// location of the config file for the duration of the command.
|
|
83
|
-
const tempConfigPath = await copyConfig(
|
|
103
|
+
const tempConfigPath = await copyConfig(cachedConfig.configPath, command.workingDir)
|
|
84
104
|
const buildSiteOptions = {
|
|
85
105
|
...sharedOptions,
|
|
86
106
|
outputConfigPath: tempConfigPath,
|
|
@@ -118,13 +138,19 @@ const runNetlifyBuild = async ({ cachedConfig, env, options, settings, site, tim
|
|
|
118
138
|
// Run Netlify Build using the `startDev` entry point.
|
|
119
139
|
const { error: startDevError, success } = await startDev(devCommand, startDevOptions)
|
|
120
140
|
|
|
121
|
-
if (!success) {
|
|
141
|
+
if (!success && startDevError) {
|
|
122
142
|
error(`Could not start local development server\n\n${startDevError.message}\n\n${startDevError.stack}`)
|
|
123
143
|
}
|
|
124
144
|
|
|
125
145
|
return {}
|
|
126
146
|
}
|
|
127
147
|
|
|
148
|
+
/**
|
|
149
|
+
* @param {Omit<Parameters<typeof runNetlifyBuild>[0], 'timeline'>} options
|
|
150
|
+
*/
|
|
128
151
|
export const runDevTimeline = (options) => runNetlifyBuild({ ...options, timeline: 'dev' })
|
|
129
152
|
|
|
153
|
+
/**
|
|
154
|
+
* @param {Omit<Parameters<typeof runNetlifyBuild>[0], 'timeline'>} options
|
|
155
|
+
*/
|
|
130
156
|
export const runBuildTimeline = (options) => runNetlifyBuild({ ...options, timeline: 'build' })
|
package/src/utils/shell.mjs
CHANGED
|
@@ -40,17 +40,26 @@ const cleanupBeforeExit = async ({ exitCode }) => {
|
|
|
40
40
|
/**
|
|
41
41
|
* Run a command and pipe stdout, stderr and stdin
|
|
42
42
|
* @param {string} command
|
|
43
|
-
* @param {
|
|
43
|
+
* @param {object} options
|
|
44
|
+
* @param {import('ora').Ora|null} [options.spinner]
|
|
45
|
+
* @param {NodeJS.ProcessEnv} [options.env]
|
|
46
|
+
* @param {string} [options.cwd]
|
|
44
47
|
* @returns {execa.ExecaChildProcess<string>}
|
|
45
48
|
*/
|
|
46
|
-
export const runCommand = (command,
|
|
49
|
+
export const runCommand = (command, options = {}) => {
|
|
50
|
+
const { cwd, env = {}, spinner = null } = options
|
|
47
51
|
const commandProcess = execa.command(command, {
|
|
48
52
|
preferLocal: true,
|
|
49
53
|
// we use reject=false to avoid rejecting synchronously when the command doesn't exist
|
|
50
54
|
reject: false,
|
|
51
|
-
env
|
|
55
|
+
env: {
|
|
56
|
+
// we want always colorful terminal outputs
|
|
57
|
+
FORCE_COLOR: 'true',
|
|
58
|
+
...env,
|
|
59
|
+
},
|
|
52
60
|
// windowsHide needs to be false for child process to terminate properly on Windows
|
|
53
61
|
windowsHide: false,
|
|
62
|
+
cwd,
|
|
54
63
|
})
|
|
55
64
|
|
|
56
65
|
// This ensures that an active spinner stays at the bottom of the commandline
|
|
@@ -82,8 +91,9 @@ export const runCommand = (command, env = {}, spinner = null) => {
|
|
|
82
91
|
const [commandWithoutArgs] = command.split(' ')
|
|
83
92
|
if (result.failed && isNonExistingCommandError({ command: commandWithoutArgs, error: result })) {
|
|
84
93
|
log(
|
|
85
|
-
NETLIFYDEVERR
|
|
86
|
-
|
|
94
|
+
`${NETLIFYDEVERR} Failed running command: ${command}. Please verify ${chalk.magenta(
|
|
95
|
+
`'${commandWithoutArgs}'`,
|
|
96
|
+
)} exists`,
|
|
87
97
|
)
|
|
88
98
|
} else {
|
|
89
99
|
const errorMessage = result.failed
|
|
@@ -100,6 +110,13 @@ export const runCommand = (command, env = {}, spinner = null) => {
|
|
|
100
110
|
return commandProcess
|
|
101
111
|
}
|
|
102
112
|
|
|
113
|
+
/**
|
|
114
|
+
*
|
|
115
|
+
* @param {object} config
|
|
116
|
+
* @param {string} config.command
|
|
117
|
+
* @param {*} config.error
|
|
118
|
+
* @returns
|
|
119
|
+
*/
|
|
103
120
|
const isNonExistingCommandError = ({ command, error: commandError }) => {
|
|
104
121
|
// `ENOENT` is only returned for non Windows systems
|
|
105
122
|
// See https://github.com/sindresorhus/execa/pull/447
|
|
@@ -108,7 +125,7 @@ const isNonExistingCommandError = ({ command, error: commandError }) => {
|
|
|
108
125
|
}
|
|
109
126
|
|
|
110
127
|
// if the command is a package manager we let it report the error
|
|
111
|
-
if (['yarn', 'npm'].includes(command)) {
|
|
128
|
+
if (['yarn', 'npm', 'pnpm'].includes(command)) {
|
|
112
129
|
return false
|
|
113
130
|
}
|
|
114
131
|
|
|
@@ -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)
|
|
@@ -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
|
-
}
|