@netlify/config 18.2.4 → 18.2.5
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.js +5 -0
- package/lib/api/build_settings.js +20 -33
- package/lib/api/client.js +10 -13
- package/lib/api/site_info.js +48 -56
- package/lib/base.js +10 -18
- package/lib/bin/flags.js +134 -142
- package/lib/bin/main.js +49 -63
- package/lib/build_dir.js +11 -15
- package/lib/cached_config.js +14 -17
- package/lib/case.js +16 -35
- package/lib/context.js +62 -84
- package/lib/default.js +18 -22
- package/lib/env/envelope.js +23 -23
- package/lib/env/git.js +18 -18
- package/lib/env/main.js +127 -179
- package/lib/error.js +19 -27
- package/lib/events.js +18 -19
- package/lib/files.js +63 -87
- package/lib/functions_config.js +36 -52
- package/lib/headers.js +17 -27
- package/lib/inline_config.js +6 -7
- package/lib/log/cleanup.js +54 -82
- package/lib/log/logger.js +25 -36
- package/lib/log/main.js +31 -40
- package/lib/log/messages.js +56 -95
- package/lib/log/options.js +24 -38
- package/lib/log/serialize.js +3 -4
- package/lib/log/theme.js +10 -11
- package/lib/main.js +188 -263
- package/lib/merge.js +25 -35
- package/lib/merge_normalize.js +17 -24
- package/lib/mutations/apply.js +53 -65
- package/lib/mutations/config_prop_name.js +6 -8
- package/lib/mutations/update.js +79 -98
- package/lib/normalize.js +24 -28
- package/lib/options/base.js +39 -51
- package/lib/options/branch.js +23 -26
- package/lib/options/feature_flags.js +7 -10
- package/lib/options/main.js +76 -96
- package/lib/options/repository_root.js +11 -16
- package/lib/origin.js +22 -29
- package/lib/parse.js +42 -55
- package/lib/path.js +29 -40
- package/lib/redirects.js +16 -26
- package/lib/simplify.js +66 -92
- package/lib/utils/group.js +5 -6
- package/lib/utils/remove_falsy.js +9 -13
- package/lib/utils/set.js +19 -25
- package/lib/utils/toml.js +13 -16
- package/lib/validate/context.js +24 -43
- package/lib/validate/example.js +20 -27
- package/lib/validate/helpers.js +17 -23
- package/lib/validate/identical.js +8 -12
- package/lib/validate/main.js +83 -127
- package/lib/validate/validations.js +243 -257
- package/package.json +13 -8
package/lib/merge_normalize.js
CHANGED
|
@@ -1,31 +1,24 @@
|
|
|
1
|
-
import { normalizeConfigCase } from './case.js'
|
|
2
|
-
import { normalizeConfig } from './normalize.js'
|
|
3
|
-
import { addOrigins } from './origin.js'
|
|
4
|
-
import { validateIdenticalPlugins } from './validate/identical.js'
|
|
5
|
-
import {
|
|
6
|
-
validatePreCaseNormalize,
|
|
7
|
-
validatePreMergeConfig,
|
|
8
|
-
validatePreNormalizeConfig,
|
|
9
|
-
validatePostNormalizeConfig,
|
|
10
|
-
} from './validate/main.js'
|
|
11
|
-
|
|
1
|
+
import { normalizeConfigCase } from './case.js';
|
|
2
|
+
import { normalizeConfig } from './normalize.js';
|
|
3
|
+
import { addOrigins } from './origin.js';
|
|
4
|
+
import { validateIdenticalPlugins } from './validate/identical.js';
|
|
5
|
+
import { validatePreCaseNormalize, validatePreMergeConfig, validatePreNormalizeConfig, validatePostNormalizeConfig, } from './validate/main.js';
|
|
12
6
|
// Perform validation and normalization logic to apply to all of:
|
|
13
7
|
// - config, defaultConfig, inlineConfig
|
|
14
8
|
// - context-specific configs
|
|
15
9
|
// Therefore, this is performing before merging those together.
|
|
16
10
|
export const normalizeBeforeConfigMerge = function (config, origin) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
11
|
+
validatePreCaseNormalize(config);
|
|
12
|
+
const configA = normalizeConfigCase(config);
|
|
13
|
+
validatePreMergeConfig(configA);
|
|
14
|
+
const configB = addOrigins(configA, origin);
|
|
15
|
+
validateIdenticalPlugins(configB);
|
|
16
|
+
return configB;
|
|
17
|
+
};
|
|
25
18
|
// Validation and normalization logic performed after merging
|
|
26
19
|
export const normalizeAfterConfigMerge = function (config) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
20
|
+
validatePreNormalizeConfig(config);
|
|
21
|
+
const configA = normalizeConfig(config);
|
|
22
|
+
validatePostNormalizeConfig(configA);
|
|
23
|
+
return configA;
|
|
24
|
+
};
|
package/lib/mutations/apply.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { throwUserError } from '../error.js'
|
|
2
|
-
import { EVENTS } from '../events.js'
|
|
3
|
-
import { WILDCARD_ALL, FUNCTION_CONFIG_PROPERTIES } from '../functions_config.js'
|
|
4
|
-
import { setProp } from '../utils/set.js'
|
|
5
|
-
|
|
6
|
-
import { getPropName } from './config_prop_name.js'
|
|
7
|
-
|
|
1
|
+
import { throwUserError } from '../error.js';
|
|
2
|
+
import { EVENTS } from '../events.js';
|
|
3
|
+
import { WILDCARD_ALL, FUNCTION_CONFIG_PROPERTIES } from '../functions_config.js';
|
|
4
|
+
import { setProp } from '../utils/set.js';
|
|
5
|
+
import { getPropName } from './config_prop_name.js';
|
|
8
6
|
// Apply a series of mutations to `inlineConfig`.
|
|
9
7
|
// Meant to be used to apply configuration changes at build time.
|
|
10
8
|
// Those are applied on the `inlineConfig` object after `@netlify/config`
|
|
@@ -12,67 +10,57 @@ import { getPropName } from './config_prop_name.js'
|
|
|
12
10
|
// normalization) so that the final `config` object can be serialized back to
|
|
13
11
|
// a `netlify.toml`.
|
|
14
12
|
export const applyMutations = function (inlineConfig, configMutations) {
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
13
|
+
return configMutations.reduce(applyMutation, inlineConfig);
|
|
14
|
+
};
|
|
18
15
|
const applyMutation = function (inlineConfig, { keys, value, event }) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return denormalize === undefined ? setProp(inlineConfig, keys, value) : denormalize(inlineConfig, value, keys)
|
|
28
|
-
}
|
|
29
|
-
|
|
16
|
+
const propName = getPropName(keys);
|
|
17
|
+
if (!(propName in MUTABLE_PROPS)) {
|
|
18
|
+
throwUserError(`"netlifyConfig.${propName}" is read-only.`);
|
|
19
|
+
}
|
|
20
|
+
const { lastEvent, denormalize } = MUTABLE_PROPS[propName];
|
|
21
|
+
validateEvent(lastEvent, event, propName);
|
|
22
|
+
return denormalize === undefined ? setProp(inlineConfig, keys, value) : denormalize(inlineConfig, value, keys);
|
|
23
|
+
};
|
|
30
24
|
const validateEvent = function (lastEvent, event, propName) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
25
|
+
if (EVENTS.indexOf(lastEvent) < EVENTS.indexOf(event)) {
|
|
26
|
+
throwUserError(`"netlifyConfig.${propName}" cannot be modified after "${lastEvent}".`);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
36
29
|
// `functions['*'].*` has higher priority than `functions.*` so we convert the
|
|
37
30
|
// latter to the former.
|
|
38
|
-
const denormalizeFunctionsTopProps = function (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
functions: { ...functions, [WILDCARD_ALL]: { ...wildcardProps, [key]: value } },
|
|
47
|
-
}
|
|
48
|
-
: { ...inlineConfig, functions: { ...functions, [key]: value } }
|
|
49
|
-
}
|
|
50
|
-
|
|
31
|
+
const denormalizeFunctionsTopProps = function ({ functions, functions: { [WILDCARD_ALL]: wildcardProps } = {}, ...inlineConfig }, value, [, key]) {
|
|
32
|
+
return FUNCTION_CONFIG_PROPERTIES.has(key)
|
|
33
|
+
? {
|
|
34
|
+
...inlineConfig,
|
|
35
|
+
functions: { ...functions, [WILDCARD_ALL]: { ...wildcardProps, [key]: value } },
|
|
36
|
+
}
|
|
37
|
+
: { ...inlineConfig, functions: { ...functions, [key]: value } };
|
|
38
|
+
};
|
|
51
39
|
// List of properties that are not read-only.
|
|
52
40
|
const MUTABLE_PROPS = {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
41
|
+
'build.command': { lastEvent: 'onPreBuild' },
|
|
42
|
+
'build.edge_functions': { lastEvent: 'onPostBuild' },
|
|
43
|
+
'build.environment': { lastEvent: 'onPostBuild' },
|
|
44
|
+
'build.environment.*': { lastEvent: 'onPostBuild' },
|
|
45
|
+
'build.functions': { lastEvent: 'onBuild' },
|
|
46
|
+
'build.processing': { lastEvent: 'onPostBuild' },
|
|
47
|
+
'build.processing.css': { lastEvent: 'onPostBuild' },
|
|
48
|
+
'build.processing.css.bundle': { lastEvent: 'onPostBuild' },
|
|
49
|
+
'build.processing.css.minify': { lastEvent: 'onPostBuild' },
|
|
50
|
+
'build.processing.html': { lastEvent: 'onPostBuild' },
|
|
51
|
+
'build.processing.html.pretty_urls': { lastEvent: 'onPostBuild' },
|
|
52
|
+
'build.processing.images': { lastEvent: 'onPostBuild' },
|
|
53
|
+
'build.processing.images.compress': { lastEvent: 'onPostBuild' },
|
|
54
|
+
'build.processing.js': { lastEvent: 'onPostBuild' },
|
|
55
|
+
'build.processing.js.bundle': { lastEvent: 'onPostBuild' },
|
|
56
|
+
'build.processing.js.minify': { lastEvent: 'onPostBuild' },
|
|
57
|
+
'build.processing.skip_processing': { lastEvent: 'onPostBuild' },
|
|
58
|
+
'build.publish': { lastEvent: 'onPostBuild' },
|
|
59
|
+
'build.services': { lastEvent: 'onPostBuild' },
|
|
60
|
+
'build.services.*': { lastEvent: 'onPostBuild' },
|
|
61
|
+
edge_functions: { lastEvent: 'onPostBuild' },
|
|
62
|
+
'functions.*': { lastEvent: 'onBuild', denormalize: denormalizeFunctionsTopProps },
|
|
63
|
+
'functions.*.*': { lastEvent: 'onBuild' },
|
|
64
|
+
headers: { lastEvent: 'onPostBuild' },
|
|
65
|
+
redirects: { lastEvent: 'onPostBuild' },
|
|
66
|
+
};
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
// Retrieve normalized property name
|
|
2
2
|
export const getPropName = function (keys) {
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
|
|
3
|
+
return keys.reduce(normalizeDynamicProp, '');
|
|
4
|
+
};
|
|
6
5
|
// Some properties are user-defined, i.e. we need to replace them with a "*" token
|
|
7
6
|
// Check if a property name is dynamic, such as `functions.{functionName}`, or
|
|
8
7
|
// is an array index.
|
|
9
8
|
// In those cases, we replace it by "*".
|
|
10
9
|
const normalizeDynamicProp = function (propName, key) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
10
|
+
const normalizedKey = Number.isInteger(key) || DYNAMIC_OBJECT_PROPS.has(propName) ? '*' : String(key);
|
|
11
|
+
return propName === '' ? normalizedKey : `${propName}.${normalizedKey}`;
|
|
12
|
+
};
|
|
15
13
|
// Properties with dynamic children
|
|
16
|
-
const DYNAMIC_OBJECT_PROPS = new Set(['build.services', 'build.environment', 'functions', 'functions.*'])
|
|
14
|
+
const DYNAMIC_OBJECT_PROPS = new Set(['build.services', 'build.environment', 'functions', 'functions.*']);
|
package/lib/mutations/update.js
CHANGED
|
@@ -1,117 +1,98 @@
|
|
|
1
|
-
import { promises as fs } from 'fs'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { serializeToml } from '../utils/toml.js'
|
|
12
|
-
|
|
13
|
-
import { applyMutations } from './apply.js'
|
|
14
|
-
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { pathExists } from 'path-exists';
|
|
3
|
+
import { ensureConfigPriority } from '../context.js';
|
|
4
|
+
import { addHeaders } from '../headers.js';
|
|
5
|
+
import { mergeConfigs } from '../merge.js';
|
|
6
|
+
import { parseOptionalConfig } from '../parse.js';
|
|
7
|
+
import { addRedirects } from '../redirects.js';
|
|
8
|
+
import { simplifyConfig } from '../simplify.js';
|
|
9
|
+
import { serializeToml } from '../utils/toml.js';
|
|
10
|
+
import { applyMutations } from './apply.js';
|
|
15
11
|
// Persist configuration changes to `netlify.toml`.
|
|
16
12
|
// If `netlify.toml` does not exist, creates it. Otherwise, merges the changes.
|
|
17
|
-
export const updateConfig = async function (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
deleteSideFile(headersPath),
|
|
35
|
-
deleteSideFile(redirectsPath),
|
|
36
|
-
])
|
|
37
|
-
}
|
|
38
|
-
|
|
13
|
+
export const updateConfig = async function (configMutations, { buildDir, configPath, headersPath, redirectsPath, context, branch, logs, featureFlags }) {
|
|
14
|
+
if (configMutations.length === 0) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const inlineConfig = applyMutations({}, configMutations);
|
|
18
|
+
const normalizedInlineConfig = ensureConfigPriority(inlineConfig, context, branch);
|
|
19
|
+
const updatedConfig = await mergeWithConfig(normalizedInlineConfig, configPath);
|
|
20
|
+
const configWithHeaders = await addHeaders({ config: updatedConfig, headersPath, logs, featureFlags });
|
|
21
|
+
const finalConfig = await addRedirects({ config: configWithHeaders, redirectsPath, logs, featureFlags });
|
|
22
|
+
const simplifiedConfig = simplifyConfig(finalConfig);
|
|
23
|
+
await backupConfig({ buildDir, configPath, headersPath, redirectsPath });
|
|
24
|
+
await Promise.all([
|
|
25
|
+
saveConfig(configPath, simplifiedConfig),
|
|
26
|
+
deleteSideFile(headersPath),
|
|
27
|
+
deleteSideFile(redirectsPath),
|
|
28
|
+
]);
|
|
29
|
+
};
|
|
39
30
|
// If `netlify.toml` exists, deeply merges the configuration changes.
|
|
40
31
|
const mergeWithConfig = async function (normalizedInlineConfig, configPath) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
32
|
+
const config = await parseOptionalConfig(configPath);
|
|
33
|
+
const updatedConfig = mergeConfigs([config, normalizedInlineConfig]);
|
|
34
|
+
return updatedConfig;
|
|
35
|
+
};
|
|
46
36
|
// Serialize the changes to `netlify.toml`
|
|
47
37
|
const saveConfig = async function (configPath, simplifiedConfig) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
38
|
+
const serializedConfig = serializeToml(simplifiedConfig);
|
|
39
|
+
await fs.writeFile(configPath, serializedConfig);
|
|
40
|
+
};
|
|
52
41
|
// Deletes `_headers/_redirects` since they are merged to `netlify.toml`,
|
|
53
42
|
// to fix any priority problem.
|
|
54
43
|
const deleteSideFile = async function (filePath) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
44
|
+
if (filePath === undefined || !(await pathExists(filePath))) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
await fs.unlink(filePath);
|
|
48
|
+
};
|
|
62
49
|
// Modifications to `netlify.toml` and `_headers/_redirects` are only meant for
|
|
63
50
|
// the deploy API call. After it's been performed, we restore their former
|
|
64
51
|
// state.
|
|
65
52
|
// We do this by backing them up inside some sibling directory.
|
|
66
53
|
const backupConfig = async function ({ buildDir, configPath, headersPath, redirectsPath }) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
54
|
+
const tempDir = getTempDir(buildDir);
|
|
55
|
+
await fs.mkdir(tempDir, { recursive: true });
|
|
56
|
+
await Promise.all([
|
|
57
|
+
backupFile(configPath, `${tempDir}/netlify.toml`),
|
|
58
|
+
backupFile(headersPath, `${tempDir}/_headers`),
|
|
59
|
+
backupFile(redirectsPath, `${tempDir}/_redirects`),
|
|
60
|
+
]);
|
|
61
|
+
};
|
|
76
62
|
export const restoreConfig = async function (configMutations, { buildDir, configPath, headersPath, redirectsPath }) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
63
|
+
if (configMutations.length === 0) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const tempDir = getTempDir(buildDir);
|
|
67
|
+
await Promise.all([
|
|
68
|
+
copyOrDelete(`${tempDir}/netlify.toml`, configPath),
|
|
69
|
+
copyOrDelete(`${tempDir}/_headers`, headersPath),
|
|
70
|
+
copyOrDelete(`${tempDir}/_redirects`, redirectsPath),
|
|
71
|
+
]);
|
|
72
|
+
};
|
|
89
73
|
const getTempDir = function (buildDir) {
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
74
|
+
return `${buildDir}/.netlify/deploy`;
|
|
75
|
+
};
|
|
93
76
|
const backupFile = async function (original, backup) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
await fs.copyFile(original, backup)
|
|
102
|
-
}
|
|
103
|
-
|
|
77
|
+
// this makes sure we don't restore stale files
|
|
78
|
+
await deleteNoError(backup);
|
|
79
|
+
if (!(await pathExists(original))) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
await fs.copyFile(original, backup);
|
|
83
|
+
};
|
|
104
84
|
const deleteNoError = async (path) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
85
|
+
try {
|
|
86
|
+
await fs.unlink(path);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// continue regardless error
|
|
90
|
+
}
|
|
91
|
+
};
|
|
110
92
|
const copyOrDelete = async function (src, dest) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
93
|
+
if (await pathExists(src)) {
|
|
94
|
+
await fs.copyFile(src, dest);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
await deleteNoError(dest);
|
|
98
|
+
};
|
package/lib/normalize.js
CHANGED
|
@@ -1,36 +1,32 @@
|
|
|
1
|
-
import { normalizeFunctionsProps, WILDCARD_ALL } from './functions_config.js'
|
|
2
|
-
import { mergeConfigs } from './merge.js'
|
|
3
|
-
import { DEFAULT_ORIGIN } from './origin.js'
|
|
4
|
-
import { removeFalsy } from './utils/remove_falsy.js'
|
|
5
|
-
|
|
1
|
+
import { normalizeFunctionsProps, WILDCARD_ALL } from './functions_config.js';
|
|
2
|
+
import { mergeConfigs } from './merge.js';
|
|
3
|
+
import { DEFAULT_ORIGIN } from './origin.js';
|
|
4
|
+
import { removeFalsy } from './utils/remove_falsy.js';
|
|
6
5
|
// Normalize configuration object
|
|
7
6
|
export const normalizeConfig = function (config) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
7
|
+
const configA = removeEmpty(config);
|
|
8
|
+
const { build, functions, plugins, ...configB } = mergeConfigs([DEFAULT_CONFIG, configA]);
|
|
9
|
+
const { build: buildA, functions: functionsA, functionsDirectoryProps } = normalizeFunctionsProps(build, functions);
|
|
10
|
+
const pluginsA = plugins.map(normalizePlugin);
|
|
11
|
+
return { ...configB, build: buildA, functions: functionsA, plugins: pluginsA, ...functionsDirectoryProps };
|
|
12
|
+
};
|
|
15
13
|
// Remove empty strings.
|
|
16
14
|
// This notably ensures that empty strings in the build command are removed.
|
|
17
15
|
// Otherwise those would be run during builds, making the build fail.
|
|
18
16
|
const removeEmpty = function ({ build, ...config }) {
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
17
|
+
return removeFalsy({ ...config, build: removeFalsy(build) });
|
|
18
|
+
};
|
|
22
19
|
const DEFAULT_CONFIG = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
20
|
+
build: {
|
|
21
|
+
environment: {},
|
|
22
|
+
publish: '.',
|
|
23
|
+
publishOrigin: DEFAULT_ORIGIN,
|
|
24
|
+
processing: { css: {}, html: {}, images: {}, js: {} },
|
|
25
|
+
services: {},
|
|
26
|
+
},
|
|
27
|
+
functions: { [WILDCARD_ALL]: {} },
|
|
28
|
+
plugins: [],
|
|
29
|
+
};
|
|
34
30
|
const normalizePlugin = function ({ inputs = {}, ...plugin }) {
|
|
35
|
-
|
|
36
|
-
}
|
|
31
|
+
return removeFalsy({ ...plugin, inputs });
|
|
32
|
+
};
|
package/lib/options/base.js
CHANGED
|
@@ -1,66 +1,54 @@
|
|
|
1
|
-
import { promises as fs } from 'fs'
|
|
2
|
-
import { dirname, relative, sep } from 'path'
|
|
3
|
-
|
|
4
|
-
import { pathExists } from 'path-exists'
|
|
5
|
-
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { dirname, relative, sep } from 'path';
|
|
3
|
+
import { pathExists } from 'path-exists';
|
|
6
4
|
// Retrieve `base` override.
|
|
7
5
|
// This uses any directory below `repositoryRoot` and above (or equal to)
|
|
8
6
|
// `cwd` that has a `.netlify` or `netlify.toml`. This allows Netlify CLI users
|
|
9
7
|
// to `cd` into monorepo directories to change their base and build directories.
|
|
10
8
|
// Do all checks in parallel for speed
|
|
11
9
|
export const getBaseOverride = async function ({ repositoryRoot, cwd }) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// since we want `publish`, `functions` and `edge_functions` to be relative to it.
|
|
30
|
-
return { base, baseRelDir: true }
|
|
31
|
-
}
|
|
32
|
-
|
|
10
|
+
// Performance optimization
|
|
11
|
+
if (repositoryRoot === cwd) {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
const [repositoryRootA, cwdA] = await Promise.all([fs.realpath(repositoryRoot), fs.realpath(cwd)]);
|
|
15
|
+
const basePaths = getBasePaths(repositoryRootA, cwdA);
|
|
16
|
+
const basePath = await locatePath(basePaths);
|
|
17
|
+
if (basePath === undefined) {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
// `base` starting with a `/` are relative to `repositoryRoot`, so we cannot
|
|
21
|
+
// return an absolute path
|
|
22
|
+
const base = relative(repositoryRoot, dirname(basePath));
|
|
23
|
+
// When `base` is explicitely overridden, `baseRelDir: true` makes more sense
|
|
24
|
+
// since we want `publish`, `functions` and `edge_functions` to be relative to it.
|
|
25
|
+
return { base, baseRelDir: true };
|
|
26
|
+
};
|
|
33
27
|
// Returns list of files to check for the existence of a `base`
|
|
34
28
|
const getBasePaths = function (repositoryRoot, cwd) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
29
|
+
const subdirs = getSubdirs(repositoryRoot, cwd);
|
|
30
|
+
const basePaths = subdirs.flatMap((subdir) => BASE_FILENAMES.map((filename) => `${subdir}/${filename}`));
|
|
31
|
+
return basePaths;
|
|
32
|
+
};
|
|
40
33
|
// Retrieves list of directories between `repositoryRoot` and `cwd`, including
|
|
41
34
|
// `cwd` but excluding `repositoryRoot`
|
|
42
35
|
const getSubdirs = function (repositoryRoot, dir, subdirs = []) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const BASE_FILENAMES = ['.netlify', 'netlify.toml', 'package.json']
|
|
51
|
-
|
|
36
|
+
if (!dir.startsWith(`${repositoryRoot}${sep}`)) {
|
|
37
|
+
return subdirs;
|
|
38
|
+
}
|
|
39
|
+
return getSubdirs(repositoryRoot, dirname(dir), [...subdirs, dir]);
|
|
40
|
+
};
|
|
41
|
+
const BASE_FILENAMES = ['.netlify', 'netlify.toml', 'package.json'];
|
|
52
42
|
// Returns the first path that exists.
|
|
53
43
|
// Like `locate-path` library but works with mixed files/directories
|
|
54
44
|
const locatePath = async function (paths) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
45
|
+
const results = await Promise.all(paths.map(returnIfExists));
|
|
46
|
+
const path = results.find(Boolean);
|
|
47
|
+
return path;
|
|
48
|
+
};
|
|
60
49
|
const returnIfExists = async function (path) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
50
|
+
if (!(await pathExists(path))) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
return path;
|
|
54
|
+
};
|
package/lib/options/branch.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { execaCommand } from 'execa'
|
|
2
|
-
|
|
1
|
+
import { execaCommand } from 'execa';
|
|
3
2
|
// Find out git branch among (in priority order):
|
|
4
3
|
// - `branch` option
|
|
5
4
|
// - `BRANCH` environment variable
|
|
@@ -7,28 +6,26 @@ import { execaCommand } from 'execa'
|
|
|
7
6
|
// - `main` (using `git`)
|
|
8
7
|
// - 'master' (fallback)
|
|
9
8
|
export const getBranch = async function ({ branch, repositoryRoot }) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return FALLBACK_BRANCH
|
|
25
|
-
}
|
|
26
|
-
|
|
9
|
+
if (branch) {
|
|
10
|
+
return branch;
|
|
11
|
+
}
|
|
12
|
+
const headBranch = await getGitBranch(repositoryRoot, 'HEAD');
|
|
13
|
+
if (headBranch !== undefined) {
|
|
14
|
+
return headBranch;
|
|
15
|
+
}
|
|
16
|
+
const mainBranch = await getGitBranch(repositoryRoot, 'main');
|
|
17
|
+
if (mainBranch !== undefined) {
|
|
18
|
+
return mainBranch;
|
|
19
|
+
}
|
|
20
|
+
return FALLBACK_BRANCH;
|
|
21
|
+
};
|
|
27
22
|
const getGitBranch = async function (repositoryRoot, gitRef) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
try {
|
|
24
|
+
const { stdout } = await execaCommand(`git rev-parse --abbrev-ref ${gitRef}`, { cwd: repositoryRoot });
|
|
25
|
+
return stdout;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// continue regardless error
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const FALLBACK_BRANCH = 'master';
|