@akash-chowdhury-24/deployhub 1.0.14 → 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,6 +1,6 @@
1
1
  {
2
2
  "name": "@akash-chowdhury-24/deployhub",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "description": "Zero-configuration deployment and artifact manager",
5
5
  "type": "module",
6
6
  "main": "./src/cli/index.js",
@@ -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
@@ -103,6 +118,102 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
103
118
  log.success(`Amplify branch "${branch}" ready`);
104
119
  }
105
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
+
106
217
  async function deploy(artifactDir) {
107
218
  if (!appId) throw new Error('AMPLIFY_APP_ID is required');
108
219
 
@@ -152,16 +263,7 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
152
263
  const amplifyZipPath = path.join(artifactDir, 'amplify-deploy.zip');
153
264
  await createRootZip(buildDir, amplifyZipPath);
154
265
 
155
- const createResult = await runCli(
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);
266
+ const deployment = await createManualDeployment(awsEnv);
165
267
  const jobId = deployment.jobId;
166
268
  const zipUploadUrl = deployment.zipUploadUrl;
167
269