datagrok-tools 6.1.5 → 6.1.6

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.
@@ -21,6 +21,7 @@ Commands:
21
21
  init Modify a package template
22
22
  link Link \`datagrok-api\` and libraries for local development
23
23
  publish Upload a package
24
+ report Manage user error reports (fetch, resolve, create ticket)
24
25
  test Run package tests
25
26
  testall Run packages tests
26
27
  migrate Migrate legacy tags to meta.role
@@ -321,6 +322,23 @@ Examples:
321
322
  // file and converting your scripts in the \`package.json\` file
322
323
  // `;
323
324
 
325
+ const HELP_REPORT = `
326
+ Usage: grok report <subcommand> <instance> <id>
327
+
328
+ Manage Datagrok user error reports
329
+
330
+ Subcommands:
331
+ fetch Download a report zip from a managed instance
332
+ resolve Mark a report as resolved
333
+ ticket Create a JIRA ticket for a report via the Datlas API
334
+
335
+ Examples:
336
+ grok report fetch dev 1528 Download report #1528 from the 'dev' instance
337
+ grok report resolve dev 1528 Resolve report #1528 on the 'dev' instance
338
+ grok report ticket dev <report-uuid> Create a JIRA ticket for a report
339
+
340
+ The instance name must match a server alias in ~/.grok/config.yaml.
341
+ `;
324
342
  const help = exports.help = {
325
343
  add: HELP_ADD,
326
344
  api: HELP_API,
@@ -333,6 +351,7 @@ const help = exports.help = {
333
351
  init: HELP_INIT,
334
352
  link: HELP_LINK,
335
353
  publish: HELP_PUBLISH,
354
+ report: HELP_REPORT,
336
355
  test: HELP_TEST,
337
356
  testall: HELP_TESTALL,
338
357
  migrate: HELP_MIGRATE,
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.report = report;
8
+ var _fs = _interopRequireDefault(require("fs"));
9
+ var _os = _interopRequireDefault(require("os"));
10
+ var _path = _interopRequireDefault(require("path"));
11
+ var color = _interopRequireWildcard(require("../utils/color-utils"));
12
+ var _testUtils = require("../utils/test-utils");
13
+ 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); }
14
+ const fetch = require('node-fetch');
15
+ async function report(args) {
16
+ const subcommand = args._[1];
17
+ switch (subcommand) {
18
+ case 'fetch':
19
+ return await handleFetch(args);
20
+ case 'resolve':
21
+ return await handleResolve(args);
22
+ case 'ticket':
23
+ return await handleTicket(args);
24
+ default:
25
+ return false;
26
+ }
27
+ }
28
+ async function handleFetch(args) {
29
+ const instance = args._[2];
30
+ const number = args._[3];
31
+ if (!instance || !number) {
32
+ color.error('Usage: grok report fetch <instance> <number>');
33
+ return false;
34
+ }
35
+ try {
36
+ const {
37
+ url,
38
+ key
39
+ } = (0, _testUtils.getDevKey)(instance);
40
+ const token = await (0, _testUtils.getToken)(url, key);
41
+ console.log(`Searching for report #${number}...`);
42
+ const searchResp = await fetch(`${url}/reports?text=number%3D${encodeURIComponent(number)}`, {
43
+ headers: {
44
+ Authorization: token
45
+ }
46
+ });
47
+ if (!searchResp.ok) {
48
+ color.error(`Report search failed (HTTP ${searchResp.status})`);
49
+ return false;
50
+ }
51
+ const results = await searchResp.json();
52
+ if (!Array.isArray(results) || results.length === 0) {
53
+ color.error(`Report #${number} not found`);
54
+ return false;
55
+ }
56
+ const reportData = results[0];
57
+ const reportId = reportData.id || reportData.Id;
58
+ if (!reportId) {
59
+ color.error('Report found but has no id field');
60
+ return false;
61
+ }
62
+ console.log(`Downloading report ${reportId}...`);
63
+ const downloadResp = await fetch(`${url}/reports/${reportId}/zip`, {
64
+ headers: {
65
+ Authorization: token
66
+ }
67
+ });
68
+ if (!downloadResp.ok) {
69
+ color.error(`Report download failed (HTTP ${downloadResp.status})`);
70
+ return false;
71
+ }
72
+ const buffer = await downloadResp.buffer();
73
+ const outputPath = _path.default.join(_os.default.tmpdir(), `report_${instance}_${number}.zip`);
74
+ _fs.default.writeFileSync(outputPath, buffer);
75
+ const metaPath = outputPath.replace('.zip', '_meta.json');
76
+ _fs.default.writeFileSync(metaPath, JSON.stringify(reportData, null, 2));
77
+ color.success(`Report saved to: ${outputPath}`);
78
+ console.log(outputPath);
79
+ return true;
80
+ } catch (err) {
81
+ color.error(`Error: ${err.message}`);
82
+ return false;
83
+ }
84
+ }
85
+ async function handleResolve(args) {
86
+ const instance = args._[2];
87
+ const number = args._[3];
88
+ if (!instance || !number) {
89
+ color.error('Usage: grok report resolve <instance> <number>');
90
+ return false;
91
+ }
92
+ try {
93
+ const metaPath = _path.default.join(_os.default.tmpdir(), `report_${instance}_${number}_meta.json`);
94
+ if (!_fs.default.existsSync(metaPath)) {
95
+ color.error(`Meta file not found: ${metaPath}`);
96
+ color.warn('Hint: was the report fetched via `grok report fetch` first?');
97
+ return false;
98
+ }
99
+ const meta = JSON.parse(_fs.default.readFileSync(metaPath, 'utf-8'));
100
+ const reportId = meta.id || meta.Id;
101
+ if (!reportId) {
102
+ color.error(`No report id in meta file: ${metaPath}`);
103
+ return false;
104
+ }
105
+ const {
106
+ url,
107
+ key
108
+ } = (0, _testUtils.getDevKey)(instance);
109
+ const token = await (0, _testUtils.getToken)(url, key);
110
+ console.log(`Resolving report #${number} (id: ${reportId})...`);
111
+ const resp = await fetch(`${url}/reports/${reportId}/resolve`, {
112
+ method: 'POST',
113
+ headers: {
114
+ Authorization: token
115
+ }
116
+ });
117
+ if (resp.ok) {
118
+ color.success(`Report #${number} resolved on ${instance}`);
119
+ return true;
120
+ }
121
+ const body = await resp.text();
122
+ color.error(`Resolve failed (HTTP ${resp.status}): ${body}`);
123
+ return false;
124
+ } catch (err) {
125
+ color.error(`Error: ${err.message}`);
126
+ return false;
127
+ }
128
+ }
129
+ async function handleTicket(args) {
130
+ const instance = args._[2];
131
+ const reportId = args._[3];
132
+ if (!instance || !reportId) {
133
+ color.error('Usage: grok report ticket <instance> <report-id>');
134
+ return false;
135
+ }
136
+ try {
137
+ const {
138
+ url,
139
+ key
140
+ } = (0, _testUtils.getDevKey)(instance);
141
+ const token = await (0, _testUtils.getToken)(url, key);
142
+ console.log('Getting current user...');
143
+ const userResp = await fetch(`${url}/users/current`, {
144
+ headers: {
145
+ Authorization: token
146
+ }
147
+ });
148
+ if (!userResp.ok) {
149
+ color.error(`Failed to get current user (HTTP ${userResp.status})`);
150
+ return false;
151
+ }
152
+ const user = await userResp.json();
153
+ const userId = user.id || user.Id;
154
+ if (!userId) {
155
+ color.error('No user id in response');
156
+ return false;
157
+ }
158
+ console.log(`Creating JIRA ticket for report ${reportId}...`);
159
+ const ticketResp = await fetch(`${url}/reports/${reportId}/jira?assigneeId=${userId}`, {
160
+ method: 'POST',
161
+ headers: {
162
+ Authorization: token,
163
+ 'Content-Type': 'application/json'
164
+ }
165
+ });
166
+ if (ticketResp.status !== 200 && ticketResp.status !== 201) {
167
+ const body = await ticketResp.text();
168
+ color.error(`JIRA ticket creation failed (HTTP ${ticketResp.status}): ${body}`);
169
+ return false;
170
+ }
171
+ const result = await ticketResp.json();
172
+ const ticketKey = result.key;
173
+ if (!ticketKey) {
174
+ color.error(`No ticket key in response: ${JSON.stringify(result).slice(0, 200)}`);
175
+ return false;
176
+ }
177
+ color.success(`Created ticket: ${ticketKey}`);
178
+ console.log(ticketKey);
179
+ return true;
180
+ } catch (err) {
181
+ color.error(`Error: ${err.message}`);
182
+ return false;
183
+ }
184
+ }
package/bin/grok.js CHANGED
@@ -18,6 +18,7 @@ const commands = {
18
18
  init: require('./commands/init').init,
19
19
  link: require('./commands/link').link,
20
20
  publish: require('./commands/publish').publish,
21
+ report: require('./commands/report').report,
21
22
  test: require('./commands/test').test,
22
23
  testall: require('./commands/test-all').testAll,
23
24
  stresstest: require('./commands/stress-tests').stressTests,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "datagrok-tools",
3
- "version": "6.1.5",
3
+ "version": "6.1.6",
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": {