@akash-chowdhury-24/deployhub 1.0.14 → 1.0.16
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/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import archiver from 'archiver';
|
|
4
|
-
import axios from 'axios';
|
|
5
4
|
import { createLogger } from '../../../logger/index.js';
|
|
6
5
|
import {
|
|
7
6
|
runCli,
|
|
@@ -10,6 +9,21 @@ import {
|
|
|
10
9
|
checkUrlHealth,
|
|
11
10
|
} from './_shared.js';
|
|
12
11
|
|
|
12
|
+
const BLOCKING_AMPLIFY_JOB_STATUSES = new Set([
|
|
13
|
+
'CREATED',
|
|
14
|
+
'PENDING',
|
|
15
|
+
'PROVISIONING',
|
|
16
|
+
'RUNNING',
|
|
17
|
+
'CANCELLING',
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {number} ms
|
|
22
|
+
*/
|
|
23
|
+
function sleep(ms) {
|
|
24
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
25
|
+
}
|
|
26
|
+
|
|
13
27
|
/**
|
|
14
28
|
* @param {string} sourceDir
|
|
15
29
|
* @param {string} zipPath
|
|
@@ -34,11 +48,18 @@ async function createRootZip(sourceDir, zipPath) {
|
|
|
34
48
|
* @param {string} uploadUrl
|
|
35
49
|
*/
|
|
36
50
|
async function uploadZipToAmplify(zipPath, uploadUrl) {
|
|
37
|
-
await
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
const body = await fs.readFile(zipPath);
|
|
52
|
+
const response = await fetch(uploadUrl, {
|
|
53
|
+
method: 'PUT',
|
|
54
|
+
body,
|
|
41
55
|
});
|
|
56
|
+
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
const detail = await response.text().catch(() => '');
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Amplify zip upload failed: HTTP ${response.status}${detail ? ` — ${detail}` : ''}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
42
63
|
}
|
|
43
64
|
|
|
44
65
|
/**
|
|
@@ -103,6 +124,102 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
103
124
|
log.success(`Amplify branch "${branch}" ready`);
|
|
104
125
|
}
|
|
105
126
|
|
|
127
|
+
/**
|
|
128
|
+
* @param {Record<string, string>} awsEnv
|
|
129
|
+
* @returns {Promise<{ jobId?: string, status?: string }[]>}
|
|
130
|
+
*/
|
|
131
|
+
async function listBranchJobs(awsEnv) {
|
|
132
|
+
const result = await runCli(
|
|
133
|
+
`aws amplify list-jobs --app-id ${appId} --branch-name ${branch} --max-items 10 --output json`,
|
|
134
|
+
process.cwd(),
|
|
135
|
+
awsEnv
|
|
136
|
+
);
|
|
137
|
+
if (result.exitCode !== 0) return [];
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const data = JSON.parse(result.stdout);
|
|
141
|
+
return data.jobSummaries || [];
|
|
142
|
+
} catch {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Cancel stuck jobs left by failed uploads so create-deployment can proceed.
|
|
149
|
+
* @param {Record<string, string>} awsEnv
|
|
150
|
+
*/
|
|
151
|
+
async function clearBlockingAmplifyJobs(awsEnv) {
|
|
152
|
+
const jobs = await listBranchJobs(awsEnv);
|
|
153
|
+
const blocking = jobs.filter((job) =>
|
|
154
|
+
BLOCKING_AMPLIFY_JOB_STATUSES.has(job.status || '')
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (blocking.length === 0) return;
|
|
158
|
+
|
|
159
|
+
for (const job of blocking) {
|
|
160
|
+
log.info(`Stopping in-progress Amplify job ${job.jobId} (${job.status})...`);
|
|
161
|
+
const stopResult = await runCli(
|
|
162
|
+
`aws amplify stop-job --app-id ${appId} --branch-name ${branch} --job-id ${job.jobId}`,
|
|
163
|
+
process.cwd(),
|
|
164
|
+
awsEnv
|
|
165
|
+
);
|
|
166
|
+
if (stopResult.exitCode !== 0) {
|
|
167
|
+
log.warn(
|
|
168
|
+
`Could not stop Amplify job ${job.jobId}: ${stopResult.stderr || stopResult.stdout}`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
174
|
+
await sleep(5000);
|
|
175
|
+
const current = await listBranchJobs(awsEnv);
|
|
176
|
+
const stillBlocking = current.filter((job) =>
|
|
177
|
+
BLOCKING_AMPLIFY_JOB_STATUSES.has(job.status || '')
|
|
178
|
+
);
|
|
179
|
+
if (stillBlocking.length === 0) {
|
|
180
|
+
log.info('Amplify branch is ready for a new deployment');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
throw new Error(
|
|
186
|
+
'Timed out waiting for in-progress Amplify jobs to finish. Stop them in the AWS console and retry.'
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @param {Record<string, string>} awsEnv
|
|
192
|
+
* @returns {Promise<Record<string, unknown>>}
|
|
193
|
+
*/
|
|
194
|
+
async function createManualDeployment(awsEnv) {
|
|
195
|
+
await clearBlockingAmplifyJobs(awsEnv);
|
|
196
|
+
|
|
197
|
+
const createResult = await runCli(
|
|
198
|
+
`aws amplify create-deployment --app-id ${appId} --branch-name ${branch} --output json`,
|
|
199
|
+
process.cwd(),
|
|
200
|
+
awsEnv
|
|
201
|
+
);
|
|
202
|
+
if (createResult.exitCode !== 0) {
|
|
203
|
+
const errorText = `${createResult.stderr || ''}${createResult.stdout || ''}`;
|
|
204
|
+
if (/was not finished/i.test(errorText)) {
|
|
205
|
+
log.warn('Amplify has a stuck deployment — clearing it and retrying...');
|
|
206
|
+
await clearBlockingAmplifyJobs(awsEnv);
|
|
207
|
+
const retryResult = await runCli(
|
|
208
|
+
`aws amplify create-deployment --app-id ${appId} --branch-name ${branch} --output json`,
|
|
209
|
+
process.cwd(),
|
|
210
|
+
awsEnv
|
|
211
|
+
);
|
|
212
|
+
if (retryResult.exitCode !== 0) {
|
|
213
|
+
throw new Error(`Amplify create-deployment failed: ${retryResult.stderr}`);
|
|
214
|
+
}
|
|
215
|
+
return JSON.parse(retryResult.stdout);
|
|
216
|
+
}
|
|
217
|
+
throw new Error(`Amplify create-deployment failed: ${createResult.stderr}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return JSON.parse(createResult.stdout);
|
|
221
|
+
}
|
|
222
|
+
|
|
106
223
|
async function deploy(artifactDir) {
|
|
107
224
|
if (!appId) throw new Error('AMPLIFY_APP_ID is required');
|
|
108
225
|
|
|
@@ -152,16 +269,7 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
152
269
|
const amplifyZipPath = path.join(artifactDir, 'amplify-deploy.zip');
|
|
153
270
|
await createRootZip(buildDir, amplifyZipPath);
|
|
154
271
|
|
|
155
|
-
const
|
|
156
|
-
`aws amplify create-deployment --app-id ${appId} --branch-name ${branch} --output json`,
|
|
157
|
-
process.cwd(),
|
|
158
|
-
awsEnv
|
|
159
|
-
);
|
|
160
|
-
if (createResult.exitCode !== 0) {
|
|
161
|
-
throw new Error(`Amplify create-deployment failed: ${createResult.stderr}`);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const deployment = JSON.parse(createResult.stdout);
|
|
272
|
+
const deployment = await createManualDeployment(awsEnv);
|
|
165
273
|
const jobId = deployment.jobId;
|
|
166
274
|
const zipUploadUrl = deployment.zipUploadUrl;
|
|
167
275
|
|