genbox 1.0.83 → 1.0.85
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/dist/commands/create.js +108 -35
- package/dist/commands/destroy.js +104 -110
- package/package.json +1 -1
package/dist/commands/create.js
CHANGED
|
@@ -728,7 +728,9 @@ function buildPayload(resolved, config, publicKey, privateKey, configLoader) {
|
|
|
728
728
|
const files = [];
|
|
729
729
|
// Track env files to move in setup script (staging approach to avoid blocking git clone)
|
|
730
730
|
const envFilesToMove = [];
|
|
731
|
-
// Send .env.genbox content to server for
|
|
731
|
+
// Send .env.genbox content to server for processing
|
|
732
|
+
// OPTIMIZATION: Instead of duplicating GLOBAL section for each app,
|
|
733
|
+
// send ONE .env.genbox file and let server extract app-specific content
|
|
732
734
|
const envGenboxPath = path.join(process.cwd(), '.env.genbox');
|
|
733
735
|
if (fs.existsSync(envGenboxPath)) {
|
|
734
736
|
const rawEnvContent = fs.readFileSync(envGenboxPath, 'utf-8');
|
|
@@ -751,42 +753,77 @@ function buildPayload(resolved, config, publicKey, privateKey, configLoader) {
|
|
|
751
753
|
if (connectTo && Object.keys(serviceUrlMap).length > 0) {
|
|
752
754
|
console.log(chalk_1.default.dim(` Using ${connectTo} URLs for variable expansion`));
|
|
753
755
|
}
|
|
754
|
-
//
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
756
|
+
// For projects with many apps, send ONE processed .env file to avoid duplicating GLOBAL
|
|
757
|
+
// This significantly reduces cloud-init size (Hetzner has 32KB limit)
|
|
758
|
+
if (resolved.apps.length > 3) {
|
|
759
|
+
// Send single .env.genbox with expansions applied, let server split into app files
|
|
760
|
+
let expandedEnvContent = rawEnvContent;
|
|
761
|
+
for (const [varName, value] of Object.entries(serviceUrlMap)) {
|
|
762
|
+
const pattern = new RegExp(`\\$\\{${varName}\\}`, 'g');
|
|
763
|
+
expandedEnvContent = expandedEnvContent.replace(pattern, value);
|
|
764
|
+
}
|
|
765
|
+
files.push({
|
|
766
|
+
path: '/home/dev/.env.genbox',
|
|
767
|
+
content: expandedEnvContent,
|
|
768
|
+
permissions: '0644',
|
|
769
|
+
});
|
|
770
|
+
// Track which apps need .env files (server will process)
|
|
771
|
+
for (const app of resolved.apps) {
|
|
772
|
+
const appPath = config.apps[app.name]?.path || app.name;
|
|
773
|
+
const repoPath = resolved.repos.find(r => r.name === app.name)?.path ||
|
|
774
|
+
(resolved.repos[0]?.path ? `${resolved.repos[0].path}/${appPath}` : `/home/dev/${config.project.name}/${appPath}`);
|
|
775
|
+
const servicesSections = Array.from(sections.keys()).filter(s => s.startsWith(`${app.name}/`));
|
|
776
|
+
if (servicesSections.length > 0) {
|
|
777
|
+
for (const serviceSectionName of servicesSections) {
|
|
778
|
+
const serviceName = serviceSectionName.split('/')[1];
|
|
779
|
+
envFilesToMove.push({
|
|
780
|
+
stagingName: serviceSectionName, // e.g., "api/gateway" - server will parse
|
|
781
|
+
targetPath: `${repoPath}/apps/${serviceName}/.env`,
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
else {
|
|
786
|
+
envFilesToMove.push({
|
|
787
|
+
stagingName: app.name,
|
|
788
|
+
targetPath: `${repoPath}/.env`,
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
// For small projects, use the original per-app approach (simpler)
|
|
795
|
+
for (const app of resolved.apps) {
|
|
796
|
+
const appPath = config.apps[app.name]?.path || app.name;
|
|
797
|
+
const repoPath = resolved.repos.find(r => r.name === app.name)?.path ||
|
|
798
|
+
(resolved.repos[0]?.path ? `${resolved.repos[0].path}/${appPath}` : `/home/dev/${config.project.name}/${appPath}`);
|
|
799
|
+
const servicesSections = Array.from(sections.keys()).filter(s => s.startsWith(`${app.name}/`));
|
|
800
|
+
if (servicesSections.length > 0) {
|
|
801
|
+
for (const serviceSectionName of servicesSections) {
|
|
802
|
+
const serviceName = serviceSectionName.split('/')[1];
|
|
803
|
+
const serviceEnvContent = (0, utils_1.buildAppEnvContent)(sections, serviceSectionName, serviceUrlMap);
|
|
804
|
+
const stagingName = `${app.name}-${serviceName}.env`;
|
|
805
|
+
const targetPath = `${repoPath}/apps/${serviceName}/.env`;
|
|
806
|
+
files.push({
|
|
807
|
+
path: `/home/dev/.env-staging/${stagingName}`,
|
|
808
|
+
content: serviceEnvContent,
|
|
809
|
+
permissions: '0644',
|
|
810
|
+
});
|
|
811
|
+
envFilesToMove.push({ stagingName, targetPath });
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
else {
|
|
815
|
+
const appEnvContent = (0, utils_1.buildAppEnvContent)(sections, app.name, serviceUrlMap);
|
|
769
816
|
files.push({
|
|
770
|
-
path: `/home/dev/.env-staging/${
|
|
771
|
-
content:
|
|
817
|
+
path: `/home/dev/.env-staging/${app.name}.env`,
|
|
818
|
+
content: appEnvContent,
|
|
772
819
|
permissions: '0644',
|
|
773
820
|
});
|
|
774
|
-
envFilesToMove.push({
|
|
821
|
+
envFilesToMove.push({
|
|
822
|
+
stagingName: `${app.name}.env`,
|
|
823
|
+
targetPath: `${repoPath}/.env`,
|
|
824
|
+
});
|
|
775
825
|
}
|
|
776
826
|
}
|
|
777
|
-
else {
|
|
778
|
-
// Regular app - build app-specific env content (GLOBAL + app section)
|
|
779
|
-
const appEnvContent = (0, utils_1.buildAppEnvContent)(sections, app.name, serviceUrlMap);
|
|
780
|
-
files.push({
|
|
781
|
-
path: `/home/dev/.env-staging/${app.name}.env`,
|
|
782
|
-
content: appEnvContent,
|
|
783
|
-
permissions: '0644',
|
|
784
|
-
});
|
|
785
|
-
envFilesToMove.push({
|
|
786
|
-
stagingName: `${app.name}.env`,
|
|
787
|
-
targetPath: `${repoPath}/.env`,
|
|
788
|
-
});
|
|
789
|
-
}
|
|
790
827
|
}
|
|
791
828
|
}
|
|
792
829
|
// Add setup script if generated
|
|
@@ -870,9 +907,45 @@ function generateSetupScript(resolved, config, envFilesToMove = []) {
|
|
|
870
907
|
'set -e',
|
|
871
908
|
'',
|
|
872
909
|
];
|
|
873
|
-
//
|
|
874
|
-
//
|
|
875
|
-
|
|
910
|
+
// Check if we're using the optimized single-file approach (for projects with many apps)
|
|
911
|
+
// or the legacy per-app staging approach
|
|
912
|
+
const useOptimizedEnv = resolved.apps.length > 3;
|
|
913
|
+
if (useOptimizedEnv && envFilesToMove.length > 0) {
|
|
914
|
+
// OPTIMIZED: Parse single .env.genbox and create app-specific .env files
|
|
915
|
+
lines.push('# Process .env.genbox and create app-specific .env files');
|
|
916
|
+
lines.push('if [ -f "/home/dev/.env.genbox" ]; then');
|
|
917
|
+
lines.push(' echo "Processing .env.genbox for app-specific .env files..."');
|
|
918
|
+
lines.push('');
|
|
919
|
+
lines.push(' # Function to extract section content');
|
|
920
|
+
lines.push(' extract_section() {');
|
|
921
|
+
lines.push(' local section="$1"');
|
|
922
|
+
lines.push(' local file="$2"');
|
|
923
|
+
lines.push(' awk -v section="$section" \'');
|
|
924
|
+
lines.push(' BEGIN { in_global=0; in_section=0; }');
|
|
925
|
+
lines.push(' /^# === GLOBAL ===/ { in_global=1; next }');
|
|
926
|
+
lines.push(' /^# === [^=]+ ===/ {');
|
|
927
|
+
lines.push(' in_global=0;');
|
|
928
|
+
lines.push(' if ($0 ~ "# === "section" ===") { in_section=1 }');
|
|
929
|
+
lines.push(' else { in_section=0 }');
|
|
930
|
+
lines.push(' next');
|
|
931
|
+
lines.push(' }');
|
|
932
|
+
lines.push(' in_global || in_section { print }');
|
|
933
|
+
lines.push(' \' "$file" | grep -v "^$" | head -n -1');
|
|
934
|
+
lines.push(' }');
|
|
935
|
+
lines.push('');
|
|
936
|
+
for (const { stagingName, targetPath } of envFilesToMove) {
|
|
937
|
+
lines.push(` # Create .env for ${stagingName}`);
|
|
938
|
+
lines.push(` mkdir -p "$(dirname "${targetPath}")"`);
|
|
939
|
+
lines.push(` extract_section "${stagingName}" /home/dev/.env.genbox > "${targetPath}"`);
|
|
940
|
+
lines.push(` echo " Created ${targetPath}"`);
|
|
941
|
+
}
|
|
942
|
+
lines.push('');
|
|
943
|
+
lines.push(' rm -f /home/dev/.env.genbox');
|
|
944
|
+
lines.push('fi');
|
|
945
|
+
lines.push('');
|
|
946
|
+
}
|
|
947
|
+
else if (envFilesToMove.length > 0) {
|
|
948
|
+
// LEGACY: Move pre-staged .env files
|
|
876
949
|
lines.push('# Move .env files from staging to app directories');
|
|
877
950
|
for (const { stagingName, targetPath } of envFilesToMove) {
|
|
878
951
|
lines.push(`if [ -f "/home/dev/.env-staging/${stagingName}" ]; then`);
|
package/dist/commands/destroy.js
CHANGED
|
@@ -170,132 +170,139 @@ async function handleBulkDelete(options) {
|
|
|
170
170
|
console.log(chalk_1.default.yellow(`Completed: ${successCount} destroyed, ${failCount} failed.`));
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Trigger save-work on genbox and display progress
|
|
175
|
+
* Returns the result with status and repo details
|
|
176
|
+
*/
|
|
177
|
+
async function triggerSaveWork(genbox) {
|
|
178
|
+
const spinner = (0, ora_1.default)('Saving uncommitted changes...').start();
|
|
179
|
+
spinner.text = 'Checking for uncommitted changes...';
|
|
180
|
+
try {
|
|
181
|
+
const result = await (0, api_1.fetchApi)(`/genboxes/${genbox._id}/save-work`, {
|
|
182
|
+
method: 'POST',
|
|
183
|
+
});
|
|
184
|
+
// Handle different statuses
|
|
185
|
+
switch (result.status) {
|
|
186
|
+
case 'no_changes':
|
|
187
|
+
spinner.succeed(chalk_1.default.dim('No uncommitted changes found'));
|
|
188
|
+
return result;
|
|
189
|
+
case 'success':
|
|
190
|
+
spinner.succeed(chalk_1.default.green('All changes saved successfully'));
|
|
191
|
+
break;
|
|
192
|
+
case 'partial':
|
|
193
|
+
spinner.warn(chalk_1.default.yellow('Some changes saved (partial success)'));
|
|
194
|
+
break;
|
|
195
|
+
case 'failed':
|
|
196
|
+
spinner.fail(chalk_1.default.red('Failed to save changes'));
|
|
197
|
+
if (result.error) {
|
|
198
|
+
console.log(chalk_1.default.dim(` Error: ${result.error}`));
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
case 'unreachable':
|
|
202
|
+
spinner.fail(chalk_1.default.red('Genbox is not reachable'));
|
|
203
|
+
if (result.error) {
|
|
204
|
+
console.log(chalk_1.default.dim(` ${result.error}`));
|
|
205
|
+
}
|
|
206
|
+
return result;
|
|
207
|
+
default:
|
|
208
|
+
spinner.info(chalk_1.default.dim(`Save work status: ${result.status}`));
|
|
209
|
+
}
|
|
210
|
+
// Display repo results
|
|
211
|
+
if (result.repos && result.repos.length > 0) {
|
|
212
|
+
console.log('');
|
|
213
|
+
for (const repo of result.repos) {
|
|
214
|
+
const repoName = repo.path.split('/').pop() || repo.path;
|
|
215
|
+
if (!repo.hadChanges) {
|
|
216
|
+
console.log(chalk_1.default.dim(` ${repoName}: No changes`));
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (repo.committed && repo.pushed) {
|
|
220
|
+
const statusIcon = repo.prCreated ? chalk_1.default.green('✓') : chalk_1.default.yellow('↑');
|
|
221
|
+
const branchInfo = chalk_1.default.cyan(repo.branch);
|
|
222
|
+
if (repo.prCreated && repo.prUrl) {
|
|
223
|
+
console.log(` ${statusIcon} ${repoName}: PR created → ${chalk_1.default.underline(repo.prUrl)}`);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
console.log(` ${statusIcon} ${repoName}: Pushed to ${branchInfo}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else if (repo.error) {
|
|
230
|
+
console.log(` ${chalk_1.default.red('✗')} ${repoName}: ${chalk_1.default.red(repo.error)}`);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
console.log(` ${chalk_1.default.red('✗')} ${repoName}: Failed to save`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
spinner.fail(chalk_1.default.red(`Failed to save work: ${error.message}`));
|
|
241
|
+
return { status: 'failed', error: error.message };
|
|
242
|
+
}
|
|
243
|
+
}
|
|
173
244
|
/**
|
|
174
245
|
* Check for uncommitted changes and handle them before destroy
|
|
175
246
|
*/
|
|
176
247
|
async function handleUncommittedChanges(genbox, options) {
|
|
177
|
-
// Skip if --yes flag is used (user explicitly wants to skip
|
|
248
|
+
// Skip if --yes flag is used without save-changes (user explicitly wants to skip)
|
|
178
249
|
if (options.yes && !options.saveChanges) {
|
|
179
250
|
return { proceed: true };
|
|
180
251
|
}
|
|
181
|
-
// If save-changes is
|
|
252
|
+
// If save-changes is set to 'trash' or 'skip', don't save
|
|
182
253
|
if (options.saveChanges === 'trash' || options.saveChanges === 'skip') {
|
|
183
|
-
return { proceed: true
|
|
254
|
+
return { proceed: true };
|
|
255
|
+
}
|
|
256
|
+
// If save-changes is set to 'save', auto-save without prompting
|
|
257
|
+
if (options.saveChanges === 'save') {
|
|
258
|
+
console.log('');
|
|
259
|
+
const result = await triggerSaveWork(genbox);
|
|
260
|
+
return { proceed: true, saveWorkResult: result };
|
|
184
261
|
}
|
|
185
|
-
//
|
|
262
|
+
// Interactive mode - ask user what to do
|
|
186
263
|
console.log('');
|
|
187
264
|
console.log(chalk_1.default.blue('Checking for uncommitted changes...'));
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
// There are uncommitted changes
|
|
203
|
-
const changeCount = gitStatus.split('\n').filter(line => line.trim()).length;
|
|
204
|
-
console.log(chalk_1.default.yellow(` Found ${changeCount} uncommitted change${changeCount === 1 ? '' : 's'}.`));
|
|
265
|
+
// First, do a quick check via save-work to see if there are changes
|
|
266
|
+
// The save-work endpoint will return 'no_changes' if nothing to save
|
|
267
|
+
const result = await triggerSaveWork(genbox);
|
|
268
|
+
// If no changes or unreachable, just proceed
|
|
269
|
+
if (result.status === 'no_changes' || result.status === 'unreachable') {
|
|
270
|
+
return { proceed: true, saveWorkResult: result };
|
|
271
|
+
}
|
|
272
|
+
// If save was successful or partial, we're done
|
|
273
|
+
if (result.status === 'success' || result.status === 'partial') {
|
|
274
|
+
return { proceed: true, saveWorkResult: result };
|
|
275
|
+
}
|
|
276
|
+
// If failed, ask user if they want to continue
|
|
277
|
+
if (result.status === 'failed') {
|
|
205
278
|
console.log('');
|
|
206
|
-
// If save-changes is set to 'pr', auto-select that option
|
|
207
|
-
if (options.saveChanges === 'pr') {
|
|
208
|
-
return { proceed: true, action: 'pr' };
|
|
209
|
-
}
|
|
210
|
-
// Prompt user for action
|
|
211
279
|
const action = await (0, select_1.default)({
|
|
212
|
-
message: 'What would you like to do
|
|
280
|
+
message: 'Save work failed. What would you like to do?',
|
|
213
281
|
choices: [
|
|
214
282
|
{
|
|
215
|
-
name: '
|
|
216
|
-
value: '
|
|
217
|
-
description: 'Creates a PR with your changes before destroying',
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
name: 'Trash changes',
|
|
221
|
-
value: 'trash',
|
|
222
|
-
description: 'Discard all uncommitted changes',
|
|
283
|
+
name: 'Continue with destroy (changes will be lost)',
|
|
284
|
+
value: 'continue',
|
|
223
285
|
},
|
|
224
286
|
{
|
|
225
287
|
name: 'Cancel destroy',
|
|
226
288
|
value: 'cancel',
|
|
227
|
-
description: 'Keep the genbox running',
|
|
228
289
|
},
|
|
229
290
|
],
|
|
230
|
-
default: '
|
|
291
|
+
default: 'cancel',
|
|
231
292
|
});
|
|
232
293
|
if (action === 'cancel') {
|
|
233
|
-
return { proceed: false };
|
|
234
|
-
}
|
|
235
|
-
return { proceed: true, action };
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
// If we can't check (e.g., genbox is not running), just proceed
|
|
239
|
-
console.log(chalk_1.default.dim(' Could not check for changes (genbox may not be accessible).'));
|
|
240
|
-
return { proceed: true, action: 'skip' };
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Commit, push and create PR for changes
|
|
245
|
-
*/
|
|
246
|
-
async function createPRForChanges(genbox) {
|
|
247
|
-
const spinner = (0, ora_1.default)('Creating PR for uncommitted changes...').start();
|
|
248
|
-
try {
|
|
249
|
-
// Execute git commands on the genbox to commit, push, and create PR
|
|
250
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
251
|
-
const branchName = `genbox-save/${genbox.name}-${timestamp}`;
|
|
252
|
-
const commands = [
|
|
253
|
-
// Ensure we're in the project directory
|
|
254
|
-
'cd /home/dev/*',
|
|
255
|
-
// Create a new branch for the changes
|
|
256
|
-
`git checkout -b "${branchName}"`,
|
|
257
|
-
// Stage all changes
|
|
258
|
-
'git add -A',
|
|
259
|
-
// Commit with a descriptive message
|
|
260
|
-
`git commit -m "Save changes from genbox '${genbox.name}' before destroy"`,
|
|
261
|
-
// Push to origin
|
|
262
|
-
`git push -u origin "${branchName}"`,
|
|
263
|
-
// Try to create PR using gh CLI if available
|
|
264
|
-
`gh pr create --title "Changes from genbox '${genbox.name}'" --body "Auto-saved changes before genbox destroy" 2>/dev/null || echo "PR_SKIP"`,
|
|
265
|
-
].join(' && ');
|
|
266
|
-
const result = await (0, api_1.fetchApi)(`/genboxes/${genbox._id}/exec`, {
|
|
267
|
-
method: 'POST',
|
|
268
|
-
body: JSON.stringify({
|
|
269
|
-
command: commands,
|
|
270
|
-
timeout: 60000,
|
|
271
|
-
}),
|
|
272
|
-
});
|
|
273
|
-
if (result?.exitCode !== 0 && !result?.stdout?.includes('PR_SKIP')) {
|
|
274
|
-
spinner.fail(chalk_1.default.red('Failed to save changes'));
|
|
275
|
-
console.log(chalk_1.default.dim(` Error: ${result?.stderr || 'Unknown error'}`));
|
|
276
|
-
return false;
|
|
277
|
-
}
|
|
278
|
-
if (result?.stdout?.includes('PR_SKIP')) {
|
|
279
|
-
spinner.succeed(chalk_1.default.green(`Changes pushed to branch '${branchName}'`));
|
|
280
|
-
console.log(chalk_1.default.dim(' Note: Could not create PR automatically. Create it manually on GitHub.'));
|
|
281
|
-
}
|
|
282
|
-
else {
|
|
283
|
-
spinner.succeed(chalk_1.default.green('PR created successfully'));
|
|
294
|
+
return { proceed: false, saveWorkResult: result };
|
|
284
295
|
}
|
|
285
|
-
return true;
|
|
286
|
-
}
|
|
287
|
-
catch (error) {
|
|
288
|
-
spinner.fail(chalk_1.default.red(`Failed to save changes: ${error.message}`));
|
|
289
|
-
return false;
|
|
290
296
|
}
|
|
297
|
+
return { proceed: true, saveWorkResult: result };
|
|
291
298
|
}
|
|
292
299
|
exports.destroyCommand = new commander_1.Command('destroy')
|
|
293
300
|
.alias('delete')
|
|
294
301
|
.description('Destroy one or more Genboxes')
|
|
295
302
|
.argument('[name]', 'Name of the Genbox to destroy (optional - will prompt if not provided)')
|
|
296
|
-
.option('-y, --yes', 'Skip confirmation')
|
|
303
|
+
.option('-y, --yes', 'Skip confirmation and save-work prompts')
|
|
297
304
|
.option('-a, --all', 'Bulk delete mode - select multiple genboxes to destroy')
|
|
298
|
-
.option('--save-changes <action>', 'Handle uncommitted changes:
|
|
305
|
+
.option('--save-changes <action>', 'Handle uncommitted changes: save (commit/push/PR), trash (discard), skip (ignore)')
|
|
299
306
|
.action(async (name, options) => {
|
|
300
307
|
try {
|
|
301
308
|
// Bulk delete mode when --all is used without a specific name
|
|
@@ -317,27 +324,14 @@ exports.destroyCommand = new commander_1.Command('destroy')
|
|
|
317
324
|
}
|
|
318
325
|
// Check for uncommitted changes if genbox is running
|
|
319
326
|
if (target.status === 'running') {
|
|
320
|
-
const { proceed
|
|
327
|
+
const { proceed } = await handleUncommittedChanges(target, options);
|
|
321
328
|
if (!proceed) {
|
|
322
329
|
console.log(chalk_1.default.dim('Destroy cancelled.'));
|
|
323
330
|
return;
|
|
324
331
|
}
|
|
325
|
-
// Handle the action
|
|
326
|
-
if (action === 'pr') {
|
|
327
|
-
const success = await createPRForChanges(target);
|
|
328
|
-
if (!success) {
|
|
329
|
-
const continueAnyway = await (0, confirm_1.default)({
|
|
330
|
-
message: 'Failed to save changes. Continue with destroy anyway?',
|
|
331
|
-
default: false,
|
|
332
|
-
});
|
|
333
|
-
if (!continueAnyway) {
|
|
334
|
-
console.log(chalk_1.default.dim('Destroy cancelled.'));
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
332
|
}
|
|
340
333
|
// Confirm
|
|
334
|
+
console.log('');
|
|
341
335
|
let confirmed = options.yes;
|
|
342
336
|
if (!confirmed) {
|
|
343
337
|
confirmed = await (0, confirm_1.default)({
|