@akash-chowdhury-24/deployhub 1.0.13 → 1.0.15
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,7 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
3
|
import archiver from 'archiver';
|
|
4
|
-
import
|
|
4
|
+
import axios from 'axios';
|
|
5
5
|
import { createLogger } from '../../../logger/index.js';
|
|
6
6
|
import {
|
|
7
7
|
runCli,
|
|
@@ -10,6 +10,21 @@ import {
|
|
|
10
10
|
checkUrlHealth,
|
|
11
11
|
} from './_shared.js';
|
|
12
12
|
|
|
13
|
+
const BLOCKING_AMPLIFY_JOB_STATUSES = new Set([
|
|
14
|
+
'CREATED',
|
|
15
|
+
'PENDING',
|
|
16
|
+
'PROVISIONING',
|
|
17
|
+
'RUNNING',
|
|
18
|
+
'CANCELLING',
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {number} ms
|
|
23
|
+
*/
|
|
24
|
+
function sleep(ms) {
|
|
25
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
26
|
+
}
|
|
27
|
+
|
|
13
28
|
/**
|
|
14
29
|
* @param {string} sourceDir
|
|
15
30
|
* @param {string} zipPath
|
|
@@ -29,6 +44,18 @@ async function createRootZip(sourceDir, zipPath) {
|
|
|
29
44
|
});
|
|
30
45
|
}
|
|
31
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @param {string} zipPath
|
|
49
|
+
* @param {string} uploadUrl
|
|
50
|
+
*/
|
|
51
|
+
async function uploadZipToAmplify(zipPath, uploadUrl) {
|
|
52
|
+
await axios.put(uploadUrl, fs.createReadStream(zipPath), {
|
|
53
|
+
headers: { 'Content-Type': 'application/zip' },
|
|
54
|
+
maxBodyLength: Infinity,
|
|
55
|
+
maxContentLength: Infinity,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
32
59
|
/**
|
|
33
60
|
* @param {import('../../../core/config.js').DeployHubConfig} config
|
|
34
61
|
* @param {string} envName
|
|
@@ -91,6 +118,102 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
91
118
|
log.success(`Amplify branch "${branch}" ready`);
|
|
92
119
|
}
|
|
93
120
|
|
|
121
|
+
/**
|
|
122
|
+
* @param {Record<string, string>} awsEnv
|
|
123
|
+
* @returns {Promise<{ jobId?: string, status?: string }[]>}
|
|
124
|
+
*/
|
|
125
|
+
async function listBranchJobs(awsEnv) {
|
|
126
|
+
const result = await runCli(
|
|
127
|
+
`aws amplify list-jobs --app-id ${appId} --branch-name ${branch} --max-items 10 --output json`,
|
|
128
|
+
process.cwd(),
|
|
129
|
+
awsEnv
|
|
130
|
+
);
|
|
131
|
+
if (result.exitCode !== 0) return [];
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const data = JSON.parse(result.stdout);
|
|
135
|
+
return data.jobSummaries || [];
|
|
136
|
+
} catch {
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Cancel stuck jobs left by failed uploads so create-deployment can proceed.
|
|
143
|
+
* @param {Record<string, string>} awsEnv
|
|
144
|
+
*/
|
|
145
|
+
async function clearBlockingAmplifyJobs(awsEnv) {
|
|
146
|
+
const jobs = await listBranchJobs(awsEnv);
|
|
147
|
+
const blocking = jobs.filter((job) =>
|
|
148
|
+
BLOCKING_AMPLIFY_JOB_STATUSES.has(job.status || '')
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
if (blocking.length === 0) return;
|
|
152
|
+
|
|
153
|
+
for (const job of blocking) {
|
|
154
|
+
log.info(`Stopping in-progress Amplify job ${job.jobId} (${job.status})...`);
|
|
155
|
+
const stopResult = await runCli(
|
|
156
|
+
`aws amplify stop-job --app-id ${appId} --branch-name ${branch} --job-id ${job.jobId}`,
|
|
157
|
+
process.cwd(),
|
|
158
|
+
awsEnv
|
|
159
|
+
);
|
|
160
|
+
if (stopResult.exitCode !== 0) {
|
|
161
|
+
log.warn(
|
|
162
|
+
`Could not stop Amplify job ${job.jobId}: ${stopResult.stderr || stopResult.stdout}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
168
|
+
await sleep(5000);
|
|
169
|
+
const current = await listBranchJobs(awsEnv);
|
|
170
|
+
const stillBlocking = current.filter((job) =>
|
|
171
|
+
BLOCKING_AMPLIFY_JOB_STATUSES.has(job.status || '')
|
|
172
|
+
);
|
|
173
|
+
if (stillBlocking.length === 0) {
|
|
174
|
+
log.info('Amplify branch is ready for a new deployment');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
throw new Error(
|
|
180
|
+
'Timed out waiting for in-progress Amplify jobs to finish. Stop them in the AWS console and retry.'
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @param {Record<string, string>} awsEnv
|
|
186
|
+
* @returns {Promise<Record<string, unknown>>}
|
|
187
|
+
*/
|
|
188
|
+
async function createManualDeployment(awsEnv) {
|
|
189
|
+
await clearBlockingAmplifyJobs(awsEnv);
|
|
190
|
+
|
|
191
|
+
const createResult = await runCli(
|
|
192
|
+
`aws amplify create-deployment --app-id ${appId} --branch-name ${branch} --output json`,
|
|
193
|
+
process.cwd(),
|
|
194
|
+
awsEnv
|
|
195
|
+
);
|
|
196
|
+
if (createResult.exitCode !== 0) {
|
|
197
|
+
const errorText = `${createResult.stderr || ''}${createResult.stdout || ''}`;
|
|
198
|
+
if (/was not finished/i.test(errorText)) {
|
|
199
|
+
log.warn('Amplify has a stuck deployment — clearing it and retrying...');
|
|
200
|
+
await clearBlockingAmplifyJobs(awsEnv);
|
|
201
|
+
const retryResult = await runCli(
|
|
202
|
+
`aws amplify create-deployment --app-id ${appId} --branch-name ${branch} --output json`,
|
|
203
|
+
process.cwd(),
|
|
204
|
+
awsEnv
|
|
205
|
+
);
|
|
206
|
+
if (retryResult.exitCode !== 0) {
|
|
207
|
+
throw new Error(`Amplify create-deployment failed: ${retryResult.stderr}`);
|
|
208
|
+
}
|
|
209
|
+
return JSON.parse(retryResult.stdout);
|
|
210
|
+
}
|
|
211
|
+
throw new Error(`Amplify create-deployment failed: ${createResult.stderr}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return JSON.parse(createResult.stdout);
|
|
215
|
+
}
|
|
216
|
+
|
|
94
217
|
async function deploy(artifactDir) {
|
|
95
218
|
if (!appId) throw new Error('AMPLIFY_APP_ID is required');
|
|
96
219
|
|
|
@@ -140,24 +263,12 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
140
263
|
const amplifyZipPath = path.join(artifactDir, 'amplify-deploy.zip');
|
|
141
264
|
await createRootZip(buildDir, amplifyZipPath);
|
|
142
265
|
|
|
143
|
-
const
|
|
144
|
-
`aws amplify create-deployment --app-id ${appId} --branch-name ${branch} --output json`,
|
|
145
|
-
process.cwd(),
|
|
146
|
-
awsEnv
|
|
147
|
-
);
|
|
148
|
-
if (createResult.exitCode !== 0) {
|
|
149
|
-
throw new Error(`Amplify create-deployment failed: ${createResult.stderr}`);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const deployment = JSON.parse(createResult.stdout);
|
|
266
|
+
const deployment = await createManualDeployment(awsEnv);
|
|
153
267
|
const jobId = deployment.jobId;
|
|
154
268
|
const zipUploadUrl = deployment.zipUploadUrl;
|
|
155
269
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
stdio: 'inherit',
|
|
159
|
-
shell: true,
|
|
160
|
-
});
|
|
270
|
+
log.info('Uploading zip to Amplify...');
|
|
271
|
+
await uploadZipToAmplify(amplifyZipPath, zipUploadUrl);
|
|
161
272
|
|
|
162
273
|
const startResult = await runCli(
|
|
163
274
|
`aws amplify start-deployment --app-id ${appId} --branch-name ${branch} --job-id ${jobId}`,
|