-
Notifications
You must be signed in to change notification settings - Fork 100
Expand file tree
/
Copy pathmain.ts
More file actions
233 lines (209 loc) · 6.12 KB
/
Copy pathmain.ts
File metadata and controls
233 lines (209 loc) · 6.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
import type { NetlifyAPI } from '@netlify/api'
import omit from 'omit.js'
import { removeFalsy } from '../utils/remove_falsy.js'
import { getEnvelope } from './envelope.js'
import { getGitEnv } from './git.js'
// Retrieve this site's environment variable. Also take into account team-wide
// environment variables.
// The buildbot already has the right environment variables. This is mostly
// meant so that local builds can mimic production builds
// TODO: add `netlify.toml` `build.environment`, after normalization
// TODO: add `CONTEXT` and others
export const getEnv = async function ({
api,
mode,
config,
siteInfo,
accounts,
buildDir,
branch,
deployId,
buildId,
context,
cachedEnv,
}) {
if (mode === 'buildbot') {
return {}
}
const internalEnv = getInternalEnv(cachedEnv)
const generalEnv = await getGeneralEnv({ siteInfo, buildDir, branch, deployId, buildId, context })
const [accountEnv, uiEnv, configFileEnv] = await getUserEnv({
api,
config,
siteInfo,
accounts,
context,
})
// Sources of environment variables, in descending order of precedence.
const sources = [
{ key: 'configFile', values: configFileEnv },
{ key: 'ui', values: uiEnv },
{ key: 'account', values: accountEnv },
{ key: 'general', values: generalEnv },
{ key: 'internal', values: internalEnv },
]
// A hash mapping names of environment variables to objects containing the following properties:
// - sources: List of sources where the environment variable was found. The first element is the source that
// actually provided the variable (i.e. the one with the highest precedence).
// - value: The value of the environment variable.
const env = new Map()
sources.forEach((source) => {
Object.keys(source.values).forEach((key) => {
if (env.has(key)) {
const { sources: envSources, value } = env.get(key)
env.set(key, {
sources: [...envSources, source.key],
value: convertToString(value),
})
} else {
env.set(key, {
sources: [source.key],
value: convertToString(source.values[key]),
})
}
})
})
return Object.fromEntries(env)
}
const convertToString = (value) => {
if (value === null || value === undefined) {
return value
}
if (typeof value === 'string') {
return value
}
return value.toString()
}
// Environment variables not set by users, but meant to mimic the production
// environment.
const getGeneralEnv = async function ({
siteInfo,
siteInfo: { id, name, account_id: accountId },
buildDir,
branch,
deployId,
buildId,
context,
}) {
const gitEnv = await getGitEnv(buildDir, branch)
const deployUrls = getDeployUrls({ siteInfo: siteInfo as $TSFixMe, branch, deployId })
return removeFalsy({
SITE_ID: id,
SITE_NAME: name,
DEPLOY_ID: deployId,
BUILD_ID: buildId,
ACCOUNT_ID: accountId,
...deployUrls,
CONTEXT: context,
NETLIFY_LOCAL: 'true',
...gitEnv,
// Localization
LANG: 'en_US.UTF-8',
LANGUAGE: 'en_US:en',
LC_ALL: 'en_US.UTF-8',
// Disable telemetry of some tools
GATSBY_TELEMETRY_DISABLED: '1',
NEXT_TELEMETRY_DISABLED: '1',
})
}
/**
* Retrieve internal environment variables (needed for the CLI).
* Based on the cached environment, it returns the internal environment variables.
* Internal environment variables are those that are set by the CLI and are not retrieved by Envelope or the API.
*/
const getInternalEnv = function (
cachedEnv: Record<string, { sources: string[]; value: string }>,
): Record<string, string> {
return Object.entries(cachedEnv).reduce(
(prev, [key, { sources, value }]) => {
if (sources.includes('internal')) {
prev[key] = value
}
return prev
},
{} as Record<string, string>,
)
}
const getDeployUrls = function ({
siteInfo: {
name = DEFAULT_SITE_NAME,
ssl_url: sslUrl,
build_settings: { repo_url: REPOSITORY_URL = undefined } = {},
},
branch,
deployId,
}) {
return {
URL: sslUrl,
REPOSITORY_URL,
DEPLOY_PRIME_URL: `https://${branch}--${name}${NETLIFY_DEFAULT_DOMAIN}`,
DEPLOY_URL: `https://${deployId}--${name}${NETLIFY_DEFAULT_DOMAIN}`,
}
}
const NETLIFY_DEFAULT_DOMAIN = '.netlify.app'
// `site.name` is `undefined` when there is no token or siteId
const DEFAULT_SITE_NAME = 'site-name'
// Environment variables specified by the user
const getUserEnv = async function ({ api, config, siteInfo, accounts, context }) {
const accountEnv = await getAccountEnv({ api, siteInfo, accounts, context })
const uiEnv = getUiEnv({ siteInfo })
const configFileEnv = getConfigFileEnv({ config })
return [accountEnv, uiEnv, configFileEnv].map(cleanUserEnv)
}
// Account-wide environment variables
const getAccountEnv = async function ({
api,
siteInfo,
accounts,
context,
}: {
api: NetlifyAPI
siteInfo: any
accounts: any
context?: string
}) {
if (siteInfo.use_envelope) {
return await getEnvelope({ api, accountId: siteInfo.account_slug, context })
}
const { site_env: siteEnv = {} } = accounts.find(({ slug }) => slug === siteInfo.account_slug) || {}
return siteEnv
}
// Site-specific environment variables set in the UI
const getUiEnv = function ({ siteInfo: { build_settings: { env = {} } = {} } }) {
return env
}
// Site-specific environment variables set in netlify.toml
const getConfigFileEnv = function ({
config: {
build: { environment = {} },
},
}) {
return environment
}
// Some environment variables cannot be overridden by configuration
const cleanUserEnv = function (userEnv) {
return omit.default(userEnv, READONLY_ENV)
}
const READONLY_ENV = [
// Set in local builds
'BRANCH',
'CACHED_COMMIT_REF',
'COMMIT_REF',
'CONTEXT',
'HEAD',
'REPOSITORY_URL',
'URL',
// CI builds set NETLIFY=true while CLI and programmatic builds set
// NETLIFY_LOCAL=true
'NETLIFY',
'NETLIFY_LOCAL',
// Not set in local builds because there is no CI build/deploy, incoming hooks nor PR
'INCOMING_HOOK_BODY',
'INCOMING_HOOK_TITLE',
'INCOMING_HOOK_URL',
'NETLIFY_BUILD_BASE',
'NETLIFY_BUILD_LIFECYCLE_TRIAL',
'NETLIFY_IMAGES_CDN_DOMAIN',
'PULL_REQUEST',
'REVIEW_ID',
]