Skip to content

Commit de99c38

Browse files
committed
Add dev-env sync custom config option
1 parent dd94c13 commit de99c38

File tree

5 files changed

+652
-11
lines changed

5 files changed

+652
-11
lines changed

src/bin/vip-dev-env-sync-sql.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,11 @@ command( {
5959
undefined,
6060
processSlug
6161
)
62+
.option( 'experimental-config-file', 'The backup copy config file', undefined )
6263
.option( 'force', 'Skip validations.', undefined, processBooleanOption )
6364
.examples( examples )
6465
.argv( process.argv, async ( arg, opt ) => {
65-
const { app, env, ...optRest } = opt;
66+
const { app, env, experimentalConfigFile, ...optRest } = opt;
6667
const slug = await getEnvironmentName( optRest );
6768
const trackerFn = makeCommandTracker( 'dev_env_sync_sql', {
6869
app: app.id,
@@ -80,7 +81,14 @@ command( {
8081
throw new UserError( 'Environment needs to be started first' );
8182
}
8283

83-
const cmd = new DevEnvSyncSQLCommand( app, env, slug, lando, trackerFn );
84+
const cmd = new DevEnvSyncSQLCommand(
85+
app,
86+
env,
87+
slug,
88+
lando,
89+
trackerFn,
90+
experimentalConfigFile
91+
);
8492
// TODO: There's a function called handleCLIException for dev-env that handles exceptions but DevEnvSyncSQLCommand has its own implementation.
8593
// We should probably use handleCLIException instead?
8694
const didCommandRun = await cmd.run();

src/commands/dev-env-sync-sql.ts

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ import { BackupStorageAvailability } from '../lib/backup-storage-availability/ba
1515
import * as exit from '../lib/cli/exit';
1616
import { unzipFile } from '../lib/client-file-uploader';
1717
import { fixMyDumperTransform, getSqlDumpDetails, SqlDumpType } from '../lib/database';
18+
import {
19+
DBLiveCopyConfig,
20+
downloadFile,
21+
getDownloadURL,
22+
startLiveBackupCopy,
23+
} from '../lib/live-backup-copy';
1824
import { makeTempDir } from '../lib/utils';
1925
import { getReadInterface } from '../lib/validations/line-by-line';
2026

@@ -91,33 +97,31 @@ export class DevEnvSyncSQLCommand {
9197
public tmpDir: string;
9298
public siteUrls: string[] = [];
9399
public searchReplaceMap: Record< string, string > = {};
100+
public configFile?: string;
94101
public _track: TrackFunction;
95102
private _sqlDumpType?: SqlDumpType;
96103

97104
/**
98105
* Creates a new instance of the command
99-
*
100-
* @param app The app object
101-
* @param env The environment object
102-
* @param slug The site slug
103-
* @param lando The lando object
104-
* @param trackerFn Function to call for tracking
105106
*/
106107
constructor(
107108
public app: App,
108109
public env: AppEnvironment,
109110
public slug: string,
110111
public lando: Lando,
111-
trackerFn: TrackFunction = () => {}
112+
trackerFn: TrackFunction = () => {},
113+
configFile?: string
112114
) {
113115
this._track = trackerFn;
114116
this.tmpDir = makeTempDir();
117+
this.configFile = configFile;
115118
}
116119

117120
public track( name: string, eventProps: Record< string, unknown > ) {
118121
return this._track( name, {
119122
...eventProps,
120123
sqldump_type: this._sqlDumpType,
124+
live_backup_copy: Boolean( this.configFile ),
121125
} );
122126
}
123127

@@ -156,6 +160,12 @@ export class DevEnvSyncSQLCommand {
156160
* the latest backup
157161
*/
158162
public async generateExport(): Promise< void > {
163+
if ( this.configFile ) {
164+
await this.generateLiveBackupCopy();
165+
166+
return;
167+
}
168+
159169
const exportCommand = new ExportSQLCommand(
160170
this.app,
161171
this.env,
@@ -165,6 +175,51 @@ export class DevEnvSyncSQLCommand {
165175
await exportCommand.run();
166176
}
167177

178+
private async generateLiveBackupCopy(): Promise< void > {
179+
if ( ! this.configFile ) {
180+
throw new Error( 'Configuration file is required for live backup copy.' );
181+
}
182+
183+
if ( ! this.app.id || ! this.env.id ) {
184+
throw new Error( 'App ID and Environment ID are required to start live backup copy.' );
185+
}
186+
187+
const config = JSON.parse( fs.readFileSync( this.configFile, 'utf-8' ) ) as DBLiveCopyConfig;
188+
if ( ! config.type ) {
189+
throw new Error( 'Invalid configuration file. Missing tool or type.' );
190+
}
191+
192+
try {
193+
console.log( `${ chalk.green( '✓' ) } Creating backup copy` );
194+
195+
const copyId = await startLiveBackupCopy( {
196+
appId: this.app.id,
197+
environmentId: this.env.id,
198+
config,
199+
} );
200+
201+
const downloadURL = await getDownloadURL( {
202+
appId: this.app.id,
203+
environmentId: this.env.id,
204+
copyId,
205+
} );
206+
207+
console.log( `${ chalk.green( '✓' ) } Downloading file` );
208+
209+
await downloadFile( downloadURL, this.gzFile );
210+
} catch ( err ) {
211+
const message = err instanceof Error ? err.message : 'Unknown error';
212+
213+
await this.track( 'error', {
214+
error_type: 'live_backup_copy',
215+
error_message: message,
216+
stack: err instanceof Error ? err.stack : undefined,
217+
} );
218+
219+
exit.withError( `Error creating backup copy: ${ message }` );
220+
}
221+
}
222+
168223
/**
169224
* Runs the search-replace operation on the SQL file
170225
* to replace the site urls with the lando domain

0 commit comments

Comments
 (0)