@anura-gate/watcher-jira 0.2.3 → 0.2.5
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/lib/gate-watcher-jira.js +92 -1
- package/package.json +1 -1
package/lib/gate-watcher-jira.js
CHANGED
|
@@ -209,6 +209,97 @@ class GateJiraWatcher extends EventEmitter {
|
|
|
209
209
|
this._jiraHeaders.Authorization = `Bearer ${accessToken}`;
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
// -- Public: Direct Jira Actions ------------------------------------
|
|
213
|
+
// Convenience methods that call the Jira API directly (no GATE queue).
|
|
214
|
+
// Useful when you want the agent to act immediately.
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Post a comment on a Jira issue.
|
|
218
|
+
* @param {string} issueKey — e.g. "PROJ-123"
|
|
219
|
+
* @param {string} text — Comment body (plain text)
|
|
220
|
+
*/
|
|
221
|
+
async postComment(issueKey, text) {
|
|
222
|
+
const res = await this._jiraPost(`/rest/api/3/issue/${issueKey}/comment`, {
|
|
223
|
+
body: {
|
|
224
|
+
type: "doc",
|
|
225
|
+
version: 1,
|
|
226
|
+
content: [{ type: "paragraph", content: [{ type: "text", text }] }],
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
if (!res.ok) throw new Error(res.data?.errorMessages?.[0] || `Failed to post comment (${res.status})`);
|
|
230
|
+
return res.data;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Create a new Jira issue.
|
|
235
|
+
* @param {object} opts
|
|
236
|
+
* @param {string} opts.project — Project key (e.g. "PROJ")
|
|
237
|
+
* @param {string} opts.summary — Issue title
|
|
238
|
+
* @param {string} [opts.description] — Issue description (plain text)
|
|
239
|
+
* @param {string} [opts.issueType] — Issue type (default: "Task")
|
|
240
|
+
* @param {string} [opts.priority] — Priority name (e.g. "High")
|
|
241
|
+
* @param {string} [opts.assignee] — Atlassian account ID
|
|
242
|
+
* @param {string[]} [opts.labels] — Labels
|
|
243
|
+
*/
|
|
244
|
+
async createIssue(opts) {
|
|
245
|
+
const fields = {
|
|
246
|
+
project: { key: opts.project },
|
|
247
|
+
summary: opts.summary,
|
|
248
|
+
issuetype: { name: opts.issueType || "Task" },
|
|
249
|
+
};
|
|
250
|
+
if (opts.description) {
|
|
251
|
+
fields.description = {
|
|
252
|
+
type: "doc",
|
|
253
|
+
version: 1,
|
|
254
|
+
content: [{ type: "paragraph", content: [{ type: "text", text: opts.description }] }],
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
if (opts.assignee) fields.assignee = { accountId: opts.assignee };
|
|
258
|
+
if (opts.priority) fields.priority = { name: opts.priority };
|
|
259
|
+
if (opts.labels) fields.labels = opts.labels;
|
|
260
|
+
|
|
261
|
+
const res = await this._jiraPost("/rest/api/3/issue", { fields });
|
|
262
|
+
if (!res.ok) throw new Error(res.data?.errorMessages?.[0] || `Failed to create issue (${res.status})`);
|
|
263
|
+
return res.data;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Transition a Jira issue to a new status.
|
|
268
|
+
* @param {string} issueKey — e.g. "PROJ-123"
|
|
269
|
+
* @param {string} transitionName — Target status name (e.g. "Done", "In Progress")
|
|
270
|
+
*/
|
|
271
|
+
async transitionIssue(issueKey, transitionName) {
|
|
272
|
+
const transRes = await this._jiraGet(`/rest/api/3/issue/${issueKey}/transitions`);
|
|
273
|
+
if (!transRes.ok) throw new Error("Failed to fetch transitions");
|
|
274
|
+
|
|
275
|
+
const transition = transRes.data.transitions?.find(
|
|
276
|
+
(t) => t.name.toLowerCase() === transitionName.toLowerCase()
|
|
277
|
+
);
|
|
278
|
+
if (!transition) {
|
|
279
|
+
const available = (transRes.data.transitions || []).map((t) => t.name).join(", ");
|
|
280
|
+
throw new Error(`Transition "${transitionName}" not found. Available: ${available}`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const res = await this._jiraPost(`/rest/api/3/issue/${issueKey}/transitions`, {
|
|
284
|
+
transition: { id: transition.id },
|
|
285
|
+
});
|
|
286
|
+
if (!res.ok) throw new Error(res.data?.errorMessages?.[0] || `Failed to transition (${res.status})`);
|
|
287
|
+
return { transitioned: true, to: transitionName };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Assign a Jira issue.
|
|
292
|
+
* @param {string} issueKey — e.g. "PROJ-123"
|
|
293
|
+
* @param {string|null} accountId — Atlassian account ID, or null to unassign
|
|
294
|
+
*/
|
|
295
|
+
async assignIssue(issueKey, accountId) {
|
|
296
|
+
const res = await this._jiraPut(`/rest/api/3/issue/${issueKey}/assignee`, {
|
|
297
|
+
accountId: accountId || null,
|
|
298
|
+
});
|
|
299
|
+
if (!res.ok) throw new Error(res.data?.errorMessages?.[0] || `Failed to assign (${res.status})`);
|
|
300
|
+
return { assigned: true, assignee: accountId };
|
|
301
|
+
}
|
|
302
|
+
|
|
212
303
|
// -- Internal: Jira API -------------------------------------------
|
|
213
304
|
|
|
214
305
|
_jiraUrl(path) {
|
|
@@ -305,7 +396,7 @@ class GateJiraWatcher extends EventEmitter {
|
|
|
305
396
|
expand: "changelog",
|
|
306
397
|
});
|
|
307
398
|
|
|
308
|
-
const res = await this._jiraGet(`/rest/api/3/search?${params.toString()}`);
|
|
399
|
+
const res = await this._jiraGet(`/rest/api/3/search/jql?${params.toString()}`);
|
|
309
400
|
if (!res.ok) {
|
|
310
401
|
this.emit("jira_error", { path: "search", error: `JQL search failed (${res.status}): ${JSON.stringify(res.data?.errorMessages || res.data)}` });
|
|
311
402
|
return;
|