datagrok-tools 6.5.6 → 6.5.8
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/.devcontainer/docker-compose.yaml +68 -24
- package/CHANGELOG.md +41 -6
- package/CLAUDE.md +35 -10
- package/Core.json +1027 -0
- package/GROK_S.md +563 -27
- package/bin/commands/api.js +121 -70
- package/bin/commands/help.js +3 -65
- package/bin/commands/server-domains.js +468 -0
- package/bin/commands/server-migrate.js +392 -0
- package/bin/commands/server.js +455 -92
- package/bin/grok.js +16 -5
- package/bin/utils/migrate/bundle.js +223 -0
- package/bin/utils/migrate/bundle.ts +222 -0
- package/bin/utils/migrate/parts.js +83 -0
- package/bin/utils/migrate/parts.ts +72 -0
- package/bin/utils/migrate/pool.js +17 -0
- package/bin/utils/migrate/pool.ts +13 -0
- package/bin/utils/migrate/pusher.js +980 -0
- package/bin/utils/migrate/pusher.ts +829 -0
- package/bin/utils/migrate/registry.js +349 -0
- package/bin/utils/migrate/registry.ts +255 -0
- package/bin/utils/migrate/rewriter.js +59 -0
- package/bin/utils/migrate/rewriter.ts +59 -0
- package/bin/utils/migrate/walker.js +571 -0
- package/bin/utils/migrate/walker.ts +509 -0
- package/bin/utils/node-dapi.js +787 -141
- package/bin/utils/playwright-runner.js +55 -39
- package/bin/utils/server-client.js +15 -2
- package/bin/utils/server-output.js +65 -4
- package/bin/utils/test-utils.js +1 -1
- package/domain-schema.schema.json +57 -6
- package/package.json +6 -1
- /package/{vitest.config.ts → vitest.config.mts} +0 -0
package/bin/commands/server.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.HELP_SERVER = void 0;
|
|
6
7
|
exports.buildInlineManifest = buildInlineManifest;
|
|
7
8
|
exports.parseFuncCall = parseFuncCall;
|
|
8
9
|
exports.resolveManifestSources = resolveManifestSources;
|
|
@@ -12,17 +13,29 @@ var path = _interopRequireWildcard(require("path"));
|
|
|
12
13
|
var _nodeDapi = require("../utils/node-dapi");
|
|
13
14
|
var _serverClient = require("../utils/server-client");
|
|
14
15
|
var _serverOutput = require("../utils/server-output");
|
|
16
|
+
var _serverMigrate = require("./server-migrate");
|
|
17
|
+
var _serverDomains = require("./server-domains");
|
|
18
|
+
var _registry = require("../utils/migrate/registry");
|
|
19
|
+
var _walker = require("../utils/migrate/walker");
|
|
15
20
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
16
21
|
/// Docs: [Grok Dapi](/docs/plans/grok-dapi/)
|
|
17
22
|
|
|
23
|
+
/** `queries|scripts get <nqName>` resolves through `/entities`, which needs the entity type. */
|
|
24
|
+
const ENTITY_TYPES = {
|
|
25
|
+
queries: 'DataQuery',
|
|
26
|
+
scripts: 'Script',
|
|
27
|
+
reports: 'UserReport'
|
|
28
|
+
};
|
|
18
29
|
const ENTITIES = ['users', 'groups', 'functions', 'connections', 'queries', 'scripts', 'packages', 'reports', 'files', 'tables'];
|
|
19
|
-
const
|
|
30
|
+
const COMMANDS = ['shares', 'domains', 'raw', 'batch', 'describe', 'healthcheck', 'sync', 'pull', 'push', 'migrate', 'diff', 'bundle'];
|
|
31
|
+
const VERBS = ['list', 'count', 'get', 'delete'];
|
|
20
32
|
async function server(argv) {
|
|
21
33
|
const args = argv['_'].slice(1);
|
|
22
34
|
const entity = args[0];
|
|
23
35
|
const verb = args[1];
|
|
24
36
|
const rest = args.slice(2);
|
|
25
37
|
const output = argv.output ?? argv.o ?? 'table';
|
|
38
|
+
(0, _serverOutput.setOutputFormat)(output);
|
|
26
39
|
const limit = Number(argv.limit ?? argv.l ?? 50);
|
|
27
40
|
const offset = Number(argv.offset ?? 0);
|
|
28
41
|
const filter = argv.filter ?? argv.f ?? '';
|
|
@@ -34,24 +47,40 @@ async function server(argv) {
|
|
|
34
47
|
}
|
|
35
48
|
let client;
|
|
36
49
|
try {
|
|
37
|
-
client = await (0, _serverClient.createClient)(host);
|
|
50
|
+
client = await (0, _serverClient.createClient)(host, !!argv.admin);
|
|
38
51
|
} catch (err) {
|
|
52
|
+
// a bad alias, URL or key is not a usage error: no help dump, just the reason
|
|
39
53
|
(0, _serverOutput.printError)(err);
|
|
40
|
-
|
|
54
|
+
process.exitCode = 1;
|
|
55
|
+
return true;
|
|
41
56
|
}
|
|
42
57
|
const dapi = new _nodeDapi.NodeDapi(client);
|
|
43
58
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
if (entity === '
|
|
48
|
-
if (entity === '
|
|
49
|
-
if (entity === '
|
|
50
|
-
if (entity === '
|
|
59
|
+
// await each handler so a rejection lands in the catch below instead of
|
|
60
|
+
// escaping to grok.js as an unhandled rejection (stack trace + exit 255)
|
|
61
|
+
if (['pull', 'push', 'migrate', 'diff', 'bundle'].includes(entity)) return await (0, _serverMigrate.handleMigrate)(dapi, entity, [verb, ...rest].filter(Boolean), argv, output);
|
|
62
|
+
if (entity === 'domains') return await (0, _serverDomains.handleDomains)(dapi, verb, rest, argv, output);
|
|
63
|
+
if (entity === 'batch') return await handleBatch(dapi, argv, verb, rest, output);
|
|
64
|
+
if (entity === 'raw') return await handleRaw(dapi, verb, rest, argv, output);
|
|
65
|
+
if (entity === 'describe') return await handleDescribe(dapi, verb ?? rest[0], output);
|
|
66
|
+
if (entity === 'healthcheck') return await handleHealthcheck(dapi, argv, output);
|
|
67
|
+
if (entity === 'sync') return await handleSync(dapi, verb, rest, argv, output);
|
|
68
|
+
if (entity === 'functions' && verb === 'run') return await handleFuncRun(dapi, rest, argv, output);
|
|
69
|
+
if (entity === 'functions' && verb === 'list') return await handleFunctionsList(dapi, argv, limit, offset, filter, output);
|
|
51
70
|
if (entity === 'files' && verb === 'list') {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
71
|
+
if (!rest[0]) {
|
|
72
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s files list <connector>[/<path>] [-r]\n e.g. grok s files list "System:AppData" -r'));
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const files = await dapi.files.list(String(rest[0]), recursive);
|
|
76
|
+
if (output === 'json') (0, _serverOutput.printOutput)(files, output);else if (output === 'quiet') {
|
|
77
|
+
for (const f of files) console.log(f.path);
|
|
78
|
+
} else (0, _serverOutput.printOutput)(files.map(f => ({
|
|
79
|
+
path: f.path,
|
|
80
|
+
kind: f.isFile ? 'file' : 'dir',
|
|
81
|
+
size: f.isFile ? f.size ?? '' : '',
|
|
82
|
+
updatedOn: f.updatedOn ?? ''
|
|
83
|
+
})), output);
|
|
55
84
|
return true;
|
|
56
85
|
}
|
|
57
86
|
if (entity === 'files' && verb === 'get') {
|
|
@@ -64,24 +93,30 @@ async function server(argv) {
|
|
|
64
93
|
if (output !== 'quiet') console.log(`Deleted ${rest[0]}`);
|
|
65
94
|
return true;
|
|
66
95
|
}
|
|
67
|
-
if (entity === 'files' && verb === 'put') return handleFilesPut(dapi, rest, output);
|
|
68
|
-
if (entity === 'shares' && verb === 'add') return handleSharesAdd(dapi, rest, argv, output);
|
|
69
|
-
if (entity === 'shares' && verb === 'list') return handleSharesList(dapi, rest, output);
|
|
70
|
-
if (entity === 'users' && verb === 'save') return handleUserSave(dapi, argv, output);
|
|
71
|
-
if (entity === 'groups' && verb === 'save') return handleGroupSave(dapi, argv, output);
|
|
72
|
-
if (entity === 'connections' && verb === 'save') return handleConnSave(dapi, argv, output);
|
|
73
|
-
if (entity === 'connections' && verb === 'test') return handleConnTest(dapi, rest, argv, output);
|
|
74
|
-
if (entity === 'groups' && verb === 'add-members') return handleGroupAddMembers(dapi, rest, argv, output);
|
|
75
|
-
if (entity === 'groups' && verb === 'remove-members') return handleGroupRemoveMembers(dapi, rest, argv, output);
|
|
76
|
-
if (entity === 'groups' && verb === 'list-members') return handleGroupListMembers(dapi, rest, argv, output);
|
|
77
|
-
if (entity === '
|
|
78
|
-
if (entity === 'users' && verb === '
|
|
79
|
-
if (entity === '
|
|
80
|
-
if (entity === 'tables' && verb === '
|
|
81
|
-
if (entity === '
|
|
96
|
+
if (entity === 'files' && verb === 'put') return await handleFilesPut(dapi, rest, output);
|
|
97
|
+
if (entity === 'shares' && verb === 'add') return await handleSharesAdd(dapi, rest, argv, output);
|
|
98
|
+
if (entity === 'shares' && verb === 'list') return await handleSharesList(dapi, rest, output);
|
|
99
|
+
if (entity === 'users' && verb === 'save') return await handleUserSave(dapi, argv, output);
|
|
100
|
+
if (entity === 'groups' && verb === 'save') return await handleGroupSave(dapi, argv, output);
|
|
101
|
+
if (entity === 'connections' && verb === 'save') return await handleConnSave(dapi, argv, output);
|
|
102
|
+
if (entity === 'connections' && verb === 'test') return await handleConnTest(dapi, rest, argv, output);
|
|
103
|
+
if (entity === 'groups' && verb === 'add-members') return await handleGroupAddMembers(dapi, rest, argv, output);
|
|
104
|
+
if (entity === 'groups' && verb === 'remove-members') return await handleGroupRemoveMembers(dapi, rest, argv, output);
|
|
105
|
+
if (entity === 'groups' && (verb === 'list-members' || verb === 'list-memberships')) return await handleGroupListMembers(dapi, verb, rest, argv, output);
|
|
106
|
+
if (entity === 'users' && verb === 'block') return await handleUserBlock(dapi, rest, output);
|
|
107
|
+
if (entity === 'users' && verb === 'unblock') return await handleUserUnblock(dapi, rest, output);
|
|
108
|
+
if (entity === 'tables' && verb === 'download') return await handleTablesDownload(dapi, rest, argv, output);
|
|
109
|
+
if (entity === 'tables' && verb === 'upload') return await handleTablesUpload(dapi, rest, output);
|
|
110
|
+
if (entity === 'packages' && verb === 'install') return await handlePackagesInstall(dapi, rest, argv, output);
|
|
111
|
+
if (entity === 'packages' && verb === 'uninstall') return await handlePackagesUninstall(dapi, rest, output);
|
|
112
|
+
if (entity === 'packages' && verb === 'share') return await handlePackagesShare(dapi, rest, argv, output);
|
|
113
|
+
if (entity === 'packages' && verb === 'versions') return await handlePackagesVersions(dapi, rest, output);
|
|
114
|
+
if (entity === 'packages' && verb === 'set-version') return await handlePackagesSetVersion(dapi, rest, output);
|
|
115
|
+
if (entity === 'packages' && verb === 'outdated') return await handlePackagesOutdated(dapi, output);
|
|
116
|
+
if (entity === 'packages' && verb === 'update') return await handlePackagesUpdate(dapi, rest, argv, output);
|
|
82
117
|
const source = dapi[entity];
|
|
83
118
|
if (!source || !ENTITIES.includes(entity)) {
|
|
84
|
-
(0, _serverOutput.printError)(new Error(`Unknown
|
|
119
|
+
(0, _serverOutput.printError)(new Error(`Unknown command '${entity}'. Entities: ${ENTITIES.join(', ')}. Other commands: ${COMMANDS.join(', ')}. See grok s --help`));
|
|
85
120
|
return false;
|
|
86
121
|
}
|
|
87
122
|
if (!verb) {
|
|
@@ -89,17 +124,30 @@ async function server(argv) {
|
|
|
89
124
|
return true;
|
|
90
125
|
}
|
|
91
126
|
if (verb === 'list') {
|
|
92
|
-
const
|
|
93
|
-
|
|
127
|
+
const results = source instanceof _nodeDapi.InternalDataSource ? await source.list({
|
|
128
|
+
text: filter || undefined,
|
|
129
|
+
limit,
|
|
130
|
+
page: Math.floor(offset / limit) + 1
|
|
131
|
+
}) : await source.filter(filter).by(limit).page(Math.floor(offset / limit)).list();
|
|
94
132
|
(0, _serverOutput.printOutput)(results, output);
|
|
95
133
|
return true;
|
|
96
134
|
}
|
|
135
|
+
if (verb === 'count') {
|
|
136
|
+
if (entity === 'reports') throw new Error('The server has no count endpoint for reports; use `grok s reports list --output quiet | wc -l`');
|
|
137
|
+
const n = source instanceof _nodeDapi.InternalDataSource ? await source.count({
|
|
138
|
+
text: filter || undefined
|
|
139
|
+
}) : await source.filter(filter).count();
|
|
140
|
+
(0, _serverOutput.printOutput)(n, output);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
97
143
|
if (verb === 'get') {
|
|
98
144
|
if (!rest[0]) {
|
|
99
145
|
(0, _serverOutput.printError)(new Error('Usage: grok s <entity> get <id>'));
|
|
100
146
|
return false;
|
|
101
147
|
}
|
|
102
|
-
|
|
148
|
+
// The internal routers find by id only; a name has to be resolved through /entities first.
|
|
149
|
+
const id = source instanceof _nodeDapi.InternalDataSource && !(0, _registry.isUuid)(rest[0]) ? (await (0, _walker.resolveEntity)(dapi, rest[0], ENTITY_TYPES[entity])).id : rest[0];
|
|
150
|
+
const result = await source.find(id);
|
|
103
151
|
(0, _serverOutput.printOutput)(result, output);
|
|
104
152
|
return true;
|
|
105
153
|
}
|
|
@@ -112,11 +160,17 @@ async function server(argv) {
|
|
|
112
160
|
if (output !== 'quiet') console.log(`Deleted ${entity}/${rest[0]}`);
|
|
113
161
|
return true;
|
|
114
162
|
}
|
|
115
|
-
|
|
163
|
+
const extraVerbs = entity === 'packages' ? ', install, uninstall, update, outdated, versions, set-version, share' : '';
|
|
164
|
+
(0, _serverOutput.printError)(new Error(`Unknown verb: '${verb}'. Valid: ${VERBS.join(', ')}${extraVerbs}`));
|
|
116
165
|
return false;
|
|
117
166
|
} catch (err) {
|
|
118
|
-
|
|
119
|
-
|
|
167
|
+
// A runtime failure is not a usage error: report it and exit non-zero without
|
|
168
|
+
// making grok.js dump the help block (which it does for every `false` result).
|
|
169
|
+
(0, _serverOutput.printError)(err, {
|
|
170
|
+
verbose: !!argv.verbose
|
|
171
|
+
});
|
|
172
|
+
process.exitCode = 1;
|
|
173
|
+
return true;
|
|
120
174
|
}
|
|
121
175
|
}
|
|
122
176
|
async function handleFilesPut(dapi, rest, output) {
|
|
@@ -168,6 +222,208 @@ async function handleTablesDownload(dapi, rest, argv, output) {
|
|
|
168
222
|
} else process.stdout.write(csv);
|
|
169
223
|
return true;
|
|
170
224
|
}
|
|
225
|
+
async function installPackages(dapi, targets, output) {
|
|
226
|
+
const results = [];
|
|
227
|
+
for (const t of targets) {
|
|
228
|
+
let name = t.name;
|
|
229
|
+
try {
|
|
230
|
+
const pkg = await dapi.packages.resolve(t.name);
|
|
231
|
+
if (pkg) name = pkg.name;
|
|
232
|
+
if (output === 'table') console.log(`Installing ${name} (${t.version})...`);
|
|
233
|
+
const id = await dapi.packages.install(name, t.version);
|
|
234
|
+
// the server returns the published id for any existing explicit version
|
|
235
|
+
// (even an already-current one), so null means the version doesn't exist
|
|
236
|
+
if (!id && t.version !== 'latest') results.push({
|
|
237
|
+
package: name,
|
|
238
|
+
version: t.version,
|
|
239
|
+
status: 'error',
|
|
240
|
+
error: `Version '${t.version}' not found`
|
|
241
|
+
});else results.push({
|
|
242
|
+
package: name,
|
|
243
|
+
version: t.version,
|
|
244
|
+
status: id ? 'installed' : 'noop',
|
|
245
|
+
id: id ?? undefined
|
|
246
|
+
});
|
|
247
|
+
} catch (err) {
|
|
248
|
+
results.push({
|
|
249
|
+
package: name,
|
|
250
|
+
version: t.version,
|
|
251
|
+
status: 'error',
|
|
252
|
+
error: (err?.message ?? String(err)).replace(/\s*\n\s*/g, '; ')
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return results;
|
|
257
|
+
}
|
|
258
|
+
function printPackageOps(results, output) {
|
|
259
|
+
if (output === 'quiet') {
|
|
260
|
+
for (const r of results) if (r.id) console.log(r.id);
|
|
261
|
+
} else (0, _serverOutput.printOutput)(results, output);
|
|
262
|
+
if (results.some(r => r.status === 'error')) process.exitCode = 1;
|
|
263
|
+
}
|
|
264
|
+
async function handlePackagesInstall(dapi, rest, argv, output) {
|
|
265
|
+
if (!rest.length) {
|
|
266
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s packages install <name> [<name> ...] [--version <v>]'));
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
if (argv.version !== undefined && rest.length > 1) {
|
|
270
|
+
(0, _serverOutput.printError)(new Error('--version applies to a single package'));
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
const version = argv.version !== undefined ? String(argv.version) : 'latest';
|
|
274
|
+
const results = await installPackages(dapi, rest.map(r => ({
|
|
275
|
+
name: String(r),
|
|
276
|
+
version
|
|
277
|
+
})), output);
|
|
278
|
+
printPackageOps(results, output);
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
async function handlePackagesUninstall(dapi, rest, output) {
|
|
282
|
+
if (!rest[0]) {
|
|
283
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s packages uninstall <name-or-id>'));
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
const result = await dapi.packages.uninstall(rest[0]);
|
|
287
|
+
if (output === 'json' || output === 'csv') (0, _serverOutput.printOutput)(result, output);else if (output === 'quiet') console.log(result.id);else console.log(result.repoBacked ? `Uninstalled ${result.name} (package entry kept — reinstall with 'grok s packages install ${result.name}')` : `Deleted local package ${result.name}`);
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
async function handlePackagesShare(dapi, rest, argv, output) {
|
|
291
|
+
const [name, ...groupArgs] = rest;
|
|
292
|
+
if (!name || !groupArgs.length) {
|
|
293
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s packages share <name-or-id> <group>[,<group>...] [--access View|Edit]'));
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
const groups = groupArgs.flatMap(g => g.split(',')).map(g => g.trim()).filter(Boolean).join(',');
|
|
297
|
+
const access = typeof argv.access === 'string' ? argv.access : 'View';
|
|
298
|
+
if (access !== 'View' && access !== 'Edit') {
|
|
299
|
+
(0, _serverOutput.printError)(new Error(`Invalid --access '${access}'. Use 'View' or 'Edit'.`));
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
const pkg = await dapi.packages.resolve(name);
|
|
303
|
+
if (!pkg) {
|
|
304
|
+
(0, _serverOutput.printError)(new Error(`Package '${name}' not found`));
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
const result = await dapi.shares.share(pkg.id, groups, access);
|
|
308
|
+
(0, _serverOutput.printOutput)(result, output);
|
|
309
|
+
if (result?.status === 'failed') process.exitCode = 1;
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
async function handlePackagesVersions(dapi, rest, output) {
|
|
313
|
+
if (!rest[0]) {
|
|
314
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s packages versions <name-or-id>'));
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
const versions = await dapi.packages.versions(rest[0]);
|
|
318
|
+
const flat = versions.map(v => ({
|
|
319
|
+
version: v?.version ?? '',
|
|
320
|
+
current: v?.isCurrent ?? false,
|
|
321
|
+
latest: v?.isLatest ?? false,
|
|
322
|
+
local: v?.isLocal ?? false,
|
|
323
|
+
remote: v?.isRemote ?? false,
|
|
324
|
+
debug: v?.debug ?? false,
|
|
325
|
+
id: v?.id ?? ''
|
|
326
|
+
}));
|
|
327
|
+
(0, _serverOutput.printOutput)(flat, output);
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
async function handlePackagesSetVersion(dapi, rest, output) {
|
|
331
|
+
if (!rest[0] || rest[1] === undefined) {
|
|
332
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s packages set-version <name> <version>'));
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
const version = String(rest[1]);
|
|
336
|
+
const pkg = await dapi.packages.resolve(String(rest[0]));
|
|
337
|
+
const name = pkg?.name ?? String(rest[0]);
|
|
338
|
+
const id = await dapi.packages.install(name, version);
|
|
339
|
+
if (!id) {
|
|
340
|
+
(0, _serverOutput.printError)(new Error(`Version '${version}' not found for package '${name}'`));
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
if (output === 'quiet') console.log(id);else if (output === 'json' || output === 'csv') (0, _serverOutput.printOutput)({
|
|
344
|
+
package: name,
|
|
345
|
+
version,
|
|
346
|
+
id
|
|
347
|
+
}, output);else console.log(`${name} -> ${version} (published package ${id})`);
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
async function handlePackagesOutdated(dapi, output) {
|
|
351
|
+
const rows = await dapi.packages.outdated();
|
|
352
|
+
if (!rows.length && output === 'table') {
|
|
353
|
+
console.log('All packages up to date.');
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
(0, _serverOutput.printOutput)(rows, output);
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
async function handlePackagesUpdate(dapi, rest, argv, output) {
|
|
360
|
+
const all = argv.all === true;
|
|
361
|
+
if (!all && !rest.length) {
|
|
362
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s packages update <name> [<name> ...] | --all'));
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
const outdated = await dapi.packages.outdated();
|
|
366
|
+
const results = [];
|
|
367
|
+
// a package tracking 'latest' keeps that auto-update intent; a pinned one gets
|
|
368
|
+
// pinned to the concrete registry-latest version
|
|
369
|
+
const targetVersion = o => o.desiredVersion === 'latest' ? 'latest' : o.latest;
|
|
370
|
+
let targets;
|
|
371
|
+
if (all) {
|
|
372
|
+
targets = outdated.map(o => ({
|
|
373
|
+
name: o.name,
|
|
374
|
+
version: targetVersion(o)
|
|
375
|
+
}));
|
|
376
|
+
if (!targets.length && output === 'table') {
|
|
377
|
+
console.log('All packages up to date.');
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
} else {
|
|
381
|
+
targets = [];
|
|
382
|
+
for (const r of rest) {
|
|
383
|
+
const raw = String(r);
|
|
384
|
+
let pkg = null;
|
|
385
|
+
try {
|
|
386
|
+
pkg = await dapi.packages.resolve(raw);
|
|
387
|
+
} catch (err) {
|
|
388
|
+
results.push({
|
|
389
|
+
package: raw,
|
|
390
|
+
version: '',
|
|
391
|
+
status: 'error',
|
|
392
|
+
error: (err?.message ?? String(err)).replace(/\s*\n\s*/g, '; ')
|
|
393
|
+
});
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (!pkg) {
|
|
397
|
+
results.push({
|
|
398
|
+
package: raw,
|
|
399
|
+
version: '',
|
|
400
|
+
status: 'error',
|
|
401
|
+
error: 'Package not found'
|
|
402
|
+
});
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const o = outdated.find(x => x.name === pkg.name);
|
|
406
|
+
if (o) {
|
|
407
|
+
targets.push({
|
|
408
|
+
name: pkg.name,
|
|
409
|
+
version: targetVersion(o)
|
|
410
|
+
});
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
const versions = Array.isArray(pkg.publishedVersions) ? pkg.publishedVersions : [];
|
|
414
|
+
const installed = versions.some(v => v?.isCurrent && !v?.debug);
|
|
415
|
+
results.push({
|
|
416
|
+
package: pkg.name,
|
|
417
|
+
version: '',
|
|
418
|
+
status: 'noop',
|
|
419
|
+
note: installed ? 'already up to date' : 'not installed'
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
results.push(...(await installPackages(dapi, targets, output)));
|
|
424
|
+
printPackageOps(results, output);
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
171
427
|
async function handleTablesUpload(dapi, rest, output) {
|
|
172
428
|
const [name, localPath] = rest;
|
|
173
429
|
if (!name || !localPath) {
|
|
@@ -226,13 +482,20 @@ async function handleFunctionsList(dapi, argv, limit, offset, userFilter, output
|
|
|
226
482
|
(0, _serverOutput.printOutput)(results, output);
|
|
227
483
|
return true;
|
|
228
484
|
}
|
|
229
|
-
async function handleRaw(dapi, method, rest, output) {
|
|
485
|
+
async function handleRaw(dapi, method, rest, argv, output) {
|
|
230
486
|
if (!method || !rest[0]) {
|
|
231
|
-
(0, _serverOutput.printError)(new Error('Usage: grok s raw <METHOD> <path>'));
|
|
487
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s raw <METHOD> <path> [--json body.json | --data \'{"k": 1}\']\n e.g. grok s raw GET /users/current (paths are API-relative; a leading /api is accepted)'));
|
|
232
488
|
return false;
|
|
233
489
|
}
|
|
234
|
-
|
|
235
|
-
|
|
490
|
+
let body;
|
|
491
|
+
if (argv.json) body = readJsonFile(argv.json);else if (argv.data !== undefined) {
|
|
492
|
+
try {
|
|
493
|
+
body = JSON.parse(String(argv.data));
|
|
494
|
+
} catch {
|
|
495
|
+
body = String(argv.data);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
const result = await dapi.raw(method, String(rest[0]), body);
|
|
236
499
|
(0, _serverOutput.printOutput)(result, output);
|
|
237
500
|
return true;
|
|
238
501
|
}
|
|
@@ -242,21 +505,15 @@ async function handleSync(dapi, subject, rest, argv, output) {
|
|
|
242
505
|
// runs are read-only here; `run` triggers an actual push and prints
|
|
243
506
|
// the per-item summary. Full reference in
|
|
244
507
|
// core/docs/plans/instance-sync.md (Phase 7 / operational polish).
|
|
245
|
-
//
|
|
246
|
-
// `_callSync` does dual-path routing: tries `/api/sync/...` first
|
|
247
|
-
// (nginx-fronted deployments) and falls back to `/sync/...` (bare
|
|
248
|
-
// datlas on :8082). Same approach as the server-side handshake
|
|
249
|
-
// code so the CLI works against either layout.
|
|
250
508
|
const verb = rest[0];
|
|
509
|
+
// a 1.27 server has no /sync routes at all: report that as "not found", not as a failure
|
|
251
510
|
const callSync = async (method, path, body) => {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (r && (Array.isArray(r) || typeof r === 'object') && r['#type'] !== 'ApiError') return r;
|
|
511
|
+
try {
|
|
512
|
+
return await dapi.raw(method, path, body);
|
|
513
|
+
} catch (err) {
|
|
514
|
+
if (err?.apiError?.errorCode === 404) return null;
|
|
515
|
+
throw err;
|
|
258
516
|
}
|
|
259
|
-
return null;
|
|
260
517
|
};
|
|
261
518
|
if (subject === 'pairs' && verb === 'list') {
|
|
262
519
|
const status = argv.status ? `?status=${encodeURIComponent(argv.status)}` : '';
|
|
@@ -321,8 +578,9 @@ async function handleSync(dapi, subject, rest, argv, output) {
|
|
|
321
578
|
}
|
|
322
579
|
async function handleHealthcheck(dapi, argv, output) {
|
|
323
580
|
const module = argv.module;
|
|
324
|
-
const path = module ? `/
|
|
325
|
-
const result = await dapi.
|
|
581
|
+
const path = module ? `/public/v1/healthcheck?module=${encodeURIComponent(module)}` : '/public/v1/healthcheck';
|
|
582
|
+
const result = await dapi.client.get(path);
|
|
583
|
+
const services = Array.isArray(result?.services) ? result.services : [];
|
|
326
584
|
if (output === 'json') {
|
|
327
585
|
(0, _serverOutput.printOutput)(result, output);
|
|
328
586
|
return true;
|
|
@@ -334,16 +592,25 @@ async function handleHealthcheck(dapi, argv, output) {
|
|
|
334
592
|
console.log(`time: ${result?.time ?? ''}`);
|
|
335
593
|
console.log('');
|
|
336
594
|
}
|
|
337
|
-
(0, _serverOutput.printOutput)(
|
|
595
|
+
if (services.length) (0, _serverOutput.printOutput)(services, output);else if (module) throw new Error(`Module '${module}' is not reported by the server`);else if (output !== 'quiet') console.log('(no services reported)');
|
|
338
596
|
return true;
|
|
339
597
|
}
|
|
340
598
|
async function handleDescribe(dapi, entityType, output) {
|
|
341
599
|
if (!entityType) {
|
|
342
|
-
(0, _serverOutput.printError)(new Error('Usage: grok s describe <entity
|
|
600
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s describe <entity|type> e.g. grok s describe connections, grok s describe Project'));
|
|
343
601
|
return false;
|
|
344
602
|
}
|
|
345
|
-
const result = await dapi.describe(entityType);
|
|
346
|
-
(
|
|
603
|
+
const result = await dapi.describe(String(entityType));
|
|
604
|
+
if (output === 'json') {
|
|
605
|
+
(0, _serverOutput.printOutput)(result, output);
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
if (output !== 'quiet' && result.type) console.log(`${result.type.name}${result.type.friendlyName && result.type.friendlyName !== result.type.name ? ` (${result.type.friendlyName})` : ''} id ${result.type.id}${result.type.isPackageEntity ? ' package entity' : ''}\n`);
|
|
609
|
+
if (!result.fields.length) {
|
|
610
|
+
if (output !== 'quiet') console.log('(no entity of this type exists on the server to derive the fields from)');
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
(0, _serverOutput.printOutput)(output === 'quiet' ? result.fields.map(f => f.field) : result.fields, output);
|
|
347
614
|
return true;
|
|
348
615
|
}
|
|
349
616
|
async function handleFuncRun(dapi, rest, argv, output) {
|
|
@@ -365,6 +632,7 @@ async function handleFuncRun(dapi, rest, argv, output) {
|
|
|
365
632
|
const parsed = parseFuncCall(funcName);
|
|
366
633
|
funcName = parsed.name;
|
|
367
634
|
params = parsed.params;
|
|
635
|
+
if (Object.keys(params).some(k => /^\d+$/.test(k))) params = (0, _nodeDapi.mapPositionalParams)(params, (await dapi.functions.find(funcName))?.parameterInfos, funcName);
|
|
368
636
|
}
|
|
369
637
|
const result = await dapi.functions.run(funcName, params);
|
|
370
638
|
(0, _serverOutput.printOutput)(result, output);
|
|
@@ -399,18 +667,25 @@ async function handleSharesAdd(dapi, rest, argv, output) {
|
|
|
399
667
|
return true;
|
|
400
668
|
}
|
|
401
669
|
async function handleSharesList(dapi, rest, output) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
(0, _serverOutput.printError)(new Error('Usage: grok s shares list <entity-id> (entity id must be a UUID)'));
|
|
670
|
+
if (!rest[0]) {
|
|
671
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s shares list <entity-id-or-name> e.g. grok s shares list "Admin:MyConnection"'));
|
|
405
672
|
return false;
|
|
406
673
|
}
|
|
674
|
+
const entityId = (0, _registry.isUuid)(String(rest[0])) ? String(rest[0]) : (await (0, _walker.resolveEntity)(dapi, String(rest[0]))).id;
|
|
407
675
|
const perms = await dapi.shares.list(entityId);
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
676
|
+
// the permissions route returns group ids only; a share touches a handful of groups
|
|
677
|
+
const groups = new Map();
|
|
678
|
+
for (const id of new Set(perms.map(p => p?.userGroup?.id).filter(Boolean))) groups.set(id, await dapi.groups.find(id));
|
|
679
|
+
const flat = perms.map(p => {
|
|
680
|
+
const g = groups.get(p?.userGroup?.id) ?? p?.userGroup ?? {};
|
|
681
|
+
return {
|
|
682
|
+
group: g.friendlyName ?? g.name ?? g.id ?? '',
|
|
683
|
+
groupId: g.id ?? '',
|
|
684
|
+
access: p?.permission?.name ?? p?.permission?.friendlyName ?? '',
|
|
685
|
+
personal: g.personal ?? false,
|
|
686
|
+
inherited: p?.inheritedByLink === true
|
|
687
|
+
};
|
|
688
|
+
});
|
|
414
689
|
(0, _serverOutput.printOutput)(flat, output);
|
|
415
690
|
return true;
|
|
416
691
|
}
|
|
@@ -502,23 +777,14 @@ async function handleGroupRemoveMembers(dapi, rest, argv, output) {
|
|
|
502
777
|
if (anyError) process.exitCode = 1;
|
|
503
778
|
return true;
|
|
504
779
|
}
|
|
505
|
-
async function handleGroupListMembers(dapi, rest, argv, output) {
|
|
506
|
-
if (!rest[0]) {
|
|
507
|
-
(0, _serverOutput.printError)(new Error('Usage: grok s groups list-members <group> [--admin | --no-admin]'));
|
|
508
|
-
return false;
|
|
509
|
-
}
|
|
510
|
-
const admin = typeof argv.admin === 'boolean' ? argv.admin : undefined;
|
|
511
|
-
const result = await dapi.groups.getMembers(rest[0], admin);
|
|
512
|
-
(0, _serverOutput.printOutput)(result, output);
|
|
513
|
-
return true;
|
|
514
|
-
}
|
|
515
|
-
async function handleGroupListMemberships(dapi, rest, argv, output) {
|
|
780
|
+
async function handleGroupListMembers(dapi, verb, rest, argv, output) {
|
|
516
781
|
if (!rest[0]) {
|
|
517
|
-
(0, _serverOutput.printError)(new Error(
|
|
782
|
+
(0, _serverOutput.printError)(new Error(`Usage: grok s groups ${verb} <group-or-login> [--admin | --no-admin] [--user]`));
|
|
518
783
|
return false;
|
|
519
784
|
}
|
|
520
785
|
const admin = typeof argv.admin === 'boolean' ? argv.admin : undefined;
|
|
521
|
-
const
|
|
786
|
+
const personalOnly = argv.user === true;
|
|
787
|
+
const result = verb === 'list-members' ? await dapi.groups.getMembers(String(rest[0]), admin, personalOnly) : await dapi.groups.getMemberships(String(rest[0]), admin, personalOnly);
|
|
522
788
|
(0, _serverOutput.printOutput)(result, output);
|
|
523
789
|
return true;
|
|
524
790
|
}
|
|
@@ -655,7 +921,7 @@ function parseFuncCall(expr) {
|
|
|
655
921
|
params: Object.fromEntries(positional.map((v, i) => [String(i), v]))
|
|
656
922
|
};
|
|
657
923
|
}
|
|
658
|
-
const HELP_SERVER = `
|
|
924
|
+
const HELP_SERVER = exports.HELP_SERVER = `
|
|
659
925
|
Usage: grok server <entity> <verb> [args] [options]
|
|
660
926
|
grok s <entity> <verb> [args] [options]
|
|
661
927
|
|
|
@@ -663,27 +929,29 @@ Manage a Datagrok server from the command line.
|
|
|
663
929
|
|
|
664
930
|
Entities:
|
|
665
931
|
users, groups, functions, connections, queries, scripts, packages, reports, files, tables
|
|
932
|
+
(plus domains, shares, batch, raw, describe, healthcheck, sync, pull/push/migrate/diff/bundle below)
|
|
666
933
|
|
|
667
934
|
Verbs:
|
|
668
|
-
list List entities
|
|
935
|
+
list List entities (--filter, --limit, --offset)
|
|
936
|
+
count Count entities (--filter)
|
|
669
937
|
get Get a single entity by ID or name
|
|
670
|
-
delete Delete an entity by ID
|
|
938
|
+
delete Delete an entity by ID or name (users cannot be deleted: block them; functions: scripts and queries only)
|
|
671
939
|
|
|
672
940
|
Special commands:
|
|
673
|
-
grok s functions run <Name:func(args)> Call a function
|
|
941
|
+
grok s functions run <Name:func(args)> Call a function (positional args map onto its inputs)
|
|
674
942
|
grok s functions list [--type <t>] [--language <l>] [--package <p>] [--filter <expr>]
|
|
675
943
|
Type: script|query|function|package
|
|
676
944
|
Language applies to scripts (python, r, julia, nodejs, octave, grok)
|
|
677
|
-
grok s files list <path> [-r]
|
|
945
|
+
grok s files list <connector>[/<path>] [-r] List a share (recursive with -r): path, kind, size
|
|
678
946
|
grok s files get <path> Download a file (returns bytes)
|
|
679
947
|
grok s files delete <path> Delete a file
|
|
680
948
|
grok s files put <local> <remote> Upload a local file
|
|
681
|
-
grok s raw <METHOD> <path>
|
|
682
|
-
grok s describe <entity
|
|
949
|
+
grok s raw <METHOD> <path> [--json f | --data j] Any API endpoint; path is API-relative (/users/current), /api prefix optional
|
|
950
|
+
grok s describe <entity|type> Fields of an entity type (registry record + a live sample)
|
|
683
951
|
grok s healthcheck [--module <name>] Check server + per-module health
|
|
684
952
|
grok s shares add <entity> <group>[,<group>...] [--access View|Edit]
|
|
685
953
|
Share an entity with one or more groups
|
|
686
|
-
grok s shares list <entity-id>
|
|
954
|
+
grok s shares list <entity-id-or-name> List who an entity is shared with
|
|
687
955
|
grok s users save --json user.json Create or update a user from a JSON file
|
|
688
956
|
grok s groups save --json group.json [--save-relations]
|
|
689
957
|
Create or update a group from a JSON file
|
|
@@ -693,12 +961,47 @@ Special commands:
|
|
|
693
961
|
grok s connections test --json conn.json Test connectivity of a connection defined in JSON
|
|
694
962
|
grok s groups add-members <group> <m>... [--admin] Add one or more users/groups as members
|
|
695
963
|
grok s groups remove-members <group> <m>... Remove members (no-op if not a member)
|
|
696
|
-
grok s groups list-members <group> [--admin]
|
|
697
|
-
|
|
964
|
+
grok s groups list-members <group> [--admin] [--user]
|
|
965
|
+
List members (optionally filter by admin; --user: personal group)
|
|
966
|
+
grok s groups list-memberships <group> [--admin] [--user]
|
|
967
|
+
List parent groups
|
|
698
968
|
grok s users block <id-or-login> Block a user from the platform
|
|
699
969
|
grok s users unblock <id-or-login> Unblock a previously blocked user
|
|
700
970
|
grok s tables upload <name> <file.csv|file.d42> Upload a CSV or d42 binary as a Datagrok table
|
|
701
|
-
grok s tables download <name
|
|
971
|
+
grok s tables download <name|Project:Table|id> [-O <file>]
|
|
972
|
+
Download a table as CSV (stdout by default)
|
|
973
|
+
grok s packages install <name>... [--version <v>] Install latest (or pinned) versions from the registry
|
|
974
|
+
grok s packages uninstall <name> Uninstall a package (repository entry is kept)
|
|
975
|
+
grok s packages update <name>... | --all Upgrade to the latest registry version
|
|
976
|
+
grok s packages outdated Show installed vs latest registry versions
|
|
977
|
+
grok s packages versions <name> List published versions (current/latest/debug flags)
|
|
978
|
+
grok s packages set-version <name> <version> Activate a specific published version
|
|
979
|
+
grok s packages share <name> <group>[,...] [--access View|Edit]
|
|
980
|
+
Share a package with one or more groups
|
|
981
|
+
grok s pull [<nqName|id>...] --out <dir> Export entities into a bundle directory
|
|
982
|
+
grok s push <bundle-dir> [--dry-run] Import a bundle into the target server
|
|
983
|
+
grok s migrate <selection> --from <a> --to <b> Pull from one instance and push into another
|
|
984
|
+
grok s diff <bundle-dir> What a push would change (read-only, plans with skip)
|
|
985
|
+
grok s bundle ls <bundle-dir> List what a bundle contains
|
|
986
|
+
grok s domains list [<schema>] [--filter <text>] Domain schemas, or the tables of one schema
|
|
987
|
+
grok s domains get <schema>|<schema.table> [<id>] Manifest, a table's columns, or one row
|
|
988
|
+
grok s domains query <schema.table> [--filter <expr>] [--columns a,b] [--sort 'a,!b'] [--expand x] [--limit n] [--offset n]
|
|
989
|
+
grok s domains count <schema.table> [--filter <expr>]
|
|
990
|
+
grok s domains insert <schema.table> --json rows.json | col=value ... [--error-on-duplicate]
|
|
991
|
+
grok s domains update <schema.table> <id> --json values.json | col=value ... [--version n]
|
|
992
|
+
grok s domains delete <schema.table> <id> | --filter <expr> [--limit n]
|
|
993
|
+
grok s domains delete <schema> --force Purge a user-managed schema with its data
|
|
994
|
+
grok s domains upload <schema.table> <file.csv|.d42|.json> [--upsert] [--no-all-or-nothing] [--error-on-duplicate]
|
|
995
|
+
grok s domains download <schema.table> [-O out.csv|out.d42] [--filter <expr>] [--columns a,b] [--sort s]
|
|
996
|
+
grok s domains aggregate <schema.table> --measures 'count,sum(x) as t' [--group-by a,b] [--filter <expr>]
|
|
997
|
+
grok s domains transaction <schema> --json ops.json Ordered insert/update/delete ops, atomically
|
|
998
|
+
grok s domains audit <schema>|<schema.table> [<id>] [--limit n]
|
|
999
|
+
grok s domains capabilities <schema.table> What the current user may do on the table
|
|
1000
|
+
grok s domains grants <schema>|<schema.table> Direct permission grants on a schema or table
|
|
1001
|
+
grok s domains grant <schema>|<schema.table> <group>[,...] [--access View|Edit|Delete|Share|Extend]
|
|
1002
|
+
grok s domains revoke <schema>|<schema.table> <group>[,...] [--access <permission>]
|
|
1003
|
+
grok s domains create <name> [--friendly-name <t>] [--description <t>]
|
|
1004
|
+
grok s domains apply <schema> --json manifest.json [--dry-run] [--confirm-destructive] [--if-version <v>]
|
|
702
1005
|
grok s batch <entity> <verb> arg1 [arg2 ...] Batch operation (one round-trip)
|
|
703
1006
|
grok s batch <entity> <verb> --json params.json Batch from JSON array
|
|
704
1007
|
grok s batch manifest.json Run a workflow manifest
|
|
@@ -707,18 +1010,53 @@ Special commands:
|
|
|
707
1010
|
grok s sync setup get <setup-id> Inspect a setup (selections, direction, last run)
|
|
708
1011
|
grok s sync run <setup-id> Trigger a push run; prints per-item outcome
|
|
709
1012
|
|
|
1013
|
+
Pull / push / migrate options:
|
|
1014
|
+
--out <dir> Bundle directory to write (pull; merges into an existing bundle)
|
|
1015
|
+
--type <t,t> conn, query, script, project, dashboard, space, view, layout, table,
|
|
1016
|
+
file, group, job, notebook, model
|
|
1017
|
+
--name <glob> Entity name glob: 'Cereal*' matches by prefix, '*demo*' anywhere
|
|
1018
|
+
--namespace <ns> Everything under a namespace, recursively
|
|
1019
|
+
--space <nqName> The space itself plus everything under it
|
|
1020
|
+
--author <login> Entities authored by a login
|
|
1021
|
+
--tag <tag> Entities carrying a tag
|
|
1022
|
+
--since <2w|date> Entities updated since ('2w' means '-2w'; also --since=-2w)
|
|
1023
|
+
--filter <expr> Smart-filter expression ANDed with the other flags
|
|
1024
|
+
--no-deps Do not follow dependencies (never-travels rules still apply)
|
|
1025
|
+
--no-include-data Do not pull table data (.d42) for pulled tables
|
|
1026
|
+
--include-files Also pull the bytes of pulled files
|
|
1027
|
+
--replace Clear the bundle directory before writing
|
|
1028
|
+
--dry-run Push: print the plan and stop
|
|
1029
|
+
--on-conflict <p> Push: what to do when the name is taken on the target by another id —
|
|
1030
|
+
fail (default) aborts before any write, skip leaves the target alone
|
|
1031
|
+
(and fails whatever depends on it), adopt writes into the twin and
|
|
1032
|
+
records idmap.json, duplicate creates the bundle entity under its own
|
|
1033
|
+
id next to the twin (a UserGroup cannot be duplicated — group names
|
|
1034
|
+
are unique, so that row fails)
|
|
1035
|
+
--creds <file.yaml> Push: target-side connection secrets, 'Ns:Conn:' then ' password: \${VAR}'
|
|
1036
|
+
(a covered connection is always written, so a push rotates the secret)
|
|
1037
|
+
--from <alias|url> Migrate: source instance (pulled from, never written to)
|
|
1038
|
+
--to <alias|url> Migrate: target instance
|
|
1039
|
+
--keep Migrate: keep the temporary bundle and print its path on stderr
|
|
1040
|
+
|
|
710
1041
|
Options:
|
|
711
1042
|
--host <alias|url> Server alias from config or full URL
|
|
1043
|
+
--admin Ask the server for an admin session, so the run sees entities the key's
|
|
1044
|
+
own account cannot (other people's spaces). Refused unless the account
|
|
1045
|
+
may start one; lasts for this command only
|
|
712
1046
|
--output <format> Output format: table (default), json, csv, quiet
|
|
713
1047
|
--filter <text> Smart filter expression
|
|
714
1048
|
--limit <n> Page size (default: 50)
|
|
715
1049
|
--offset <n> Start offset (default: 0)
|
|
716
1050
|
-r, --recursive Recursive (for files list)
|
|
717
|
-
--
|
|
1051
|
+
--verbose Print the stack of a runtime failure, not just its message
|
|
1052
|
+
--json <file> Read a JSON body from a file (save, functions run, batch, raw)
|
|
1053
|
+
--data '<json>' Inline JSON body for raw
|
|
718
1054
|
-O, --output-file Write table download to a file instead of stdout
|
|
719
1055
|
--type <t> Function discriminator: script | query | function | package
|
|
720
1056
|
--language <lang> Script language: python, r, julia, nodejs, octave, grok
|
|
721
1057
|
--package <name> Restrict to functions belonging to a package (by short name)
|
|
1058
|
+
--version <v> Package version for 'packages install' (default: latest)
|
|
1059
|
+
--all For 'packages update': upgrade every outdated package
|
|
722
1060
|
|
|
723
1061
|
Batch manifest options (in manifest.json):
|
|
724
1062
|
stopOnError Stop on first failure (default: true)
|
|
@@ -728,6 +1066,7 @@ Batch manifest options (in manifest.json):
|
|
|
728
1066
|
Examples:
|
|
729
1067
|
grok s users list
|
|
730
1068
|
grok s users list --output json --limit 10
|
|
1069
|
+
grok s users count --filter 'status = "active"'
|
|
731
1070
|
grok s users save --json user.json
|
|
732
1071
|
grok s groups save --json group.json --save-relations
|
|
733
1072
|
grok s shares add "JohnDoe:MyConnection" Chemists,Admins --access Edit
|
|
@@ -745,14 +1084,38 @@ Examples:
|
|
|
745
1084
|
grok s functions list --package PowerPack --type package --filter 'name contains "grid"'
|
|
746
1085
|
grok s files list "System:AppData" -r
|
|
747
1086
|
grok s files put ./smiles.csv "System:DemoFiles/smiles.csv"
|
|
748
|
-
grok s
|
|
1087
|
+
grok s packages install Chem Bio PowerGrid
|
|
1088
|
+
grok s packages install Chem --version 1.14.0
|
|
1089
|
+
grok s packages update --all
|
|
1090
|
+
grok s packages versions Chem
|
|
1091
|
+
grok s packages share Chem Chemists --access View
|
|
1092
|
+
grok s raw GET /users/current
|
|
1093
|
+
grok s raw POST /public/v1/functions/Sin/call --data '{"x": 1}'
|
|
749
1094
|
grok s describe connections
|
|
1095
|
+
grok s tables download MyTable -O ./my-table.csv
|
|
750
1096
|
grok s users list --host dev
|
|
751
1097
|
grok s users list --host "https://mygrok.com/api"
|
|
752
1098
|
grok s groups add-members Admins alice bob --admin
|
|
753
1099
|
grok s groups remove-members Admins alice
|
|
754
1100
|
grok s groups list-members Admins --admin
|
|
755
1101
|
grok s groups list-memberships alice
|
|
1102
|
+
grok s pull Admin:CerealDemog --out ./bundle --host dev
|
|
1103
|
+
grok s pull Chemists --out ./bundle --host dev
|
|
1104
|
+
grok s pull --type script --author alice --no-deps --out ./bundle
|
|
1105
|
+
grok s bundle ls ./bundle
|
|
1106
|
+
grok s push ./bundle --host local --dry-run
|
|
1107
|
+
grok s push ./bundle --host local --on-conflict adopt
|
|
1108
|
+
grok s pull --type space --namespace MySpace --include-files --out ./bundle
|
|
1109
|
+
grok s push ./bundle --host prod --creds ./creds.yaml
|
|
1110
|
+
grok s migrate Chem:TargetDashboard --from dev --to prod --dry-run
|
|
1111
|
+
grok s diff ./bundle --host local
|
|
1112
|
+
grok s domains list
|
|
1113
|
+
grok s domains get grit.issue
|
|
1114
|
+
grok s domains query grit.issue --filter 'status = "open"' --sort '!created_on' --limit 20
|
|
1115
|
+
grok s domains insert grit.issue title="Crash on save" status=open
|
|
1116
|
+
grok s domains upload grit.issue ./issues.csv --upsert
|
|
1117
|
+
grok s domains download grit.issue -O ./issues.csv
|
|
1118
|
+
grok s domains grant grit.issue Chemists --access Edit
|
|
756
1119
|
grok s batch files delete "System:AppData/old.txt" "System:DemoFiles/tmp.txt"
|
|
757
1120
|
grok s batch users create --json users.json
|
|
758
1121
|
grok s batch manifest.json
|