@akash-chowdhury-24/deployhub 1.0.12 → 1.0.13
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
package/src/core/config.js
CHANGED
|
@@ -21,6 +21,7 @@ const EnvironmentSchema = z.object({
|
|
|
21
21
|
accountId: z.string().optional(),
|
|
22
22
|
appId: z.string().optional(),
|
|
23
23
|
region: z.string().optional(),
|
|
24
|
+
branch: z.string().optional(),
|
|
24
25
|
githubConnected: z.boolean().optional(),
|
|
25
26
|
resourceName: z.string().optional(),
|
|
26
27
|
projectId: z.string().optional(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs-extra';
|
|
3
|
+
import archiver from 'archiver';
|
|
3
4
|
import { execa } from 'execa';
|
|
4
5
|
import { createLogger } from '../../../logger/index.js';
|
|
5
6
|
import {
|
|
@@ -9,6 +10,25 @@ import {
|
|
|
9
10
|
checkUrlHealth,
|
|
10
11
|
} from './_shared.js';
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} sourceDir
|
|
15
|
+
* @param {string} zipPath
|
|
16
|
+
*/
|
|
17
|
+
async function createRootZip(sourceDir, zipPath) {
|
|
18
|
+
await fs.ensureDir(path.dirname(zipPath));
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
const output = fs.createWriteStream(zipPath);
|
|
21
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
22
|
+
|
|
23
|
+
output.on('close', resolve);
|
|
24
|
+
archive.on('error', reject);
|
|
25
|
+
|
|
26
|
+
archive.pipe(output);
|
|
27
|
+
archive.directory(sourceDir, false);
|
|
28
|
+
archive.finalize();
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
12
32
|
/**
|
|
13
33
|
* @param {import('../../../core/config.js').DeployHubConfig} config
|
|
14
34
|
* @param {string} envName
|
|
@@ -19,21 +39,68 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
19
39
|
const log = createLogger('aws-amplify');
|
|
20
40
|
const appId = environment?.appId || env.AMPLIFY_APP_ID;
|
|
21
41
|
const region = environment?.region || env.AWS_REGION || 'us-east-1';
|
|
42
|
+
const branch = environment?.branch || env.AMPLIFY_BRANCH || 'main';
|
|
22
43
|
const githubConnected = environment?.githubConnected ?? false;
|
|
23
44
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const awsEnv = {
|
|
45
|
+
function getAwsEnv() {
|
|
46
|
+
return {
|
|
28
47
|
AWS_ACCESS_KEY_ID: env.AWS_ACCESS_KEY_ID || '',
|
|
29
48
|
AWS_SECRET_ACCESS_KEY: env.AWS_SECRET_ACCESS_KEY || '',
|
|
30
49
|
AWS_DEFAULT_REGION: region,
|
|
31
50
|
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {string} stage
|
|
55
|
+
*/
|
|
56
|
+
function resolveAmplifyStage(stage) {
|
|
57
|
+
const normalized = stage.toLowerCase();
|
|
58
|
+
if (normalized === 'production') return 'PRODUCTION';
|
|
59
|
+
if (normalized === 'staging') return 'BETA';
|
|
60
|
+
return 'DEVELOPMENT';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function branchExists(awsEnv) {
|
|
64
|
+
const result = await runCli(
|
|
65
|
+
`aws amplify get-branch --app-id ${appId} --branch-name ${branch}`,
|
|
66
|
+
process.cwd(),
|
|
67
|
+
awsEnv
|
|
68
|
+
);
|
|
69
|
+
return result.exitCode === 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function ensureBranchExists(awsEnv) {
|
|
73
|
+
if (await branchExists(awsEnv)) return;
|
|
74
|
+
|
|
75
|
+
if (githubConnected) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Amplify branch "${branch}" not found. Connect your GitHub repo in the Amplify console or choose a branch that already exists.`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const stage = resolveAmplifyStage(envName);
|
|
82
|
+
log.info(`Creating Amplify branch "${branch}" for manual zip deploys...`);
|
|
83
|
+
const createResult = await runCli(
|
|
84
|
+
`aws amplify create-branch --app-id ${appId} --branch-name ${branch} --stage ${stage} --no-enable-auto-build --description "Created by DeployHub for manual deployments"`,
|
|
85
|
+
process.cwd(),
|
|
86
|
+
awsEnv
|
|
87
|
+
);
|
|
88
|
+
if (createResult.exitCode !== 0) {
|
|
89
|
+
throw new Error(`Amplify create-branch failed: ${createResult.stderr || createResult.stdout}`);
|
|
90
|
+
}
|
|
91
|
+
log.success(`Amplify branch "${branch}" ready`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function deploy(artifactDir) {
|
|
95
|
+
if (!appId) throw new Error('AMPLIFY_APP_ID is required');
|
|
96
|
+
|
|
97
|
+
const awsEnv = getAwsEnv();
|
|
32
98
|
|
|
33
99
|
if (githubConnected) {
|
|
34
|
-
|
|
100
|
+
await ensureBranchExists(awsEnv);
|
|
101
|
+
log.info(`Triggering Amplify release job on branch ${branch} (GitHub connected)...`);
|
|
35
102
|
const result = await runCli(
|
|
36
|
-
`aws amplify start-job --app-id ${appId} --branch-name
|
|
103
|
+
`aws amplify start-job --app-id ${appId} --branch-name ${branch} --job-type RELEASE`,
|
|
37
104
|
process.cwd(),
|
|
38
105
|
awsEnv
|
|
39
106
|
);
|
|
@@ -50,6 +117,7 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
50
117
|
platform: 'aws-amplify',
|
|
51
118
|
deploymentId: jobId,
|
|
52
119
|
appId,
|
|
120
|
+
branch,
|
|
53
121
|
method: 'github',
|
|
54
122
|
},
|
|
55
123
|
envName
|
|
@@ -58,14 +126,22 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
58
126
|
return;
|
|
59
127
|
}
|
|
60
128
|
|
|
61
|
-
log.info(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
129
|
+
log.info(`Uploading build output to Amplify branch ${branch}...`);
|
|
130
|
+
await ensureBranchExists(awsEnv);
|
|
131
|
+
|
|
132
|
+
const buildOutput = config.frontend?.buildOutput || config.buildOutput || 'dist';
|
|
133
|
+
const buildDir = path.join(process.cwd(), buildOutput);
|
|
134
|
+
if (!(await fs.pathExists(buildDir))) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`Build output not found at ${buildOutput}. Amplify needs the built static files, not artifact.zip with a nested folder.`
|
|
137
|
+
);
|
|
65
138
|
}
|
|
66
139
|
|
|
140
|
+
const amplifyZipPath = path.join(artifactDir, 'amplify-deploy.zip');
|
|
141
|
+
await createRootZip(buildDir, amplifyZipPath);
|
|
142
|
+
|
|
67
143
|
const createResult = await runCli(
|
|
68
|
-
`aws amplify create-deployment --app-id ${appId} --branch-name
|
|
144
|
+
`aws amplify create-deployment --app-id ${appId} --branch-name ${branch} --output json`,
|
|
69
145
|
process.cwd(),
|
|
70
146
|
awsEnv
|
|
71
147
|
);
|
|
@@ -77,14 +153,14 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
77
153
|
const jobId = deployment.jobId;
|
|
78
154
|
const zipUploadUrl = deployment.zipUploadUrl;
|
|
79
155
|
|
|
80
|
-
await execa('curl', ['-T',
|
|
156
|
+
await execa('curl', ['-T', amplifyZipPath, zipUploadUrl], {
|
|
81
157
|
env: { ...process.env, ...awsEnv },
|
|
82
158
|
stdio: 'inherit',
|
|
83
159
|
shell: true,
|
|
84
160
|
});
|
|
85
161
|
|
|
86
162
|
const startResult = await runCli(
|
|
87
|
-
`aws amplify start-deployment --app-id ${appId} --branch-name
|
|
163
|
+
`aws amplify start-deployment --app-id ${appId} --branch-name ${branch} --job-id ${jobId}`,
|
|
88
164
|
process.cwd(),
|
|
89
165
|
awsEnv
|
|
90
166
|
);
|
|
@@ -92,12 +168,15 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
92
168
|
throw new Error(`Amplify start-deployment failed: ${startResult.stderr}`);
|
|
93
169
|
}
|
|
94
170
|
|
|
171
|
+
await fs.remove(amplifyZipPath);
|
|
172
|
+
|
|
95
173
|
await saveDeploymentRecord(
|
|
96
174
|
artifactDir,
|
|
97
175
|
{
|
|
98
176
|
platform: 'aws-amplify',
|
|
99
177
|
deploymentId: jobId,
|
|
100
178
|
appId,
|
|
179
|
+
branch,
|
|
101
180
|
method: 'zip',
|
|
102
181
|
},
|
|
103
182
|
envName
|
|
@@ -114,21 +193,18 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
114
193
|
throw new Error('No previous Amplify job ID found for rollback');
|
|
115
194
|
}
|
|
116
195
|
|
|
117
|
-
const awsEnv =
|
|
118
|
-
|
|
119
|
-
AWS_SECRET_ACCESS_KEY: env.AWS_SECRET_ACCESS_KEY || '',
|
|
120
|
-
AWS_DEFAULT_REGION: region,
|
|
121
|
-
};
|
|
196
|
+
const awsEnv = getAwsEnv();
|
|
197
|
+
const rollbackBranch = previous?.branch || branch;
|
|
122
198
|
|
|
123
|
-
log.info(`Re-triggering Amplify job ${jobId}...`);
|
|
199
|
+
log.info(`Re-triggering Amplify job ${jobId} on branch ${rollbackBranch}...`);
|
|
124
200
|
const result = await runCli(
|
|
125
|
-
`aws amplify start-job --app-id ${appId} --branch-name
|
|
201
|
+
`aws amplify start-job --app-id ${appId} --branch-name ${rollbackBranch} --job-id ${jobId} --job-type RETRY`,
|
|
126
202
|
process.cwd(),
|
|
127
203
|
awsEnv
|
|
128
204
|
);
|
|
129
205
|
if (result.exitCode !== 0) {
|
|
130
206
|
await runCli(
|
|
131
|
-
`aws amplify start-job --app-id ${appId} --branch-name
|
|
207
|
+
`aws amplify start-job --app-id ${appId} --branch-name ${rollbackBranch} --job-type RELEASE`,
|
|
132
208
|
process.cwd(),
|
|
133
209
|
awsEnv
|
|
134
210
|
);
|
|
@@ -144,18 +220,28 @@ export function createAwsAmplifyProvider(config, envName, env = process.env) {
|
|
|
144
220
|
|
|
145
221
|
async function testConnection() {
|
|
146
222
|
if (!appId) throw new Error('AMPLIFY_APP_ID is required');
|
|
147
|
-
|
|
223
|
+
|
|
224
|
+
const awsEnv = getAwsEnv();
|
|
225
|
+
const appResult = await runCli(
|
|
148
226
|
`aws amplify get-app --app-id ${appId}`,
|
|
149
227
|
process.cwd(),
|
|
150
|
-
|
|
151
|
-
AWS_ACCESS_KEY_ID: env.AWS_ACCESS_KEY_ID || '',
|
|
152
|
-
AWS_SECRET_ACCESS_KEY: env.AWS_SECRET_ACCESS_KEY || '',
|
|
153
|
-
AWS_DEFAULT_REGION: region,
|
|
154
|
-
}
|
|
228
|
+
awsEnv
|
|
155
229
|
);
|
|
156
|
-
if (
|
|
230
|
+
if (appResult.exitCode !== 0) {
|
|
157
231
|
throw new Error('Could not find Amplify app — check AMPLIFY_APP_ID and AWS credentials');
|
|
158
232
|
}
|
|
233
|
+
|
|
234
|
+
if (await branchExists(awsEnv)) return;
|
|
235
|
+
|
|
236
|
+
if (githubConnected) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
`Amplify branch "${branch}" not found. Connect your GitHub repo in the Amplify console or choose a branch that already exists.`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
log.info(
|
|
243
|
+
`Amplify branch "${branch}" will be created automatically on the first deploy`
|
|
244
|
+
);
|
|
159
245
|
}
|
|
160
246
|
|
|
161
247
|
return { deploy, rollback, healthCheck, testConnection };
|
|
@@ -104,6 +104,12 @@ export async function promptPlatformQuestions(
|
|
|
104
104
|
message: 'AWS region:',
|
|
105
105
|
default: 'us-east-1',
|
|
106
106
|
},
|
|
107
|
+
{
|
|
108
|
+
type: 'input',
|
|
109
|
+
name: 'branch',
|
|
110
|
+
message: 'Amplify branch name (auto-created for manual zip deploys):',
|
|
111
|
+
default: 'main',
|
|
112
|
+
},
|
|
107
113
|
{
|
|
108
114
|
type: 'confirm',
|
|
109
115
|
name: 'githubConnected',
|
|
@@ -113,6 +119,7 @@ export async function promptPlatformQuestions(
|
|
|
113
119
|
]);
|
|
114
120
|
config.appId = answers.appId;
|
|
115
121
|
config.region = answers.region;
|
|
122
|
+
config.branch = answers.branch;
|
|
116
123
|
config.githubConnected = answers.githubConnected;
|
|
117
124
|
break;
|
|
118
125
|
}
|