-
Notifications
You must be signed in to change notification settings - Fork 465
Expand file tree
/
Copy pathdeploy-site.ts
More file actions
244 lines (217 loc) · 8.54 KB
/
Copy pathdeploy-site.ts
File metadata and controls
244 lines (217 loc) · 8.54 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
234
235
236
237
238
239
240
241
242
243
244
import { rm } from 'fs/promises'
import { getVersion as getNetlifyBuildVersion } from '@netlify/build'
import cleanDeep from 'clean-deep'
import BaseCommand from '../../commands/base-command.js'
import { type $TSFixMe } from '../../commands/types.js'
import { warn } from '../command-helpers.js'
import {
DEFAULT_CONCURRENT_HASH,
DEFAULT_CONCURRENT_UPLOAD,
DEFAULT_DEPLOY_TIMEOUT,
DEFAULT_MAX_RETRY,
DEFAULT_SYNC_LIMIT,
} from './constants.js'
import { hashConfig } from './hash-config.js'
import hashEdgeFunctions from './hash-edge-functions.js'
import hashFiles from './hash-files.js'
import hashFns from './hash-fns.js'
import {
deployFileNormalizer,
getDbMigrationsDistPathIfExists,
getDeployConfigPathIfExists,
getEdgeFunctionsDistPathIfExists,
isEdgeFunctionFile,
} from './process-files.js'
import uploadFiles from './upload-files.js'
import { getUploadList, waitForDeploy, waitForDiff } from './util.js'
import type { DeployEvent } from './status-cb.js'
import { temporaryDirectory } from '../temporary-file.js'
export type { DeployEvent }
const buildStatsString = (possibleParts: (string | false | undefined)[]) => {
const parts = possibleParts.filter(Boolean)
const message = parts.slice(0, -1).join(', ')
return parts.length > 1 ? `${message} and ${parts[parts.length - 1]}` : message
}
export const deploySite = async (
command: BaseCommand,
api: $TSFixMe,
// @ts-expect-error TS(7006) FIXME: Parameter 'siteId' implicitly has an 'any' type.
siteId,
// @ts-expect-error TS(7006) FIXME: Parameter 'dir' implicitly has an 'any' type.
dir,
{
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
assetType,
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
branch,
concurrentHash = DEFAULT_CONCURRENT_HASH,
concurrentUpload = DEFAULT_CONCURRENT_UPLOAD,
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
config,
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
deployId,
deployTimeout = DEFAULT_DEPLOY_TIMEOUT,
draft = false,
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
filter,
fnDir = [],
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
functionsConfig,
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
hashAlgorithm,
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
manifestPath,
maxRetry = DEFAULT_MAX_RETRY,
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
siteRoot,
// @ts-expect-error TS(2525) FIXME: Initializer provides no value for this binding ele... Remove this comment to see the full error message
skipFunctionsCache,
statusCb = () => {
/* default to noop */
},
syncFileLimit = DEFAULT_SYNC_LIMIT,
tmpDir = temporaryDirectory(),
workingDir,
}: {
concurrentHash?: number
concurrentUpload?: number
deployTimeout?: number
draft?: boolean
maxRetry?: number
statusCb?: (status: DeployEvent) => void
syncFileLimit?: number
tmpDir?: string
fnDir?: string[]
workingDir: string
},
) => {
statusCb({
type: 'hashing',
msg: `Hashing files...`,
phase: 'start',
})
const edgeFunctionsDistPath = await getEdgeFunctionsDistPathIfExists(workingDir)
const deployConfigPath = await getDeployConfigPathIfExists(workingDir)
const dbMigrationsDistPath = await getDbMigrationsDistPathIfExists(workingDir)
const [
{ files: staticFiles, filesShaMap: staticShaMap },
{ fnConfig, fnShaMap, functionSchedules, functions, functionsWithNativeModules },
configFile,
{ edgeFunctions, edgeFnShaMap },
] = await Promise.all([
hashFiles({
assetType,
concurrentHash,
directories: [dir, edgeFunctionsDistPath, deployConfigPath, dbMigrationsDistPath].filter(Boolean),
filter,
hashAlgorithm,
normalizer: deployFileNormalizer.bind(null, workingDir),
statusCb,
}),
hashFns(command, fnDir, {
functionsConfig,
tmpDir,
concurrentHash,
hashAlgorithm,
statusCb,
manifestPath,
skipFunctionsCache,
rootDir: siteRoot,
}),
hashConfig({ config }),
hashEdgeFunctions(edgeFunctionsDistPath, { hashAlgorithm, statusCb }),
])
const files = { ...staticFiles, [configFile.normalizedPath]: configFile.hash }
const filesShaMap = { ...staticShaMap, [configFile.hash]: [configFile] }
const edgeFunctionsCount = Object.keys(files).filter(isEdgeFunctionFile).length
const filesCount = Object.keys(files).length - edgeFunctionsCount
const functionsCount = Object.keys(functions).length
const stats = buildStatsString([
filesCount > 0 && `${filesCount} files`,
functionsCount > 0 && `${functionsCount} functions`,
edgeFunctionsCount > 0 && 'edge functions',
])
statusCb({
type: 'hashing',
msg: `Finished hashing ${stats}`,
phase: 'stop',
})
if (filesCount === 0 && functionsCount === 0) {
throw new Error('No files or functions to deploy')
}
if (functionsWithNativeModules.length !== 0) {
const functionsWithNativeModulesMessage = functionsWithNativeModules
.map(({ name }: { name: string }) => `- ${name}`)
.join('\n')
warn(`Modules with native dependencies\n
${functionsWithNativeModulesMessage}
The serverless functions above use Node.js modules with native dependencies, which
must be installed on a system with the same architecture as the function runtime. A
mismatch in the system and runtime may lead to errors when invoking your functions.
To ensure your functions work as expected, we recommend using continuous deployment
instead of manual deployment.
For more information, visit https://ntl.fyi/cli-native-modules.`)
}
statusCb({
type: 'create-deploy',
msg: 'CDN diffing files...',
phase: 'start',
})
const packageFrameworks = command.project.frameworks.get(command.workspacePackage ?? '')
const primaryFramework = packageFrameworks?.[0]
// @ts-expect-error TS(2349) This expression is not callable
const deployParams = cleanDeep({
siteId,
deploy_id: deployId,
body: {
files,
functions,
edge_functions: edgeFunctions,
function_schedules: functionSchedules,
functions_config: fnConfig,
async: Object.keys(files).length > syncFileLimit,
branch,
draft,
framework: primaryFramework?.id ?? 'unknown',
framework_version: primaryFramework?.detected.package?.version?.toString() ?? 'unknown',
build_version: getNetlifyBuildVersion(),
},
})
let deploy = await api.updateSiteDeploy(deployParams)
if (deployParams.body.async) deploy = await waitForDiff(api, deploy.id, siteId, deployTimeout)
const {
required: requiredFiles,
required_functions: requiredFns,
required_edge_functions: requiredEdgeFns,
} = deploy
statusCb({
type: 'create-deploy',
msg: `CDN requesting ${requiredFiles.length} files${
Array.isArray(requiredFns) ? ` and ${requiredFns.length} functions` : ''
}${Array.isArray(requiredEdgeFns) ? ` and ${requiredEdgeFns.length} edge functions` : ''}`,
phase: 'stop',
})
const filesUploadList = getUploadList(requiredFiles, filesShaMap)
const functionsUploadList = getUploadList(requiredFns, fnShaMap)
const edgeFunctionsUploadList = getUploadList(requiredEdgeFns, edgeFnShaMap)
const uploadList = [...filesUploadList, ...functionsUploadList, ...edgeFunctionsUploadList]
await uploadFiles(api, deployId, uploadList, { concurrentUpload, statusCb, maxRetry })
statusCb({
type: 'wait-for-deploy',
msg: 'Waiting for deploy to go live...',
phase: 'start',
})
deploy = await waitForDeploy(api, deployId, siteId, deployTimeout)
statusCb({
type: 'wait-for-deploy',
msg: draft ? 'Draft deploy is live!' : 'Deploy is live!',
phase: 'stop',
})
await rm(tmpDir, { force: true, recursive: true })
const deployManifest = {
deployId,
deploy,
uploadList,
}
return deployManifest
}