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 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`)
@@ -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('Getting current user...');
355
- const userResp = await fetch(`${url}/users/current`, {
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 (!userResp.ok) {
361
- color.error(`Failed to get current user (HTTP ${userResp.status})`);
362
- return false;
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
- console.log(`Creating JIRA ticket for report ${reportId}...`);
371
- const ticketResp = await fetch(`${url}/reports/${reportId}/jira?assigneeId=${userId}`, {
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: token,
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 (ticketResp.status !== 200 && ticketResp.status !== 201) {
379
- const body = await ticketResp.text();
380
- color.error(`JIRA ticket creation failed (HTTP ${ticketResp.status}): ${body}`);
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 ticketResp.json();
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datagrok-tools",
3
- "version": "6.1.12",
3
+ "version": "6.1.13",
4
4
  "description": "Utility to upload and publish packages to Datagrok",
5
5
  "homepage": "https://github.com/datagrok-ai/public/tree/master/tools#readme",
6
6
  "dependencies": {