@ductape/cli 0.2.23 → 0.3.1
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/CHANGELOG.md +7 -0
- package/README.md +7 -0
- package/dist/commands/db-migrate.js +47 -8
- package/dist/commands/migrate-codebase.d.ts +190 -0
- package/dist/commands/migrate-codebase.js +776 -0
- package/dist/commands/migration-artifact.d.ts +28 -0
- package/dist/commands/migration-artifact.js +101 -0
- package/dist/commands/migration-assurance.d.ts +10 -0
- package/dist/commands/migration-assurance.js +120 -0
- package/dist/commands/migration-capabilities.d.ts +53 -0
- package/dist/commands/migration-capabilities.js +66 -0
- package/dist/commands/migration-database.d.ts +26 -0
- package/dist/commands/migration-database.js +162 -0
- package/dist/commands/migration-e2e.d.ts +68 -0
- package/dist/commands/migration-e2e.js +189 -0
- package/dist/commands/migration-environments.d.ts +20 -0
- package/dist/commands/migration-environments.js +58 -0
- package/dist/commands/migration-generated.d.ts +68 -0
- package/dist/commands/migration-generated.js +217 -0
- package/dist/commands/migration-portfolio.d.ts +88 -0
- package/dist/commands/migration-portfolio.js +223 -0
- package/dist/commands/migration-products.d.ts +23 -0
- package/dist/commands/migration-products.js +88 -0
- package/dist/commands/migration-review.d.ts +248 -0
- package/dist/commands/migration-review.js +624 -0
- package/dist/commands/migration-secrets.d.ts +24 -0
- package/dist/commands/migration-secrets.js +93 -0
- package/dist/commands/migration-slice.d.ts +132 -0
- package/dist/commands/migration-slice.js +266 -0
- package/dist/commands/migration-verification.d.ts +12 -0
- package/dist/commands/migration-verification.js +194 -0
- package/dist/commands/products.d.ts +1 -0
- package/dist/commands/products.js +33 -1
- package/dist/commands/secrets.d.ts +8 -0
- package/dist/commands/secrets.js +44 -0
- package/dist/index.js +376 -4
- package/dist/lib/migration-artifact.d.ts +19 -0
- package/dist/lib/migration-artifact.js +114 -0
- package/package.json +8 -1
- package/API_PARITY.md +0 -58
- package/DB_MIGRATE_PLAN.md +0 -223
- package/ductape.example.ts +0 -18
- package/src/commands/apply.ts +0 -153
- package/src/commands/apps-import.ts +0 -43
- package/src/commands/apps.ts +0 -92
- package/src/commands/cloud.ts +0 -68
- package/src/commands/completion.ts +0 -119
- package/src/commands/db-migrate.ts +0 -209
- package/src/commands/db-schema.ts +0 -429
- package/src/commands/db.ts +0 -63
- package/src/commands/generate.ts +0 -74
- package/src/commands/graph.ts +0 -51
- package/src/commands/init.ts +0 -39
- package/src/commands/install.ts +0 -76
- package/src/commands/link.ts +0 -84
- package/src/commands/login.ts +0 -145
- package/src/commands/logout.ts +0 -7
- package/src/commands/platform.ts +0 -123
- package/src/commands/products.ts +0 -228
- package/src/commands/profiles.ts +0 -23
- package/src/commands/resources.ts +0 -213
- package/src/commands/secrets.ts +0 -46
- package/src/commands/unlink.ts +0 -15
- package/src/commands/whoami.ts +0 -27
- package/src/commands/workspaces.ts +0 -98
- package/src/index.ts +0 -523
- package/src/lib/api-client.ts +0 -88
- package/src/lib/app-import.ts +0 -82
- package/src/lib/apply-loaders.ts +0 -30
- package/src/lib/config.ts +0 -230
- package/src/lib/context-store.ts +0 -77
- package/src/lib/db-methods.ts +0 -56
- package/src/lib/db-types.ts +0 -104
- package/src/lib/encryption.ts +0 -12
- package/src/lib/forms/enums.ts +0 -52
- package/src/lib/forms/index.ts +0 -8
- package/src/lib/forms/prompt.ts +0 -209
- package/src/lib/forms/schemas.ts +0 -288
- package/src/lib/forms/types.ts +0 -27
- package/src/lib/http.ts +0 -76
- package/src/lib/integrations.ts +0 -110
- package/src/lib/interactive-opts.ts +0 -13
- package/src/lib/migration-files.ts +0 -58
- package/src/lib/output.ts +0 -39
- package/src/lib/platform-api.ts +0 -209
- package/src/lib/proxy/context.ts +0 -94
- package/src/lib/proxy/db-proxy.ts +0 -40
- package/src/lib/proxy/graph-proxy.ts +0 -64
- package/src/lib/proxy/sdk-proxy.ts +0 -58
- package/src/lib/read-body.ts +0 -57
- package/src/lib/resources.ts +0 -160
- package/src/lib/schema-loader.ts +0 -152
- package/src/lib/snippets.ts +0 -165
- package/src/lib/templates.ts +0 -157
- package/src/lib/workspace-context.ts +0 -43
- package/src/lib/workspaces.ts +0 -283
- package/test/apply-loaders.test.ts +0 -40
- package/test/encryption.test.ts +0 -20
- package/test/forms.test.ts +0 -25
- package/test/http.test.ts +0 -15
- package/test/platform-api.test.ts +0 -42
- package/test/resources.test.ts +0 -23
- package/test/workspace-resolve.test.ts +0 -29
- package/tsconfig.json +0 -15
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { listResourceTypes } from '../lib/resources.js';
|
|
2
|
-
import { DB_PROXY_METHODS, GRAPH_PROXY_METHODS } from '../lib/db-methods.js';
|
|
3
|
-
|
|
4
|
-
const TOP_LEVEL = [
|
|
5
|
-
'login',
|
|
6
|
-
'logout',
|
|
7
|
-
'whoami',
|
|
8
|
-
'profiles',
|
|
9
|
-
'workspaces',
|
|
10
|
-
'link',
|
|
11
|
-
'unlink',
|
|
12
|
-
'init',
|
|
13
|
-
'install',
|
|
14
|
-
'start',
|
|
15
|
-
'stop',
|
|
16
|
-
'status',
|
|
17
|
-
'products',
|
|
18
|
-
'apps',
|
|
19
|
-
'resources',
|
|
20
|
-
'cloud',
|
|
21
|
-
'db',
|
|
22
|
-
'graph',
|
|
23
|
-
'secrets',
|
|
24
|
-
'generate',
|
|
25
|
-
'completion',
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
const ENTITY_CRUD = 'list get create update delete';
|
|
29
|
-
|
|
30
|
-
export function runCompletion(shell: 'bash' | 'zsh' | 'fish'): void {
|
|
31
|
-
const resources = listResourceTypes();
|
|
32
|
-
const crud = 'create list get update delete connect';
|
|
33
|
-
|
|
34
|
-
if (shell === 'bash') {
|
|
35
|
-
console.log(`
|
|
36
|
-
_ductape_completions() {
|
|
37
|
-
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
38
|
-
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
39
|
-
local cmd="\${COMP_WORDS[1]}"
|
|
40
|
-
|
|
41
|
-
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
42
|
-
COMPREPLY=( $(compgen -W "${TOP_LEVEL.join(' ')}" -- "$cur") )
|
|
43
|
-
return
|
|
44
|
-
fi
|
|
45
|
-
|
|
46
|
-
case "$cmd" in
|
|
47
|
-
products)
|
|
48
|
-
if [[ \${COMP_CWORD} -eq 2 ]]; then
|
|
49
|
-
COMPREPLY=( $(compgen -W "${ENTITY_CRUD}" -- "$cur") )
|
|
50
|
-
fi
|
|
51
|
-
;;
|
|
52
|
-
apps)
|
|
53
|
-
if [[ \${COMP_CWORD} -eq 2 ]]; then
|
|
54
|
-
COMPREPLY=( $(compgen -W "import ${ENTITY_CRUD}" -- "$cur") )
|
|
55
|
-
elif [[ \${COMP_CWORD} -eq 3 && "\${COMP_WORDS[2]}" == "import" ]]; then
|
|
56
|
-
COMPREPLY=( $(compgen -f -- "$cur") )
|
|
57
|
-
fi
|
|
58
|
-
;;
|
|
59
|
-
resources)
|
|
60
|
-
if [[ \${COMP_CWORD} -eq 2 ]]; then
|
|
61
|
-
COMPREPLY=( $(compgen -W "types ${resources.join(' ')}" -- "$cur") )
|
|
62
|
-
elif [[ \${COMP_CWORD} -eq 3 ]]; then
|
|
63
|
-
COMPREPLY=( $(compgen -W "${crud}" -- "$cur") )
|
|
64
|
-
fi
|
|
65
|
-
;;
|
|
66
|
-
db)
|
|
67
|
-
if [[ \${COMP_CWORD} -eq 2 ]]; then
|
|
68
|
-
COMPREPLY=( $(compgen -W "${DB_PROXY_METHODS.join(' ')}" -- "$cur") )
|
|
69
|
-
fi
|
|
70
|
-
;;
|
|
71
|
-
graph)
|
|
72
|
-
if [[ \${COMP_CWORD} -eq 2 ]]; then
|
|
73
|
-
COMPREPLY=( $(compgen -W "${GRAPH_PROXY_METHODS.join(' ')}" -- "$cur") )
|
|
74
|
-
fi
|
|
75
|
-
;;
|
|
76
|
-
profiles|workspaces)
|
|
77
|
-
if [[ \${COMP_CWORD} -eq 2 ]]; then
|
|
78
|
-
COMPREPLY=( $(compgen -W "list use" -- "$cur") )
|
|
79
|
-
fi
|
|
80
|
-
;;
|
|
81
|
-
generate)
|
|
82
|
-
if [[ \${COMP_CWORD} -eq 2 ]]; then
|
|
83
|
-
COMPREPLY=( $(compgen -W "payload snippet" -- "$cur") )
|
|
84
|
-
fi
|
|
85
|
-
;;
|
|
86
|
-
esac
|
|
87
|
-
}
|
|
88
|
-
complete -F _ductape_completions ductape
|
|
89
|
-
`);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (shell === 'zsh') {
|
|
94
|
-
console.log(`
|
|
95
|
-
#compdef ductape
|
|
96
|
-
_ductape() {
|
|
97
|
-
local -a commands
|
|
98
|
-
commands=(
|
|
99
|
-
${TOP_LEVEL.map((c) => `'${c}:command'`).join('\n ')}
|
|
100
|
-
)
|
|
101
|
-
_arguments '1: :->cmd' '*: :->args'
|
|
102
|
-
case $state in
|
|
103
|
-
cmd) _describe 'command' commands ;;
|
|
104
|
-
args)
|
|
105
|
-
case $words[1] in
|
|
106
|
-
resources) _arguments '2: :(types ${resources.join(' ')})' '3: :(${crud.split(' ').join(' ')})' ;;
|
|
107
|
-
db) _arguments '2: :(${DB_PROXY_METHODS.join(' ')})' ;;
|
|
108
|
-
graph) _arguments '2: :(${GRAPH_PROXY_METHODS.join(' ')})' ;;
|
|
109
|
-
esac
|
|
110
|
-
;;
|
|
111
|
-
esac
|
|
112
|
-
}
|
|
113
|
-
_ductape
|
|
114
|
-
`);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
console.log(`# Fish: use ductape completion bash | source`);
|
|
119
|
-
}
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { findProjectConfig } from '../lib/config.js';
|
|
2
|
-
import { loadSchemaFile } from '../lib/schema-loader.js';
|
|
3
|
-
import { loadMigrationFiles } from '../lib/migration-files.js';
|
|
4
|
-
import { getDbProxy, requireSession } from '../lib/proxy/context.js';
|
|
5
|
-
import { fail, printJson } from '../lib/output.js';
|
|
6
|
-
import type { DatabaseContext } from '../lib/context-store.js';
|
|
7
|
-
|
|
8
|
-
interface MigrateOpts {
|
|
9
|
-
env?: string;
|
|
10
|
-
db?: string;
|
|
11
|
-
dryRun?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface MigrateStatusOpts {
|
|
15
|
-
env?: string;
|
|
16
|
-
db?: string;
|
|
17
|
-
json?: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface MigrateRollbackOpts {
|
|
21
|
-
env?: string;
|
|
22
|
-
db?: string;
|
|
23
|
-
n?: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function buildDbContext(dbTag: string, envSlug: string, productTag: string): DatabaseContext {
|
|
27
|
-
return { database: dbTag, env: envSlug, product: productTag };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async function getAppliedTags(
|
|
31
|
-
proxy: ReturnType<typeof getDbProxy>,
|
|
32
|
-
dbContext: DatabaseContext,
|
|
33
|
-
): Promise<string[]> {
|
|
34
|
-
try {
|
|
35
|
-
const result = await proxy.execute<unknown>(
|
|
36
|
-
'migration.history',
|
|
37
|
-
[],
|
|
38
|
-
dbContext,
|
|
39
|
-
);
|
|
40
|
-
const list = Array.isArray(result)
|
|
41
|
-
? result
|
|
42
|
-
: Array.isArray((result as { data?: unknown[] }).data)
|
|
43
|
-
? (result as { data: unknown[] }).data
|
|
44
|
-
: [];
|
|
45
|
-
return (list as Array<{ tag?: string }>).map((r) => r.tag ?? '').filter(Boolean);
|
|
46
|
-
} catch {
|
|
47
|
-
return [];
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export async function runDbMigrate(opts: MigrateOpts): Promise<void> {
|
|
52
|
-
const found = findProjectConfig();
|
|
53
|
-
if (!found) fail('No linked project. Run `ductape link` from your project directory.');
|
|
54
|
-
|
|
55
|
-
const { dir } = found;
|
|
56
|
-
const session = requireSession();
|
|
57
|
-
const proxy = getDbProxy(session);
|
|
58
|
-
const envSlug = opts.env ?? session.project.env_slug;
|
|
59
|
-
const productTag = session.project.product_tag;
|
|
60
|
-
|
|
61
|
-
const schemaEntries = loadSchemaFile(dir);
|
|
62
|
-
const targets = opts.db ? schemaEntries.filter((e) => e.db === opts.db) : schemaEntries;
|
|
63
|
-
|
|
64
|
-
if (targets.length === 0) {
|
|
65
|
-
fail(opts.db ? `No db entry found for tag "${opts.db}".` : 'schema.json is empty.');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
let totalApplied = 0;
|
|
69
|
-
let totalDry = 0;
|
|
70
|
-
|
|
71
|
-
for (const entry of targets) {
|
|
72
|
-
const { db } = entry;
|
|
73
|
-
const dbContext = buildDbContext(db, envSlug, productTag);
|
|
74
|
-
const migrations = loadMigrationFiles(dir, db);
|
|
75
|
-
|
|
76
|
-
if (migrations.length === 0) {
|
|
77
|
-
console.log(`[${db}] No migration files found. Run \`ductape db schema generate\` first.`);
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const appliedTags = await getAppliedTags(proxy, dbContext);
|
|
82
|
-
const pending = migrations.filter((m) => !appliedTags.includes(m.tag));
|
|
83
|
-
|
|
84
|
-
if (pending.length === 0) {
|
|
85
|
-
console.log(`[${db}] Already up to date.`);
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
console.log(`[${db}] ${pending.length} pending migration(s).`);
|
|
90
|
-
|
|
91
|
-
for (const migration of pending) {
|
|
92
|
-
if (opts.dryRun) {
|
|
93
|
-
console.log(` [dry-run] Would apply: ${migration.tag}`);
|
|
94
|
-
totalDry++;
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
process.stdout.write(` Applying ${migration.tag}... `);
|
|
99
|
-
try {
|
|
100
|
-
await proxy.execute(
|
|
101
|
-
'migration.run',
|
|
102
|
-
[[migration]],
|
|
103
|
-
dbContext,
|
|
104
|
-
);
|
|
105
|
-
console.log('done');
|
|
106
|
-
totalApplied++;
|
|
107
|
-
} catch (err) {
|
|
108
|
-
console.log('failed');
|
|
109
|
-
fail(`Migration "${migration.tag}" failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (opts.dryRun) {
|
|
115
|
-
console.log(`\nDry run: ${totalDry} migration(s) would be applied.`);
|
|
116
|
-
} else {
|
|
117
|
-
console.log(`\nApplied ${totalApplied} migration(s).`);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export async function runDbMigrateStatus(opts: MigrateStatusOpts): Promise<void> {
|
|
122
|
-
const found = findProjectConfig();
|
|
123
|
-
if (!found) fail('No linked project. Run `ductape link` from your project directory.');
|
|
124
|
-
|
|
125
|
-
const { dir } = found;
|
|
126
|
-
const session = requireSession();
|
|
127
|
-
const proxy = getDbProxy(session);
|
|
128
|
-
const envSlug = opts.env ?? session.project.env_slug;
|
|
129
|
-
const productTag = session.project.product_tag;
|
|
130
|
-
|
|
131
|
-
const schemaEntries = loadSchemaFile(dir);
|
|
132
|
-
const targets = opts.db ? schemaEntries.filter((e) => e.db === opts.db) : schemaEntries;
|
|
133
|
-
|
|
134
|
-
const statusReport: Record<string, { applied: string[]; pending: string[] }> = {};
|
|
135
|
-
|
|
136
|
-
for (const entry of targets) {
|
|
137
|
-
const { db } = entry;
|
|
138
|
-
const dbContext = buildDbContext(db, envSlug, productTag);
|
|
139
|
-
const migrations = loadMigrationFiles(dir, db);
|
|
140
|
-
const appliedTags = await getAppliedTags(proxy, dbContext);
|
|
141
|
-
|
|
142
|
-
const applied = migrations.filter((m) => appliedTags.includes(m.tag)).map((m) => m.tag);
|
|
143
|
-
const pending = migrations.filter((m) => !appliedTags.includes(m.tag)).map((m) => m.tag);
|
|
144
|
-
|
|
145
|
-
statusReport[db] = { applied, pending };
|
|
146
|
-
|
|
147
|
-
if (!opts.json) {
|
|
148
|
-
console.log(`\n[${db}]`);
|
|
149
|
-
if (applied.length > 0) {
|
|
150
|
-
console.log(` Applied (${applied.length}):`);
|
|
151
|
-
for (const t of applied) console.log(` + ${t}`);
|
|
152
|
-
}
|
|
153
|
-
if (pending.length > 0) {
|
|
154
|
-
console.log(` Pending (${pending.length}):`);
|
|
155
|
-
for (const t of pending) console.log(` - ${t}`);
|
|
156
|
-
}
|
|
157
|
-
if (applied.length === 0 && pending.length === 0) {
|
|
158
|
-
console.log(' No migration files found.');
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (opts.json) printJson(statusReport, true);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export async function runDbMigrateRollback(opts: MigrateRollbackOpts): Promise<void> {
|
|
167
|
-
const found = findProjectConfig();
|
|
168
|
-
if (!found) fail('No linked project. Run `ductape link` from your project directory.');
|
|
169
|
-
|
|
170
|
-
const { dir } = found;
|
|
171
|
-
const session = requireSession();
|
|
172
|
-
const proxy = getDbProxy(session);
|
|
173
|
-
const envSlug = opts.env ?? session.project.env_slug;
|
|
174
|
-
const productTag = session.project.product_tag;
|
|
175
|
-
const rollbackCount = opts.n ?? 1;
|
|
176
|
-
|
|
177
|
-
const schemaEntries = loadSchemaFile(dir);
|
|
178
|
-
const targets = opts.db ? schemaEntries.filter((e) => e.db === opts.db) : schemaEntries;
|
|
179
|
-
|
|
180
|
-
for (const entry of targets) {
|
|
181
|
-
const { db } = entry;
|
|
182
|
-
const dbContext = buildDbContext(db, envSlug, productTag);
|
|
183
|
-
const migrations = loadMigrationFiles(dir, db);
|
|
184
|
-
const appliedTags = await getAppliedTags(proxy, dbContext);
|
|
185
|
-
|
|
186
|
-
const applied = migrations.filter((m) => appliedTags.includes(m.tag));
|
|
187
|
-
const toRollback = applied.slice(-rollbackCount).reverse();
|
|
188
|
-
|
|
189
|
-
if (toRollback.length === 0) {
|
|
190
|
-
console.log(`[${db}] Nothing to roll back.`);
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
for (const migration of toRollback) {
|
|
195
|
-
process.stdout.write(` Rolling back ${migration.tag}... `);
|
|
196
|
-
try {
|
|
197
|
-
await proxy.execute(
|
|
198
|
-
'migration.rollback',
|
|
199
|
-
[[migration], 1],
|
|
200
|
-
dbContext,
|
|
201
|
-
);
|
|
202
|
-
console.log('done');
|
|
203
|
-
} catch (err) {
|
|
204
|
-
console.log('failed');
|
|
205
|
-
fail(`Rollback of "${migration.tag}" failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|