datagrok-tools 6.1.12 → 6.1.13
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 +4 -0
- package/bin/commands/report.js +54 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Datagrok-tools changelog
|
|
2
2
|
|
|
3
|
+
## 6.1.13 (2026-04-30)
|
|
4
|
+
|
|
5
|
+
* Reports: `grok report ticket` now uses direct JIRA REST honoring `$JIRA_PROJECT`, replacing the Datlas-mediated path that hardcoded GROK.
|
|
6
|
+
|
|
3
7
|
## 6.1.11 (2026-04-27)
|
|
4
8
|
|
|
5
9
|
* `grok report read <path | instance number>` — normalize a report zip/json into one JSON object on stdout (envelope unwrap, `_meta.json` merge, optional `--extract-screenshot` / `--extract-d42` / `--extract-actions`)
|
package/bin/commands/report.js
CHANGED
|
@@ -342,46 +342,79 @@ async function handleTicket(args) {
|
|
|
342
342
|
const instance = args._[2];
|
|
343
343
|
const reportId = args._[3];
|
|
344
344
|
if (!instance || !reportId) {
|
|
345
|
-
color.error('Usage: grok report ticket <instance> <report-id>');
|
|
345
|
+
color.error('Usage: grok report ticket <instance> <report-id> [--project <KEY>] [--type <Bug>] [--jira-url <url>]');
|
|
346
346
|
return false;
|
|
347
347
|
}
|
|
348
|
+
const projectKey = args['project'] || process.env.JIRA_PROJECT || '';
|
|
349
|
+
if (!projectKey) {
|
|
350
|
+
color.error('--project or $JIRA_PROJECT is required (no GROK default)');
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
const issueType = args['type'] || 'Bug';
|
|
354
|
+
const auth = jiraAuthHeader();
|
|
355
|
+
if (auth == null) {
|
|
356
|
+
color.error('JIRA_USER and JIRA_TOKEN env vars are required for `grok report ticket`.');
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
const jiraBase = resolveJiraBase(args);
|
|
348
360
|
try {
|
|
349
361
|
const {
|
|
350
362
|
url,
|
|
351
363
|
key
|
|
352
364
|
} = (0, _testUtils.getDevKey)(instance);
|
|
353
365
|
const token = await (0, _testUtils.getToken)(url, key);
|
|
354
|
-
console.log(
|
|
355
|
-
const
|
|
366
|
+
console.log(`Fetching report ${reportId}...`);
|
|
367
|
+
const reportResp = await fetch(`${url}/reports/${encodeURIComponent(reportId)}`, {
|
|
356
368
|
headers: {
|
|
357
369
|
Authorization: token
|
|
358
370
|
}
|
|
359
371
|
});
|
|
360
|
-
if (!
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}
|
|
364
|
-
const user = await userResp.json();
|
|
365
|
-
const userId = user.id || user.Id;
|
|
366
|
-
if (!userId) {
|
|
367
|
-
color.error('No user id in response');
|
|
372
|
+
if (!reportResp.ok) {
|
|
373
|
+
const body = await reportResp.text();
|
|
374
|
+
color.error(`Failed to fetch report (HTTP ${reportResp.status}): ${body.slice(0, 400)}`);
|
|
368
375
|
return false;
|
|
369
376
|
}
|
|
370
|
-
|
|
371
|
-
|
|
377
|
+
const body = await reportResp.json();
|
|
378
|
+
// The REST endpoint returns a flat UserReport: top-level `#type`,
|
|
379
|
+
// `number`, `errorMessage`, etc. The `data` field is a ref to the
|
|
380
|
+
// related data-table entity, not a body wrapper — do not unwrap.
|
|
381
|
+
const number = body && (body.number != null ? body.number : body.Number);
|
|
382
|
+
const errorMessage = (body && (body.errorMessage || body.ErrorMessage) || '').toString().trim();
|
|
383
|
+
let summary = number != null ? errorMessage ? `Report #${number}: ${errorMessage}` : `Report #${number}` : errorMessage || `Report ${reportId}`;
|
|
384
|
+
if (summary.length > 200) summary = summary.slice(0, 200);
|
|
385
|
+
// JIRA rejects newlines in summary.
|
|
386
|
+
summary = summary.replace(/[\r\n]+/g, ' ').trim();
|
|
387
|
+
const webRoot = url.replace(/\/api\/?$/, '');
|
|
388
|
+
const reportLink = number != null ? `${webRoot}/apps/usage/reports/${number}` : `${webRoot}/apps/usage/reports/`;
|
|
389
|
+
const description = `Auto-created from ${reportLink}`;
|
|
390
|
+
console.log(`Creating JIRA ticket in ${projectKey} (${issueType})...`);
|
|
391
|
+
const createResp = await fetch(`${jiraBase}/rest/api/2/issue/`, {
|
|
372
392
|
method: 'POST',
|
|
373
393
|
headers: {
|
|
374
|
-
Authorization:
|
|
375
|
-
'Content-Type': 'application/json'
|
|
376
|
-
|
|
394
|
+
Authorization: auth,
|
|
395
|
+
'Content-Type': 'application/json',
|
|
396
|
+
Accept: 'application/json'
|
|
397
|
+
},
|
|
398
|
+
body: JSON.stringify({
|
|
399
|
+
fields: {
|
|
400
|
+
project: {
|
|
401
|
+
key: projectKey
|
|
402
|
+
},
|
|
403
|
+
summary,
|
|
404
|
+
issuetype: {
|
|
405
|
+
name: issueType
|
|
406
|
+
},
|
|
407
|
+
description
|
|
408
|
+
}
|
|
409
|
+
})
|
|
377
410
|
});
|
|
378
|
-
if (
|
|
379
|
-
const
|
|
380
|
-
color.error(`JIRA
|
|
411
|
+
if (createResp.status !== 200 && createResp.status !== 201) {
|
|
412
|
+
const errBody = await createResp.text();
|
|
413
|
+
color.error(`JIRA issue creation failed (HTTP ${createResp.status}): ${errBody}`);
|
|
381
414
|
return false;
|
|
382
415
|
}
|
|
383
|
-
const result = await
|
|
384
|
-
const ticketKey = result.key;
|
|
416
|
+
const result = await createResp.json();
|
|
417
|
+
const ticketKey = result && result.key;
|
|
385
418
|
if (!ticketKey) {
|
|
386
419
|
color.error(`No ticket key in response: ${JSON.stringify(result).slice(0, 200)}`);
|
|
387
420
|
return false;
|
package/package.json
CHANGED