relq 1.0.2 → 1.0.4
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/cjs/cli/commands/add.cjs +403 -27
- package/dist/cjs/cli/commands/branch.cjs +13 -23
- package/dist/cjs/cli/commands/checkout.cjs +16 -29
- package/dist/cjs/cli/commands/cherry-pick.cjs +3 -4
- package/dist/cjs/cli/commands/commit.cjs +21 -29
- package/dist/cjs/cli/commands/diff.cjs +28 -32
- package/dist/cjs/cli/commands/export.cjs +7 -7
- package/dist/cjs/cli/commands/fetch.cjs +15 -21
- package/dist/cjs/cli/commands/generate.cjs +28 -54
- package/dist/cjs/cli/commands/history.cjs +19 -40
- package/dist/cjs/cli/commands/import.cjs +34 -41
- package/dist/cjs/cli/commands/init.cjs +69 -59
- package/dist/cjs/cli/commands/introspect.cjs +4 -8
- package/dist/cjs/cli/commands/log.cjs +26 -32
- package/dist/cjs/cli/commands/merge.cjs +24 -41
- package/dist/cjs/cli/commands/migrate.cjs +12 -25
- package/dist/cjs/cli/commands/pull.cjs +216 -106
- package/dist/cjs/cli/commands/push.cjs +35 -75
- package/dist/cjs/cli/commands/remote.cjs +2 -1
- package/dist/cjs/cli/commands/reset.cjs +22 -43
- package/dist/cjs/cli/commands/resolve.cjs +12 -14
- package/dist/cjs/cli/commands/rollback.cjs +16 -38
- package/dist/cjs/cli/commands/stash.cjs +5 -7
- package/dist/cjs/cli/commands/status.cjs +5 -10
- package/dist/cjs/cli/commands/sync.cjs +30 -50
- package/dist/cjs/cli/commands/tag.cjs +3 -4
- package/dist/cjs/cli/index.cjs +72 -9
- package/dist/cjs/cli/utils/change-tracker.cjs +107 -3
- package/dist/cjs/cli/utils/cli-utils.cjs +217 -0
- package/dist/cjs/cli/utils/config-loader.cjs +34 -8
- package/dist/cjs/cli/utils/fast-introspect.cjs +109 -3
- package/dist/cjs/cli/utils/git-utils.cjs +42 -161
- package/dist/cjs/cli/utils/pool-manager.cjs +156 -0
- package/dist/cjs/cli/utils/project-root.cjs +56 -5
- package/dist/cjs/cli/utils/relqignore.cjs +1 -0
- package/dist/cjs/cli/utils/repo-manager.cjs +47 -0
- package/dist/cjs/cli/utils/schema-comparator.cjs +301 -11
- package/dist/cjs/cli/utils/schema-diff.cjs +202 -1
- package/dist/cjs/cli/utils/schema-hash.cjs +2 -1
- package/dist/cjs/cli/utils/schema-introspect.cjs +7 -3
- package/dist/cjs/cli/utils/snapshot-manager.cjs +1 -0
- package/dist/cjs/cli/utils/spinner.cjs +14 -106
- package/dist/cjs/cli/utils/sql-generator.cjs +10 -2
- package/dist/cjs/cli/utils/type-generator.cjs +28 -16
- package/dist/config.d.ts +16 -6
- package/dist/esm/cli/commands/add.js +372 -29
- package/dist/esm/cli/commands/branch.js +14 -24
- package/dist/esm/cli/commands/checkout.js +16 -29
- package/dist/esm/cli/commands/cherry-pick.js +3 -4
- package/dist/esm/cli/commands/commit.js +22 -30
- package/dist/esm/cli/commands/diff.js +6 -10
- package/dist/esm/cli/commands/export.js +8 -8
- package/dist/esm/cli/commands/fetch.js +14 -20
- package/dist/esm/cli/commands/generate.js +28 -54
- package/dist/esm/cli/commands/history.js +11 -32
- package/dist/esm/cli/commands/import.js +35 -42
- package/dist/esm/cli/commands/init.js +65 -55
- package/dist/esm/cli/commands/introspect.js +4 -8
- package/dist/esm/cli/commands/log.js +6 -12
- package/dist/esm/cli/commands/merge.js +20 -37
- package/dist/esm/cli/commands/migrate.js +12 -25
- package/dist/esm/cli/commands/pull.js +204 -94
- package/dist/esm/cli/commands/push.js +21 -61
- package/dist/esm/cli/commands/remote.js +2 -1
- package/dist/esm/cli/commands/reset.js +16 -37
- package/dist/esm/cli/commands/resolve.js +13 -15
- package/dist/esm/cli/commands/rollback.js +16 -38
- package/dist/esm/cli/commands/stash.js +6 -8
- package/dist/esm/cli/commands/status.js +6 -11
- package/dist/esm/cli/commands/sync.js +30 -50
- package/dist/esm/cli/commands/tag.js +3 -4
- package/dist/esm/cli/index.js +72 -9
- package/dist/esm/cli/utils/change-tracker.js +107 -3
- package/dist/esm/cli/utils/cli-utils.js +169 -0
- package/dist/esm/cli/utils/config-loader.js +34 -8
- package/dist/esm/cli/utils/fast-introspect.js +109 -3
- package/dist/esm/cli/utils/git-utils.js +2 -124
- package/dist/esm/cli/utils/pool-manager.js +114 -0
- package/dist/esm/cli/utils/project-root.js +55 -5
- package/dist/esm/cli/utils/relqignore.js +1 -0
- package/dist/esm/cli/utils/repo-manager.js +42 -0
- package/dist/esm/cli/utils/schema-comparator.js +301 -11
- package/dist/esm/cli/utils/schema-diff.js +202 -1
- package/dist/esm/cli/utils/schema-hash.js +2 -1
- package/dist/esm/cli/utils/schema-introspect.js +7 -3
- package/dist/esm/cli/utils/snapshot-manager.js +1 -0
- package/dist/esm/cli/utils/spinner.js +1 -101
- package/dist/esm/cli/utils/sql-generator.js +10 -2
- package/dist/esm/cli/utils/type-generator.js +28 -16
- package/dist/index.d.ts +25 -8
- package/dist/schema-builder.d.ts +18 -7
- package/package.json +1 -1
|
@@ -36,22 +36,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.pushCommand = pushCommand;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
-
const readline = __importStar(require("readline"));
|
|
40
39
|
const config_loader_1 = require("../utils/config-loader.cjs");
|
|
41
40
|
const env_loader_1 = require("../utils/env-loader.cjs");
|
|
42
|
-
const
|
|
41
|
+
const cli_utils_1 = require("../utils/cli-utils.cjs");
|
|
43
42
|
const fast_introspect_1 = require("../utils/fast-introspect.cjs");
|
|
44
43
|
const relqignore_1 = require("../utils/relqignore.cjs");
|
|
45
44
|
const repo_manager_1 = require("../utils/repo-manager.cjs");
|
|
46
45
|
async function pushCommand(context) {
|
|
47
46
|
const { config, flags } = context;
|
|
48
47
|
if (!config) {
|
|
49
|
-
|
|
50
|
-
process.exit(1);
|
|
48
|
+
(0, cli_utils_1.fatal)('No configuration found', `Run ${cli_utils_1.colors.cyan('relq init')} to create one.`);
|
|
51
49
|
}
|
|
52
|
-
(0, config_loader_1.requireValidConfig)(config);
|
|
50
|
+
await (0, config_loader_1.requireValidConfig)(config, { calledFrom: 'push' });
|
|
53
51
|
const connection = config.connection;
|
|
54
|
-
const projectRoot =
|
|
52
|
+
const { projectRoot } = context;
|
|
55
53
|
const force = flags['force'] === true;
|
|
56
54
|
const dryRun = flags['dry-run'] === true;
|
|
57
55
|
const applySQL = flags['apply'] === true;
|
|
@@ -62,23 +60,17 @@ async function pushCommand(context) {
|
|
|
62
60
|
const includeViews = config.includeViews ?? false;
|
|
63
61
|
console.log('');
|
|
64
62
|
if (!(0, repo_manager_1.isInitialized)(projectRoot)) {
|
|
65
|
-
|
|
66
|
-
console.log('');
|
|
67
|
-
console.log(`${spinner_1.colors.muted('Run')} ${spinner_1.colors.cyan('relq init')} ${spinner_1.colors.muted('to initialize.')}`);
|
|
68
|
-
return;
|
|
63
|
+
(0, cli_utils_1.fatal)('not a relq repository (or any parent directories): .relq', `Run ${cli_utils_1.colors.cyan('relq init')} to initialize.`);
|
|
69
64
|
}
|
|
70
65
|
const localHead = (0, repo_manager_1.getHead)(projectRoot);
|
|
71
66
|
if (!localHead) {
|
|
72
|
-
|
|
73
|
-
console.log('');
|
|
74
|
-
console.log(`${spinner_1.colors.muted('Run')} ${spinner_1.colors.cyan('relq commit -m "message"')} ${spinner_1.colors.muted('to create a commit.')}`);
|
|
75
|
-
return;
|
|
67
|
+
(0, cli_utils_1.fatal)('no commits to push', `Run ${cli_utils_1.colors.cyan('relq commit -m "message"')} to create a commit.`);
|
|
76
68
|
}
|
|
77
|
-
const spinner = (0,
|
|
69
|
+
const spinner = (0, cli_utils_1.createSpinner)();
|
|
78
70
|
try {
|
|
79
71
|
spinner.start('Connecting to remote...');
|
|
80
72
|
await (0, repo_manager_1.ensureRemoteTable)(connection);
|
|
81
|
-
spinner.succeed(`Connected to ${
|
|
73
|
+
spinner.succeed(`Connected to ${cli_utils_1.colors.cyan((0, env_loader_1.getConnectionDescription)(connection))}`);
|
|
82
74
|
spinner.start('Checking remote commits...');
|
|
83
75
|
const remoteCommits = await (0, repo_manager_1.fetchRemoteCommits)(connection, 100);
|
|
84
76
|
const remoteHead = remoteCommits.length > 0 ? remoteCommits[0].hash : null;
|
|
@@ -96,9 +88,8 @@ async function pushCommand(context) {
|
|
|
96
88
|
spinner.succeed(`Found ${remoteDb.tables.length} tables in remote`);
|
|
97
89
|
const localSnapshot = (0, repo_manager_1.loadSnapshot)(projectRoot);
|
|
98
90
|
if (!localSnapshot) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return;
|
|
91
|
+
spinner.stop();
|
|
92
|
+
(0, cli_utils_1.fatal)('No local snapshot found', `Run ${cli_utils_1.colors.cyan('relq pull')} or ${cli_utils_1.colors.cyan('relq import')} first.`);
|
|
102
93
|
}
|
|
103
94
|
const ignorePatterns = (0, relqignore_1.loadRelqignore)(projectRoot);
|
|
104
95
|
const analysis = analyzeSync(localSnapshot, remoteDb, ignorePatterns, { includeFunctions, includeTriggers, includeViews });
|
|
@@ -106,86 +97,69 @@ async function pushCommand(context) {
|
|
|
106
97
|
const hasObjectsToDrop = analysis.objectsToDrop.length > 0;
|
|
107
98
|
const hasSchemaDrift = analysis.schemaDrift.length > 0;
|
|
108
99
|
if (hasRemoteAhead && !force) {
|
|
109
|
-
|
|
110
|
-
console.log(`${spinner_1.colors.red('error:')} Remote has ${remoteMissing.length} commit(s) you don't have locally`);
|
|
100
|
+
spinner.stop();
|
|
111
101
|
console.log('');
|
|
112
102
|
for (const commit of remoteMissing.slice(0, 3)) {
|
|
113
|
-
console.log(` ${
|
|
103
|
+
console.log(` ${cli_utils_1.colors.yellow((0, repo_manager_1.shortHash)(commit.hash))} ${commit.message}`);
|
|
114
104
|
}
|
|
115
105
|
if (remoteMissing.length > 3) {
|
|
116
|
-
console.log(` ${
|
|
106
|
+
console.log(` ${cli_utils_1.colors.muted(`... and ${remoteMissing.length - 3} more`)}`);
|
|
117
107
|
}
|
|
118
|
-
|
|
119
|
-
console.log(`${spinner_1.colors.yellow('hint:')} Run ${spinner_1.colors.cyan('relq pull')} to integrate remote changes.`);
|
|
120
|
-
console.log(`${spinner_1.colors.yellow('hint:')} Use ${spinner_1.colors.cyan('relq push --force')} to override (may cause data loss).`);
|
|
121
|
-
console.log('');
|
|
122
|
-
return;
|
|
108
|
+
(0, cli_utils_1.fatal)(`Remote has ${remoteMissing.length} commit(s) you don't have locally`, `Run ${cli_utils_1.colors.cyan('relq pull')} to integrate remote changes.\nUse ${cli_utils_1.colors.cyan('relq push --force')} to override (may cause data loss).`);
|
|
123
109
|
}
|
|
124
110
|
if (hasObjectsToDrop) {
|
|
125
111
|
console.log('');
|
|
126
|
-
|
|
112
|
+
(0, cli_utils_1.warning)(`Remote has ${analysis.objectsToDrop.length} object(s) not in your local schema:`);
|
|
127
113
|
console.log('');
|
|
128
114
|
for (const obj of analysis.objectsToDrop.slice(0, 10)) {
|
|
129
|
-
console.log(` ${
|
|
115
|
+
console.log(` ${cli_utils_1.colors.red('DROP')} ${obj.type.toLowerCase()}: ${obj.name}`);
|
|
130
116
|
}
|
|
131
117
|
if (analysis.objectsToDrop.length > 10) {
|
|
132
|
-
console.log(` ${
|
|
118
|
+
console.log(` ${cli_utils_1.colors.muted(`... and ${analysis.objectsToDrop.length - 10} more`)}`);
|
|
133
119
|
}
|
|
134
120
|
console.log('');
|
|
135
121
|
if (!force) {
|
|
136
|
-
|
|
137
|
-
console.log('');
|
|
138
|
-
console.log(`${spinner_1.colors.yellow('hint:')} Run ${spinner_1.colors.cyan('relq pull')} first to sync your local schema.`);
|
|
139
|
-
console.log(`${spinner_1.colors.yellow('hint:')} Use ${spinner_1.colors.cyan('relq push --force')} to DROP these objects from remote.`);
|
|
140
|
-
console.log('');
|
|
141
|
-
return;
|
|
122
|
+
(0, cli_utils_1.fatal)('Cannot push - remote has objects not in your history', `Run ${cli_utils_1.colors.cyan('relq pull')} first to sync your local schema.\nUse ${cli_utils_1.colors.cyan('relq push --force')} to DROP these objects from remote.`);
|
|
142
123
|
}
|
|
143
124
|
const dependencyErrors = checkDropDependencies(analysis.objectsToDrop, remoteDb, ignorePatterns);
|
|
144
125
|
if (dependencyErrors.length > 0) {
|
|
145
|
-
console.log(`${spinner_1.colors.red('error:')} Cannot drop objects due to dependencies:`);
|
|
146
126
|
console.log('');
|
|
147
127
|
for (const err of dependencyErrors) {
|
|
148
|
-
console.log(` ${
|
|
128
|
+
console.log(` ${err}`);
|
|
149
129
|
}
|
|
150
|
-
|
|
151
|
-
console.log(`${spinner_1.colors.muted('These objects are used by non-ignored objects in your schema.')}`);
|
|
152
|
-
console.log(`${spinner_1.colors.muted('Either add them to .relqignore or import them with')} ${spinner_1.colors.cyan('relq pull')}`);
|
|
153
|
-
console.log('');
|
|
154
|
-
return;
|
|
130
|
+
(0, cli_utils_1.fatal)('Cannot drop objects due to dependencies', `These objects are used by non-ignored objects in your schema.\nEither add them to .relqignore or import them with ${cli_utils_1.colors.cyan('relq pull')}`);
|
|
155
131
|
}
|
|
156
132
|
if (!skipPrompt && !dryRun) {
|
|
157
|
-
|
|
133
|
+
(0, cli_utils_1.warning)('This will DROP data from your database!');
|
|
158
134
|
console.log('');
|
|
159
|
-
const confirmed = await
|
|
135
|
+
const confirmed = await (0, cli_utils_1.confirm)(`Drop ${analysis.objectsToDrop.length} object(s) from remote?`, false);
|
|
160
136
|
if (!confirmed) {
|
|
161
|
-
|
|
162
|
-
console.log('');
|
|
163
|
-
return;
|
|
137
|
+
(0, cli_utils_1.fatal)('Operation cancelled by user');
|
|
164
138
|
}
|
|
165
139
|
}
|
|
166
140
|
}
|
|
167
141
|
if (toPush.length === 0 && !hasObjectsToDrop) {
|
|
168
|
-
console.log(
|
|
142
|
+
console.log('Everything up-to-date');
|
|
169
143
|
console.log('');
|
|
170
144
|
return;
|
|
171
145
|
}
|
|
172
146
|
console.log('');
|
|
173
|
-
console.log(`Pushing to ${
|
|
147
|
+
console.log(`Pushing to ${cli_utils_1.colors.cyan((0, env_loader_1.getConnectionDescription)(connection))}`);
|
|
174
148
|
console.log('');
|
|
175
149
|
if (toPush.length > 0) {
|
|
176
|
-
console.log(`${
|
|
150
|
+
console.log(`${cli_utils_1.colors.cyan('Commits:')} ${toPush.length}`);
|
|
177
151
|
for (const commit of toPush.slice(0, 5)) {
|
|
178
|
-
console.log(` ${
|
|
152
|
+
console.log(` ${cli_utils_1.colors.yellow((0, repo_manager_1.shortHash)(commit.hash))} ${commit.message}`);
|
|
179
153
|
}
|
|
180
154
|
if (toPush.length > 5) {
|
|
181
|
-
console.log(` ${
|
|
155
|
+
console.log(` ${cli_utils_1.colors.muted(`... and ${toPush.length - 5} more`)}`);
|
|
182
156
|
}
|
|
183
157
|
console.log('');
|
|
184
158
|
}
|
|
185
159
|
if (dryRun) {
|
|
186
|
-
console.log(`${
|
|
160
|
+
console.log(`${cli_utils_1.colors.yellow('Dry run')} - no changes applied`);
|
|
187
161
|
console.log('');
|
|
188
|
-
console.log(`${
|
|
162
|
+
console.log(`${cli_utils_1.colors.muted('Use')} ${cli_utils_1.colors.cyan('relq push --apply')} ${cli_utils_1.colors.muted('to execute.')}`);
|
|
189
163
|
console.log('');
|
|
190
164
|
return;
|
|
191
165
|
}
|
|
@@ -252,21 +226,20 @@ async function pushCommand(context) {
|
|
|
252
226
|
}
|
|
253
227
|
const oldHash = remoteHead ? (0, repo_manager_1.shortHash)(remoteHead) : '(none)';
|
|
254
228
|
const newHash = (0, repo_manager_1.shortHash)(localHead);
|
|
255
|
-
console.log(` ${oldHash}..${newHash} ${
|
|
229
|
+
console.log(` ${oldHash}..${newHash} ${cli_utils_1.colors.muted('main -> main')}`);
|
|
256
230
|
if (hasObjectsToDrop && force && applySQL) {
|
|
257
231
|
console.log('');
|
|
258
|
-
|
|
232
|
+
(0, cli_utils_1.warning)(`Dropped ${analysis.objectsToDrop.length} object(s) from remote`);
|
|
259
233
|
}
|
|
260
234
|
if (!applySQL) {
|
|
261
235
|
console.log('');
|
|
262
|
-
console.log(`${
|
|
236
|
+
console.log(`${cli_utils_1.colors.muted('Use')} ${cli_utils_1.colors.cyan('relq push --apply')} ${cli_utils_1.colors.muted('to execute SQL.')}`);
|
|
263
237
|
}
|
|
264
238
|
console.log('');
|
|
265
239
|
}
|
|
266
|
-
catch (
|
|
240
|
+
catch (err) {
|
|
267
241
|
spinner.fail('Push failed');
|
|
268
|
-
|
|
269
|
-
process.exit(1);
|
|
242
|
+
(0, cli_utils_1.fatal)(err instanceof Error ? err.message : String(err));
|
|
270
243
|
}
|
|
271
244
|
}
|
|
272
245
|
function analyzeSync(local, remote, patterns, options) {
|
|
@@ -365,17 +338,4 @@ function generateDropSQL(obj) {
|
|
|
365
338
|
return '';
|
|
366
339
|
}
|
|
367
340
|
}
|
|
368
|
-
function askConfirmation(question) {
|
|
369
|
-
const rl = readline.createInterface({
|
|
370
|
-
input: process.stdin,
|
|
371
|
-
output: process.stdout,
|
|
372
|
-
});
|
|
373
|
-
return new Promise((resolve) => {
|
|
374
|
-
rl.question(question, (answer) => {
|
|
375
|
-
rl.close();
|
|
376
|
-
const a = answer.trim().toLowerCase();
|
|
377
|
-
resolve(a === 'y' || a === 'yes');
|
|
378
|
-
});
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
341
|
exports.default = pushCommand;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.remoteCommand = remoteCommand;
|
|
4
|
+
const spinner_1 = require("../utils/spinner.cjs");
|
|
4
5
|
async function remoteCommand(context) {
|
|
5
6
|
console.log('');
|
|
6
|
-
|
|
7
|
+
(0, spinner_1.warning)('Remote tracking is coming soon.');
|
|
7
8
|
console.log('');
|
|
8
9
|
console.log('This will allow you to:');
|
|
9
10
|
console.log(' • Track multiple remote databases');
|
|
@@ -37,40 +37,26 @@ exports.resetCommand = resetCommand;
|
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
39
|
const readline = __importStar(require("readline"));
|
|
40
|
-
const
|
|
40
|
+
const cli_utils_1 = require("../utils/cli-utils.cjs");
|
|
41
41
|
const repo_manager_1 = require("../utils/repo-manager.cjs");
|
|
42
42
|
async function resetCommand(context) {
|
|
43
|
-
const { flags, args } = context;
|
|
44
|
-
const projectRoot = process.cwd();
|
|
43
|
+
const { flags, args, projectRoot } = context;
|
|
45
44
|
console.log('');
|
|
46
45
|
if (!(0, repo_manager_1.isInitialized)(projectRoot)) {
|
|
47
|
-
|
|
48
|
-
return;
|
|
46
|
+
(0, cli_utils_1.fatal)('not a relq repository (or any parent directories): .relq', `Run ${cli_utils_1.colors.cyan('relq init')} to initialize.`);
|
|
49
47
|
}
|
|
50
48
|
const hard = flags['hard'] === true;
|
|
51
49
|
const soft = flags['soft'] === true;
|
|
52
50
|
const target = args[0];
|
|
53
51
|
if (!target) {
|
|
54
|
-
|
|
55
|
-
console.log('');
|
|
56
|
-
console.log('Usage:');
|
|
57
|
-
console.log(` ${spinner_1.colors.cyan('relq reset --hard HEAD~1')} Reset to previous commit`);
|
|
58
|
-
console.log(` ${spinner_1.colors.cyan('relq reset --hard <hash>')} Reset to specific commit`);
|
|
59
|
-
console.log('');
|
|
60
|
-
return;
|
|
52
|
+
(0, cli_utils_1.fatal)('Please specify a target', `Usage:\n ${cli_utils_1.colors.cyan('relq reset --hard HEAD~1')} Reset to previous commit\n ${cli_utils_1.colors.cyan('relq reset --hard <hash>')} Reset to specific commit`);
|
|
61
53
|
}
|
|
62
54
|
if (!hard && !soft) {
|
|
63
|
-
|
|
64
|
-
console.log('');
|
|
65
|
-
console.log(` ${spinner_1.colors.cyan('--hard')} Discard all changes (DANGEROUS)`);
|
|
66
|
-
console.log(` ${spinner_1.colors.cyan('--soft')} Keep changes unstaged`);
|
|
67
|
-
console.log('');
|
|
68
|
-
return;
|
|
55
|
+
(0, cli_utils_1.fatal)('Please specify --hard or --soft', ` ${cli_utils_1.colors.cyan('--hard')} Discard all changes (DANGEROUS)\n ${cli_utils_1.colors.cyan('--soft')} Keep changes unstaged`);
|
|
69
56
|
}
|
|
70
57
|
const currentHead = (0, repo_manager_1.getHead)(projectRoot);
|
|
71
58
|
if (!currentHead) {
|
|
72
|
-
|
|
73
|
-
return;
|
|
59
|
+
(0, cli_utils_1.fatal)('No commits yet', `Run ${cli_utils_1.colors.cyan('relq pull')} or ${cli_utils_1.colors.cyan('relq import')} first.`);
|
|
74
60
|
}
|
|
75
61
|
const allCommits = (0, repo_manager_1.getAllCommits)(projectRoot);
|
|
76
62
|
let targetHash = null;
|
|
@@ -91,23 +77,17 @@ async function resetCommand(context) {
|
|
|
91
77
|
}
|
|
92
78
|
}
|
|
93
79
|
if (!targetHash) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
console.log('Available commits:');
|
|
97
|
-
for (const c of allCommits.slice(0, 5)) {
|
|
98
|
-
console.log(` ${spinner_1.colors.yellow((0, repo_manager_1.shortHash)(c.hash))} ${c.message}`);
|
|
99
|
-
}
|
|
100
|
-
return;
|
|
80
|
+
const availableList = allCommits.slice(0, 5).map(c => ` ${cli_utils_1.colors.yellow((0, repo_manager_1.shortHash)(c.hash))} ${c.message}`).join('\n');
|
|
81
|
+
(0, cli_utils_1.fatal)(`Cannot find commit: ${target}`, `Available commits:\n${availableList}`);
|
|
101
82
|
}
|
|
102
83
|
const targetCommit = (0, repo_manager_1.loadCommit)(targetHash, projectRoot);
|
|
103
84
|
if (!targetCommit) {
|
|
104
|
-
|
|
105
|
-
return;
|
|
85
|
+
(0, cli_utils_1.fatal)(`Cannot load commit: ${targetHash}`);
|
|
106
86
|
}
|
|
107
87
|
if (hard) {
|
|
108
|
-
|
|
88
|
+
(0, cli_utils_1.warning)('This will discard all local changes!');
|
|
109
89
|
console.log('');
|
|
110
|
-
console.log(`Reset to: ${
|
|
90
|
+
console.log(`Reset to: ${cli_utils_1.colors.yellow((0, repo_manager_1.shortHash)(targetHash))} ${targetCommit.message}`);
|
|
111
91
|
console.log('');
|
|
112
92
|
const rl = readline.createInterface({
|
|
113
93
|
input: process.stdin,
|
|
@@ -120,24 +100,24 @@ async function resetCommand(context) {
|
|
|
120
100
|
});
|
|
121
101
|
});
|
|
122
102
|
if (!confirmed) {
|
|
123
|
-
console.log(`${
|
|
103
|
+
console.log(`${cli_utils_1.colors.muted('Cancelled.')}`);
|
|
124
104
|
console.log('');
|
|
125
105
|
return;
|
|
126
106
|
}
|
|
127
107
|
}
|
|
128
|
-
const spinner = (0,
|
|
108
|
+
const spinner = (0, cli_utils_1.createSpinner)();
|
|
129
109
|
try {
|
|
130
110
|
spinner.start(`Resetting to ${(0, repo_manager_1.shortHash)(targetHash)}...`);
|
|
131
111
|
const commitPath = path.join(projectRoot, '.relq', 'commits', `${targetHash}.json`);
|
|
132
112
|
if (!fs.existsSync(commitPath)) {
|
|
133
|
-
spinner.
|
|
134
|
-
|
|
113
|
+
spinner.stop();
|
|
114
|
+
(0, cli_utils_1.fatal)('Cannot find commit data - repository may be corrupt');
|
|
135
115
|
}
|
|
136
116
|
const commitData = JSON.parse(fs.readFileSync(commitPath, 'utf-8'));
|
|
137
117
|
const targetSnapshot = commitData.snapshot;
|
|
138
118
|
if (!targetSnapshot) {
|
|
139
|
-
spinner.
|
|
140
|
-
|
|
119
|
+
spinner.stop();
|
|
120
|
+
(0, cli_utils_1.fatal)('Commit has no snapshot data - repository may be corrupt');
|
|
141
121
|
}
|
|
142
122
|
if (hard) {
|
|
143
123
|
(0, repo_manager_1.saveSnapshot)(targetSnapshot, projectRoot);
|
|
@@ -152,18 +132,17 @@ async function resetCommand(context) {
|
|
|
152
132
|
if (fs.existsSync(mergeStatePath))
|
|
153
133
|
fs.unlinkSync(mergeStatePath);
|
|
154
134
|
}
|
|
155
|
-
spinner.succeed(`Reset to ${
|
|
135
|
+
spinner.succeed(`Reset to ${cli_utils_1.colors.yellow((0, repo_manager_1.shortHash)(targetHash))}`);
|
|
156
136
|
console.log('');
|
|
157
|
-
console.log(`HEAD is now at ${
|
|
137
|
+
console.log(`HEAD is now at ${cli_utils_1.colors.yellow((0, repo_manager_1.shortHash)(targetHash))} ${targetCommit.message}`);
|
|
158
138
|
console.log('');
|
|
159
139
|
if (soft) {
|
|
160
|
-
console.log(`${
|
|
140
|
+
console.log(`${cli_utils_1.colors.muted('Changes are unstaged. Use')} ${cli_utils_1.colors.cyan('relq status')} ${cli_utils_1.colors.muted('to see.')}`);
|
|
161
141
|
}
|
|
162
142
|
}
|
|
163
|
-
catch (
|
|
143
|
+
catch (err) {
|
|
164
144
|
spinner.fail('Reset failed');
|
|
165
|
-
|
|
166
|
-
process.exit(1);
|
|
145
|
+
(0, cli_utils_1.fatal)(err instanceof Error ? err.message : String(err));
|
|
167
146
|
}
|
|
168
147
|
}
|
|
169
148
|
exports.default = resetCommand;
|
|
@@ -39,23 +39,21 @@ const path = __importStar(require("path"));
|
|
|
39
39
|
const spinner_1 = require("../utils/spinner.cjs");
|
|
40
40
|
const repo_manager_1 = require("../utils/repo-manager.cjs");
|
|
41
41
|
async function resolveCommand(context) {
|
|
42
|
-
const { flags, args } = context;
|
|
43
|
-
const projectRoot = process.cwd();
|
|
42
|
+
const { flags, args, projectRoot } = context;
|
|
44
43
|
console.log('');
|
|
45
44
|
if (!(0, repo_manager_1.isInitialized)(projectRoot)) {
|
|
46
|
-
|
|
47
|
-
return;
|
|
45
|
+
(0, spinner_1.fatal)('not a relq repository (or any parent directories): .relq', `Run ${spinner_1.colors.cyan('relq init')} to initialize.`);
|
|
48
46
|
}
|
|
49
47
|
const mergeStatePath = path.join(projectRoot, '.relq', 'MERGE_STATE');
|
|
50
48
|
if (!fs.existsSync(mergeStatePath)) {
|
|
51
|
-
console.log(
|
|
49
|
+
console.log('No conflicts to resolve');
|
|
52
50
|
console.log('');
|
|
53
51
|
return;
|
|
54
52
|
}
|
|
55
53
|
const mergeState = JSON.parse(fs.readFileSync(mergeStatePath, 'utf-8'));
|
|
56
54
|
if (mergeState.conflicts.length === 0) {
|
|
57
55
|
fs.unlinkSync(mergeStatePath);
|
|
58
|
-
console.log(
|
|
56
|
+
console.log('All conflicts resolved');
|
|
59
57
|
console.log('');
|
|
60
58
|
return;
|
|
61
59
|
}
|
|
@@ -69,9 +67,9 @@ async function resolveCommand(context) {
|
|
|
69
67
|
console.log('');
|
|
70
68
|
(0, repo_manager_1.saveSnapshot)(mergeState.remoteSnapshot, projectRoot);
|
|
71
69
|
fs.unlinkSync(mergeStatePath);
|
|
72
|
-
console.log(
|
|
70
|
+
console.log('Applied remote versions for all conflicts');
|
|
73
71
|
console.log('');
|
|
74
|
-
console.log(
|
|
72
|
+
console.log(`hint: run 'relq commit -m "Merge remote changes"' to complete`);
|
|
75
73
|
console.log('');
|
|
76
74
|
return;
|
|
77
75
|
}
|
|
@@ -79,9 +77,9 @@ async function resolveCommand(context) {
|
|
|
79
77
|
console.log(`Resolving ${mergeState.conflicts.length} conflict(s) with --all-ours`);
|
|
80
78
|
console.log('');
|
|
81
79
|
fs.unlinkSync(mergeStatePath);
|
|
82
|
-
console.log(
|
|
80
|
+
console.log('Kept local versions for all conflicts');
|
|
83
81
|
console.log('');
|
|
84
|
-
console.log(
|
|
82
|
+
console.log(`hint: run 'relq commit -m "Keep local changes"' to complete`);
|
|
85
83
|
console.log('');
|
|
86
84
|
return;
|
|
87
85
|
}
|
|
@@ -111,17 +109,17 @@ async function resolveCommand(context) {
|
|
|
111
109
|
mergeState.conflicts = mergeState.conflicts.filter(c => c !== conflict);
|
|
112
110
|
if (mergeState.conflicts.length === 0) {
|
|
113
111
|
fs.unlinkSync(mergeStatePath);
|
|
114
|
-
console.log(
|
|
112
|
+
console.log('All conflicts resolved');
|
|
115
113
|
}
|
|
116
114
|
else {
|
|
117
115
|
fs.writeFileSync(mergeStatePath, JSON.stringify(mergeState, null, 2));
|
|
118
|
-
console.log(
|
|
119
|
-
console.log(`${
|
|
116
|
+
console.log(`Resolved: ${conflict.objectType} ${objectName}`);
|
|
117
|
+
console.log(`${mergeState.conflicts.length} conflict(s) remaining`);
|
|
120
118
|
}
|
|
121
119
|
console.log('');
|
|
122
120
|
return;
|
|
123
121
|
}
|
|
124
|
-
|
|
122
|
+
(0, spinner_1.warning)(`You have ${mergeState.conflicts.length} unresolved conflict(s):`);
|
|
125
123
|
console.log('');
|
|
126
124
|
for (const conflict of mergeState.conflicts) {
|
|
127
125
|
const name = conflict.parentName
|
|
@@ -36,18 +36,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.rollbackCommand = rollbackCommand;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
-
const readline = __importStar(require("readline"));
|
|
40
39
|
const config_loader_1 = require("../utils/config-loader.cjs");
|
|
41
40
|
const env_loader_1 = require("../utils/env-loader.cjs");
|
|
42
|
-
const
|
|
43
|
-
reset: '\x1b[0m',
|
|
44
|
-
bold: '\x1b[1m',
|
|
45
|
-
dim: '\x1b[2m',
|
|
46
|
-
red: '\x1b[31m',
|
|
47
|
-
green: '\x1b[32m',
|
|
48
|
-
yellow: '\x1b[33m',
|
|
49
|
-
cyan: '\x1b[36m',
|
|
50
|
-
};
|
|
41
|
+
const cli_utils_1 = require("../utils/cli-utils.cjs");
|
|
51
42
|
function parseMigration(content) {
|
|
52
43
|
const upMatch = content.match(/--\s*UP\s*\n([\s\S]*?)(?=--\s*DOWN|$)/i);
|
|
53
44
|
const downMatch = content.match(/--\s*DOWN\s*\n([\s\S]*?)$/i);
|
|
@@ -56,32 +47,20 @@ function parseMigration(content) {
|
|
|
56
47
|
down: downMatch?.[1]?.trim() || '',
|
|
57
48
|
};
|
|
58
49
|
}
|
|
59
|
-
function askConfirm(question) {
|
|
60
|
-
const rl = readline.createInterface({
|
|
61
|
-
input: process.stdin,
|
|
62
|
-
output: process.stdout,
|
|
63
|
-
});
|
|
64
|
-
return new Promise((resolve) => {
|
|
65
|
-
rl.question(`${question} [y/N]: `, (answer) => {
|
|
66
|
-
rl.close();
|
|
67
|
-
resolve(answer.trim().toLowerCase() === 'y');
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
50
|
async function rollbackCommand(context) {
|
|
72
51
|
const { config, args, flags } = context;
|
|
73
52
|
if (!config) {
|
|
74
|
-
|
|
75
|
-
|
|
53
|
+
(0, cli_utils_1.fatal)('No configuration found', `run ${cli_utils_1.colors.cyan('relq init')} to create a configuration file`);
|
|
54
|
+
return;
|
|
76
55
|
}
|
|
77
|
-
(0, config_loader_1.requireValidConfig)(config);
|
|
56
|
+
await (0, config_loader_1.requireValidConfig)(config, { calledFrom: 'rollback' });
|
|
78
57
|
const connection = config.connection;
|
|
79
58
|
const migrationsDir = config.migrations?.directory || './migrations';
|
|
80
59
|
const tableName = config.migrations?.tableName || '_relq_migrations';
|
|
81
60
|
const count = parseInt(args[0]) || 1;
|
|
82
61
|
const dryRun = flags['dry-run'] === true;
|
|
83
62
|
const force = flags['force'] === true;
|
|
84
|
-
console.log(
|
|
63
|
+
console.log(`Rolling back ${count} migration(s)...`);
|
|
85
64
|
console.log(` Connection: ${(0, env_loader_1.getConnectionDescription)(connection)}`);
|
|
86
65
|
console.log('');
|
|
87
66
|
try {
|
|
@@ -101,17 +80,17 @@ async function rollbackCommand(context) {
|
|
|
101
80
|
LIMIT $1;
|
|
102
81
|
`, [count]);
|
|
103
82
|
if (result.rows.length === 0) {
|
|
104
|
-
console.log(
|
|
83
|
+
console.log('No migrations to rollback.');
|
|
105
84
|
return;
|
|
106
85
|
}
|
|
107
86
|
const toRollback = result.rows.map(r => r.name);
|
|
108
|
-
console.log(
|
|
87
|
+
console.log('Migrations to rollback:');
|
|
109
88
|
for (const name of toRollback) {
|
|
110
|
-
console.log(`
|
|
89
|
+
console.log(` - ${name}`);
|
|
111
90
|
}
|
|
112
91
|
console.log('');
|
|
113
92
|
if (!force && !dryRun) {
|
|
114
|
-
const proceed = await
|
|
93
|
+
const proceed = await (0, cli_utils_1.confirm)(`${cli_utils_1.colors.red('This will undo ' + toRollback.length + ' migration(s). Continue?')}`, false);
|
|
115
94
|
if (!proceed) {
|
|
116
95
|
console.log('Cancelled.');
|
|
117
96
|
return;
|
|
@@ -120,18 +99,18 @@ async function rollbackCommand(context) {
|
|
|
120
99
|
for (const name of toRollback) {
|
|
121
100
|
const filePath = path.join(migrationsDir, name);
|
|
122
101
|
if (!fs.existsSync(filePath)) {
|
|
123
|
-
|
|
102
|
+
(0, cli_utils_1.warning)(`Migration file not found: ${name}`);
|
|
124
103
|
continue;
|
|
125
104
|
}
|
|
126
105
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
127
106
|
const { down } = parseMigration(content);
|
|
128
107
|
if (!down) {
|
|
129
|
-
|
|
108
|
+
(0, cli_utils_1.warning)(`No DOWN section in: ${name}`);
|
|
130
109
|
continue;
|
|
131
110
|
}
|
|
132
111
|
if (dryRun) {
|
|
133
|
-
console.log(
|
|
134
|
-
console.log(
|
|
112
|
+
console.log(`[dry-run] Would rollback: ${name}`);
|
|
113
|
+
console.log(down);
|
|
135
114
|
console.log('');
|
|
136
115
|
}
|
|
137
116
|
else {
|
|
@@ -142,7 +121,7 @@ async function rollbackCommand(context) {
|
|
|
142
121
|
await client.query(down);
|
|
143
122
|
await client.query(`DELETE FROM "${tableName}" WHERE name = $1`, [name]);
|
|
144
123
|
await client.query('COMMIT');
|
|
145
|
-
console.log(
|
|
124
|
+
console.log(' Rolled back');
|
|
146
125
|
}
|
|
147
126
|
catch (error) {
|
|
148
127
|
await client.query('ROLLBACK');
|
|
@@ -155,7 +134,7 @@ async function rollbackCommand(context) {
|
|
|
155
134
|
}
|
|
156
135
|
if (!dryRun) {
|
|
157
136
|
console.log('');
|
|
158
|
-
console.log(
|
|
137
|
+
console.log(`Rolled back ${toRollback.length} migration(s).`);
|
|
159
138
|
}
|
|
160
139
|
}
|
|
161
140
|
finally {
|
|
@@ -163,7 +142,6 @@ async function rollbackCommand(context) {
|
|
|
163
142
|
}
|
|
164
143
|
}
|
|
165
144
|
catch (error) {
|
|
166
|
-
|
|
167
|
-
process.exit(1);
|
|
145
|
+
(0, cli_utils_1.fatal)('Rollback failed', error instanceof Error ? error.message : String(error));
|
|
168
146
|
}
|
|
169
147
|
}
|
|
@@ -39,13 +39,11 @@ const path = __importStar(require("path"));
|
|
|
39
39
|
const spinner_1 = require("../utils/spinner.cjs");
|
|
40
40
|
const repo_manager_1 = require("../utils/repo-manager.cjs");
|
|
41
41
|
async function stashCommand(context) {
|
|
42
|
-
const { args, flags } = context;
|
|
43
|
-
const projectRoot = process.cwd();
|
|
42
|
+
const { args, flags, projectRoot } = context;
|
|
44
43
|
const subcommand = args[0] || 'push';
|
|
45
44
|
console.log('');
|
|
46
45
|
if (!(0, repo_manager_1.isInitialized)(projectRoot)) {
|
|
47
|
-
|
|
48
|
-
return;
|
|
46
|
+
(0, spinner_1.fatal)('not a relq repository (or any parent directories): .relq', `Run ${spinner_1.colors.cyan('relq init')} to initialize.`);
|
|
49
47
|
}
|
|
50
48
|
const stashDir = path.join(projectRoot, '.relq', 'stash');
|
|
51
49
|
switch (subcommand) {
|
|
@@ -92,7 +90,7 @@ async function stashPush(projectRoot, stashDir, message) {
|
|
|
92
90
|
fs.writeFileSync(stagedPath, '[]');
|
|
93
91
|
if (fs.existsSync(unstagedPath))
|
|
94
92
|
fs.writeFileSync(unstagedPath, '[]');
|
|
95
|
-
console.log(
|
|
93
|
+
console.log('Saved working directory');
|
|
96
94
|
console.log(` stash@{${stashIdx}}: ${message}`);
|
|
97
95
|
console.log('');
|
|
98
96
|
}
|
|
@@ -117,7 +115,7 @@ async function stashPop(projectRoot, stashDir) {
|
|
|
117
115
|
fs.writeFileSync(unstagedPath, JSON.stringify(stash.unstaged, null, 2));
|
|
118
116
|
}
|
|
119
117
|
fs.unlinkSync(stashPath);
|
|
120
|
-
console.log(
|
|
118
|
+
console.log('Applied stash and dropped');
|
|
121
119
|
console.log(` ${stash.message}`);
|
|
122
120
|
console.log('');
|
|
123
121
|
}
|
|
@@ -148,7 +146,7 @@ async function stashDrop(stashDir) {
|
|
|
148
146
|
return;
|
|
149
147
|
}
|
|
150
148
|
fs.unlinkSync(path.join(stashDir, stashFiles[0]));
|
|
151
|
-
console.log(
|
|
149
|
+
console.log('Dropped stash');
|
|
152
150
|
console.log('');
|
|
153
151
|
}
|
|
154
152
|
exports.default = stashCommand;
|