datagrok-tools 6.1.1 → 6.1.3
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/bin/commands/help.js +11 -10
- package/bin/commands/publish.js +80 -21
- package/bin/grok.js +2 -0
- package/package.json +1 -1
package/bin/commands/help.js
CHANGED
|
@@ -158,16 +158,17 @@ Uploads a package
|
|
|
158
158
|
Checks for errors before publishing — the package won't be published if there are any.
|
|
159
159
|
|
|
160
160
|
Options:
|
|
161
|
-
[--all] [--refresh] [--link] [--build] [--release] [--rebuild-docker] [--skip-check] [-v | --verbose]
|
|
162
|
-
|
|
163
|
-
--all
|
|
164
|
-
--refresh
|
|
165
|
-
--link
|
|
166
|
-
--build
|
|
167
|
-
--release
|
|
168
|
-
--rebuild-docker
|
|
169
|
-
--skip-
|
|
170
|
-
--
|
|
161
|
+
[--all] [--refresh] [--link] [--build] [--release] [--rebuild-docker] [--skip-docker-rebuild] [--skip-check] [-v | --verbose]
|
|
162
|
+
|
|
163
|
+
--all Publish all available packages (run in packages directory)
|
|
164
|
+
--refresh Publish all available already loaded packages (run in packages directory)
|
|
165
|
+
--link Link the package to local packages
|
|
166
|
+
--build Builds the package
|
|
167
|
+
--release Publish package as release version
|
|
168
|
+
--rebuild-docker Force rebuild Docker images locally before pushing to registry
|
|
169
|
+
--skip-docker-rebuild Skip auto-rebuild when Dockerfile folder has changed
|
|
170
|
+
--skip-check Skip check stage
|
|
171
|
+
--verbose Print detailed output
|
|
171
172
|
|
|
172
173
|
Running \`grok publish\` is the same as running \`grok publish defaultHost --build --debug\`
|
|
173
174
|
`;
|
package/bin/commands/publish.js
CHANGED
|
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7
7
|
exports.processPackage = processPackage;
|
|
8
8
|
exports.publish = publish;
|
|
9
9
|
var _archiverPromise = _interopRequireDefault(require("archiver-promise"));
|
|
10
|
+
var _crypto = _interopRequireDefault(require("crypto"));
|
|
10
11
|
var _fs = _interopRequireDefault(require("fs"));
|
|
11
12
|
var _nodeFetch = _interopRequireDefault(require("node-fetch"));
|
|
12
13
|
var _os = _interopRequireDefault(require("os"));
|
|
@@ -49,7 +50,7 @@ function discoverDockerfiles(packageName, version, debug) {
|
|
|
49
50
|
if (!entry.isDirectory()) continue;
|
|
50
51
|
const dockerfilePath = _path.default.join(dockerfilesDir, entry.name, 'Dockerfile');
|
|
51
52
|
if (!_fs.default.existsSync(dockerfilePath)) continue;
|
|
52
|
-
const cleanName = utils.removeScope(packageName).
|
|
53
|
+
const cleanName = utils.removeScope(packageName).toLowerCase();
|
|
53
54
|
const imageName = `${cleanName}-${entry.name.toLowerCase()}`;
|
|
54
55
|
const imageTag = debug ? version : `${version}.X`;
|
|
55
56
|
results.push({
|
|
@@ -95,7 +96,10 @@ function dockerTag(source, target) {
|
|
|
95
96
|
}
|
|
96
97
|
function dockerPush(image) {
|
|
97
98
|
try {
|
|
98
|
-
|
|
99
|
+
execSync(`docker push ${image}`, {
|
|
100
|
+
encoding: 'utf-8',
|
|
101
|
+
stdio: 'inherit'
|
|
102
|
+
});
|
|
99
103
|
return true;
|
|
100
104
|
} catch (e) {
|
|
101
105
|
color.error(`Failed to push ${image}: ${e.message || e}`);
|
|
@@ -115,6 +119,43 @@ function dockerBuild(imageName, dockerfilePath, context) {
|
|
|
115
119
|
return false;
|
|
116
120
|
}
|
|
117
121
|
}
|
|
122
|
+
function calculateFolderHash(dirPath) {
|
|
123
|
+
const hash = _crypto.default.createHash('sha256');
|
|
124
|
+
const entries = listRecursive(dirPath, '');
|
|
125
|
+
entries.sort((a, b) => a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0);
|
|
126
|
+
for (const entry of entries) {
|
|
127
|
+
if (entry.isDir) {
|
|
128
|
+
hash.update(`dir:${entry.relPath}:`);
|
|
129
|
+
} else {
|
|
130
|
+
hash.update(`file:${entry.relPath}:`);
|
|
131
|
+
hash.update(_fs.default.readFileSync(entry.fullPath));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return hash.digest('hex');
|
|
135
|
+
}
|
|
136
|
+
function listRecursive(basePath, rel) {
|
|
137
|
+
const results = [];
|
|
138
|
+
const fullDir = rel ? _path.default.join(basePath, rel) : basePath;
|
|
139
|
+
for (const entry of _fs.default.readdirSync(fullDir, {
|
|
140
|
+
withFileTypes: true
|
|
141
|
+
})) {
|
|
142
|
+
const relPath = rel ? `${rel}/${entry.name}` : entry.name;
|
|
143
|
+
const fullPath = _path.default.join(fullDir, entry.name);
|
|
144
|
+
if (entry.isDirectory()) {
|
|
145
|
+
results.push({
|
|
146
|
+
relPath,
|
|
147
|
+
fullPath,
|
|
148
|
+
isDir: true
|
|
149
|
+
});
|
|
150
|
+
results.push(...listRecursive(basePath, relPath));
|
|
151
|
+
} else results.push({
|
|
152
|
+
relPath,
|
|
153
|
+
fullPath,
|
|
154
|
+
isDir: false
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return results;
|
|
158
|
+
}
|
|
118
159
|
async function getUserLogin(host, devKey) {
|
|
119
160
|
let loginResp;
|
|
120
161
|
try {
|
|
@@ -144,14 +185,18 @@ async function getUserLogin(host, devKey) {
|
|
|
144
185
|
return null;
|
|
145
186
|
}
|
|
146
187
|
}
|
|
147
|
-
async function resolveLatestCompatible(host, devKey, dockerName) {
|
|
188
|
+
async function resolveLatestCompatible(host, devKey, dockerName, version, contentHash) {
|
|
148
189
|
const userInfo = await getUserLogin(host, devKey);
|
|
149
190
|
if (!userInfo) return {
|
|
150
191
|
found: null,
|
|
151
192
|
serverError: `Authentication failed. Check your developer key.`
|
|
152
193
|
};
|
|
153
194
|
try {
|
|
154
|
-
|
|
195
|
+
let url = `${host}/docker/images/${encodeURIComponent(dockerName)}/latest-compatible`;
|
|
196
|
+
const params = [];
|
|
197
|
+
if (version) params.push(`version=${encodeURIComponent(version)}`);
|
|
198
|
+
if (contentHash) params.push(`contentHash=${encodeURIComponent(contentHash)}`);
|
|
199
|
+
if (params.length > 0) url += '?' + params.join('&');
|
|
155
200
|
const resp = await (0, _nodeFetch.default)(url, {
|
|
156
201
|
headers: {
|
|
157
202
|
'Authorization': userInfo.token
|
|
@@ -176,29 +221,31 @@ async function resolveLatestCompatible(host, devKey, dockerName) {
|
|
|
176
221
|
};
|
|
177
222
|
}
|
|
178
223
|
}
|
|
179
|
-
async function processDockerImages(packageName, version, registry, devKey, host, rebuildDocker, zip, localTimestamps, debug) {
|
|
224
|
+
async function processDockerImages(packageName, version, registry, devKey, host, rebuildDocker, zip, localTimestamps, debug, skipDockerRebuild = false) {
|
|
180
225
|
const dockerImages = discoverDockerfiles(packageName, version, debug);
|
|
181
226
|
if (dockerImages.length === 0) return;
|
|
182
227
|
color.log(`Found ${dockerImages.length} Dockerfile(s)`);
|
|
183
228
|
if (registry) dockerLogin(registry, devKey);
|
|
184
229
|
for (const img of dockerImages) {
|
|
230
|
+
color.info(`Processing docker image ${img.fullLocalName}...`);
|
|
185
231
|
let result;
|
|
232
|
+
const dockerfileDir = _path.default.join('dockerfiles', img.dirName);
|
|
233
|
+
const dockerfilePath = _path.default.join(dockerfileDir, 'Dockerfile');
|
|
234
|
+
const contentHash = calculateFolderHash(_path.default.join(curDir, dockerfileDir));
|
|
186
235
|
if (rebuildDocker) {
|
|
187
|
-
const dockerfileDir = _path.default.join('dockerfiles', img.dirName);
|
|
188
|
-
const dockerfilePath = _path.default.join(dockerfileDir, 'Dockerfile');
|
|
189
236
|
if (dockerBuild(img.fullLocalName, dockerfilePath, dockerfileDir)) {
|
|
190
237
|
result = pushImage(img, registry);
|
|
191
238
|
color.success(`Built and tagged ${img.fullLocalName}`);
|
|
192
239
|
} else {
|
|
193
|
-
result = await fallbackImage(img, host, devKey, registry);
|
|
240
|
+
result = await fallbackImage(img, host, devKey, registry, version, contentHash);
|
|
194
241
|
}
|
|
195
242
|
} else if (localImageExists(img.fullLocalName)) {
|
|
196
|
-
result = pushImage(img, registry);
|
|
197
243
|
color.success(`Found local image ${img.fullLocalName}`);
|
|
244
|
+
result = pushImage(img, registry);
|
|
198
245
|
} else {
|
|
199
246
|
color.warn(`Local image not found. Expected: ${img.fullLocalName}`);
|
|
200
|
-
color.log(` Build it with: docker build -t ${img.fullLocalName} -f
|
|
201
|
-
const fallback = await fallbackImage(img, host, devKey, registry);
|
|
247
|
+
color.log(` Build it with: docker build -t ${img.fullLocalName} -f ${dockerfilePath} ${dockerfileDir}`);
|
|
248
|
+
const fallback = await fallbackImage(img, host, devKey, registry, version, contentHash);
|
|
202
249
|
if (fallback.serverError) {
|
|
203
250
|
color.error(`Cannot resolve fallback: ${fallback.serverError}`);
|
|
204
251
|
result = {
|
|
@@ -206,14 +253,25 @@ async function processDockerImages(packageName, version, registry, devKey, host,
|
|
|
206
253
|
fallback: true,
|
|
207
254
|
requestedVersion: img.imageTag
|
|
208
255
|
};
|
|
209
|
-
} else if (fallback.image) {
|
|
256
|
+
} else if (fallback.image && fallback.hashMatch === true) {
|
|
210
257
|
result = fallback;
|
|
211
|
-
color.
|
|
258
|
+
color.success(`Falling back to ${fallback.image} (dockerfile unchanged)`);
|
|
259
|
+
} else if (fallback.image && fallback.hashMatch === false && !skipDockerRebuild) {
|
|
260
|
+
color.warn(`Dockerfile folder has changed. Rebuilding image...`);
|
|
261
|
+
if (dockerBuild(img.fullLocalName, dockerfilePath, dockerfileDir)) {
|
|
262
|
+
result = pushImage(img, registry);
|
|
263
|
+
color.success(`Built and tagged ${img.fullLocalName}`);
|
|
264
|
+
} else {
|
|
265
|
+
result = {
|
|
266
|
+
image: fallback.image,
|
|
267
|
+
fallback: true,
|
|
268
|
+
requestedVersion: img.imageTag
|
|
269
|
+
};
|
|
270
|
+
color.warn(`Build failed. Falling back to ${fallback.image} (hash mismatch)`);
|
|
271
|
+
}
|
|
212
272
|
} else {
|
|
213
273
|
// No fallback and no local image — must build
|
|
214
274
|
color.warn(`No fallback available. Building ${img.fullLocalName}...`);
|
|
215
|
-
const dockerfileDir = _path.default.join('dockerfiles', img.dirName);
|
|
216
|
-
const dockerfilePath = _path.default.join(dockerfileDir, 'Dockerfile');
|
|
217
275
|
if (dockerBuild(img.fullLocalName, dockerfilePath, dockerfileDir)) {
|
|
218
276
|
result = pushImage(img, registry);
|
|
219
277
|
color.success(`Built and tagged ${img.fullLocalName}`);
|
|
@@ -256,11 +314,11 @@ function pushImage(img, registry) {
|
|
|
256
314
|
fallback: false
|
|
257
315
|
};
|
|
258
316
|
}
|
|
259
|
-
async function fallbackImage(img, host, devKey, registry) {
|
|
317
|
+
async function fallbackImage(img, host, devKey, registry, version, contentHash) {
|
|
260
318
|
const {
|
|
261
319
|
found,
|
|
262
320
|
serverError
|
|
263
|
-
} = await resolveLatestCompatible(host, devKey, img.imageName);
|
|
321
|
+
} = await resolveLatestCompatible(host, devKey, img.imageName, version, contentHash);
|
|
264
322
|
if (serverError) return {
|
|
265
323
|
image: null,
|
|
266
324
|
fallback: true,
|
|
@@ -270,7 +328,8 @@ async function fallbackImage(img, host, devKey, registry) {
|
|
|
270
328
|
if (found) return {
|
|
271
329
|
image: found.image,
|
|
272
330
|
fallback: true,
|
|
273
|
-
requestedVersion: img.imageTag
|
|
331
|
+
requestedVersion: img.imageTag,
|
|
332
|
+
hashMatch: found.hashMatch
|
|
274
333
|
};
|
|
275
334
|
return {
|
|
276
335
|
image: null,
|
|
@@ -278,7 +337,7 @@ async function fallbackImage(img, host, devKey, registry) {
|
|
|
278
337
|
requestedVersion: img.imageTag
|
|
279
338
|
};
|
|
280
339
|
}
|
|
281
|
-
async function processPackage(debug, rebuild, host, devKey, packageName, dropDb, suffix, hostAlias, registry, rebuildDocker) {
|
|
340
|
+
async function processPackage(debug, rebuild, host, devKey, packageName, dropDb, suffix, hostAlias, registry, rebuildDocker, skipDockerRebuild) {
|
|
282
341
|
// Validate server connectivity and dev key
|
|
283
342
|
let timestamps = {};
|
|
284
343
|
let url = `${host}/packages/dev/${devKey}/${packageName}`;
|
|
@@ -400,7 +459,7 @@ async function processPackage(debug, rebuild, host, devKey, packageName, dropDb,
|
|
|
400
459
|
const userInfo = await getUserLogin(host, devKey);
|
|
401
460
|
if (userInfo) dockerVersion = userInfo.login;
|
|
402
461
|
}
|
|
403
|
-
await processDockerImages(packageName, dockerVersion, registry, devKey, host, rebuildDocker ?? false, zip, localTimestamps, debug);
|
|
462
|
+
await processDockerImages(packageName, dockerVersion, registry, devKey, host, rebuildDocker ?? false, zip, localTimestamps, debug, skipDockerRebuild ?? false);
|
|
404
463
|
zip.append(JSON.stringify(localTimestamps), {
|
|
405
464
|
name: 'timestamps.json'
|
|
406
465
|
});
|
|
@@ -545,7 +604,7 @@ async function publishPackage(args) {
|
|
|
545
604
|
if (!args.suffix && stdout) args.suffix = stdout.toString().substring(0, 8);
|
|
546
605
|
});
|
|
547
606
|
await utils.delay(100);
|
|
548
|
-
code = await processPackage(!args.release, Boolean(args.rebuild), url, key, packageName, args.dropDb ?? false, args.suffix, host, registry, args['rebuild-docker']);
|
|
607
|
+
code = await processPackage(!args.release, Boolean(args.rebuild), url, key, packageName, args.dropDb ?? false, args.suffix, host, registry, args['rebuild-docker'], args['skip-docker-rebuild']);
|
|
549
608
|
} catch (error) {
|
|
550
609
|
console.error(error);
|
|
551
610
|
code = 1;
|
package/bin/grok.js
CHANGED
|
@@ -27,6 +27,8 @@ const commands = {
|
|
|
27
27
|
const onPackageCommandNames = ['api', 'check', 'link', 'publish', 'test'];
|
|
28
28
|
|
|
29
29
|
const command = argv['_'][0];
|
|
30
|
+
if (command !== 'test' && command !== 'stresstest')
|
|
31
|
+
delete argv.dartium;
|
|
30
32
|
if (command in commands) {
|
|
31
33
|
try {
|
|
32
34
|
if (argv['help']) {
|
package/package.json
CHANGED