@cn-shell/jira
Version:
A Cloud Native extension for Jira
740 lines (739 loc) • 26.1 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CNJira = void 0;
const cn_shell_1 = __importDefault(require("cn-shell"));
const jira_resource_url_1 = require("./jira-resource-url");
// Jira config consts here
const CFG_JIRA_SERVER = "JIRA_SERVER";
const CFG_JIRA_USER = "JIRA_USER";
const CFG_JIRA_PASSWORD = "JIRA_PASSWORD";
const CFG_SESSION_REFRESH_PERIOD = "SESSION_REFRESH_PERIOD";
const DEFAULT_SESSION_REFRESH_PERIOD = "60"; // In mins
// Misc consts here
const SCRIPTRUNNER_DASHBOARDS_N_FILTERS_URL = "rest/scriptrunner/latest/canned/com.onresolve.scriptrunner.canned.jira.admin.ChangeSharedEntityOwnership";
// CNJira class here
class CNJira extends cn_shell_1.default {
// Constructor here
constructor(name, master) {
super(name, master);
let server = this.getRequiredCfg(CFG_JIRA_SERVER);
this._server = server.replace(/(\/+$)/, "");
this._user = this.getCfg(CFG_JIRA_USER);
this._password = this.getCfg(CFG_JIRA_PASSWORD, undefined, false, true);
let period = this.getCfg(CFG_SESSION_REFRESH_PERIOD, DEFAULT_SESSION_REFRESH_PERIOD);
this._refreshPeriod = parseInt(period, 10) * 60 * 1000; // Convert to ms
// Prepend the server to the resources to make our life easier
this._resourceUrls = {};
for (let r in jira_resource_url_1.JiraResources) {
this._resourceUrls[r] = `${this._server}${jira_resource_url_1.JiraResources[r]}`;
}
}
// Abstract method implementations here
async start() {
return true;
}
async stop() {
return;
}
async healthCheck() {
return true;
}
// Private methods here
// Public methods here
async login(auth) {
let url = this._resourceUrls.session;
let res = await this.httpReq({
method: "post",
url,
data: {
username: auth !== undefined ? auth.username : this._user,
password: auth !== undefined ? auth.password : this._password,
},
});
this._jiraSessionId = res.data.session.value;
// Start a timer to sutomatically renew the session ID
this._timeout = setTimeout(() => {
this.info("Refreshing session ID!");
this.login();
}, this._refreshPeriod);
}
async logout() {
if (this._jiraSessionId === undefined) {
return;
}
// Stop the timer first!
clearInterval(this._timeout);
let url = this._resourceUrls.session;
await this.httpReq({
method: "delete",
url,
headers: {
cookie: `JSESSIONID=${this._jiraSessionId}`,
},
});
this._jiraSessionId = undefined;
}
async getFieldDict(update = false) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
// Check to see if the field dict is populated AND the user hasn't requested it to be updated
if (this._fieldDict !== undefined && update === false) {
return this._fieldDict;
}
let url = this._resourceUrls.field;
let res = await this.httpReq({
method: "get",
url,
headers,
});
this._fieldDict = { byId: {}, byName: {} };
if (Array.isArray(res.data)) {
for (let field of res.data) {
this._fieldDict.byName[field.name] = {
id: field.id,
type: field.schema !== undefined ? field.schema.type : "Unknown",
itemType: field.schema !== undefined ? field.schema.items : "Unknown",
};
this._fieldDict.byId[field.id] = {
name: field.name,
type: field.schema !== undefined ? field.schema.type : "Unknown",
itemType: field.schema !== undefined ? field.schema.items : "Unknown",
};
}
}
return this._fieldDict;
}
async getAllowedFieldValues(projectKey, issueType, fieldName) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = this._resourceUrls.createmeta;
let params = new URLSearchParams();
params.append("expand", "projects.issuetypes.fields");
params.append("projectKeys", projectKey);
params.append("issuetypeNames", issueType);
let res = await this.httpReq({
method: "get",
url,
params,
headers,
});
// Convert field name to field ID
let dict = await this.getFieldDict();
let fieldInfo = dict.byName[fieldName];
if (fieldInfo === undefined) {
throw Error(`Unknown field ${fieldName}`);
}
let field = res.data.projects[0].issuetypes[0].fields[fieldInfo.id];
if (field === undefined || field.allowedValues === undefined) {
return [];
}
let allowed = [];
for (let info of field.allowedValues) {
allowed.push(info.value);
}
return allowed;
}
async getComponents(projectKey) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.components}/${projectKey}/components`;
let res = await this.httpReq({
method: "get",
url,
headers,
});
let components = {};
for (let component of res.data) {
components[component.name] = component.id;
}
return components;
}
async getProjects(component) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = this._resourceUrls.project;
let params = new URLSearchParams();
params.append("expand", "lead");
let res = await this.httpReq({
method: "get",
url,
headers,
params,
});
let projects = res.data;
if (component !== undefined) {
return projects.filter(el => el.projectCategory.name === component);
}
return projects;
}
// TODO: add getProject
async updateProject(project, data) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.project}/${project}`;
await this.httpReq({
method: "put",
url,
headers,
data,
});
}
async updateProjectLead(project, lead) {
await this.updateProject(project, { lead });
}
async createIssue(projectKey, issueType, component, fields) {
var _a;
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let components = await this.getComponents(projectKey);
let issue = {
fields: {
project: { key: projectKey },
issuetype: { name: issueType },
components: [{ id: components[component] }],
},
};
// Convert any field names to field IDs
await this.getFieldDict();
for (let fname in fields) {
let fid = (_a = this._fieldDict.byName[fname]) === null || _a === void 0 ? void 0 : _a.id;
if (fid !== undefined) {
issue.fields[fid] = fields[fname];
}
else {
issue.fields[fname] = fields[fname];
}
}
let url = this._resourceUrls.issue;
this.debug("createIssue: issue (%j)", issue);
let res = await this.httpReq({
method: "post",
url,
data: issue,
headers,
});
return res.data.key;
}
async updateIssue(key, fields, notifyUsers = true) {
var _a;
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let issue = {
fields: {},
};
// Convert any field names to field IDs
await this.getFieldDict();
for (let fname in fields) {
let fid = (_a = this._fieldDict.byName[fname]) === null || _a === void 0 ? void 0 : _a.id;
if (fid !== undefined) {
issue.fields[fid] = fields[fname];
}
else {
issue.fields[fname] = fields[fname];
}
}
let url = `${this._resourceUrls.issue}/${key}`;
if (notifyUsers === false) {
url = `${url}?notifyUsers=false`;
}
let res = await this.httpReq({
method: "put",
url,
data: issue,
headers,
});
return res.data.key;
}
async getIssue(idOrKey) {
var _a;
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.issue}/${idOrKey}`;
let res = await this.httpReq({
method: "get",
url,
headers,
});
let issue = {};
// Convert any field IDs to field name
await this.getFieldDict();
for (let fid in res.data.fields) {
let fname = (_a = this._fieldDict.byId[fid]) === null || _a === void 0 ? void 0 : _a.name;
if (fname !== undefined) {
issue[fname] = res.data.fields[fid];
}
else {
issue[fid] = res.data.fields[fid];
}
}
// Add id to list of fields
issue["id"] = res.data.id;
return issue;
}
async issueReporter(key, reporter, notifyUsers = true) {
await this.updateIssue(key, { reporter: { name: reporter } }, notifyUsers);
}
async assignIssue(key, assignee, notifyUsers = true) {
await this.updateIssue(key, {
assignee: {
name: assignee,
},
}, notifyUsers);
}
async updateLabels(key, action, labels, notifyUsers = true) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let issue = {
update: {
labels: [],
},
};
issue.update.labels = [];
// Convert any field names to field IDs
await this.getFieldDict();
for (let label of labels) {
issue.update.labels.push({ [action]: label });
}
let url = `${this._resourceUrls.issue}/${key}`;
if (notifyUsers === false) {
url = `${url}?notifyUsers=false`;
}
let res = await this.httpReq({
method: "put",
url,
data: issue,
headers,
});
return res.data.key;
}
async addComment(idOrKey, comment) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.issue}/${idOrKey}/comment`;
await this.httpReq({
method: "post",
url,
data: {
body: comment,
},
headers,
});
}
async addWatcher(idOrKey, watcher) {
let headers = {
"Content-Type": "application/json;charset=UTF-8",
};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.issue}/${idOrKey}/watchers`;
await this.httpReq({
method: "post",
url,
data: JSON.stringify(watcher),
headers,
});
}
async removeWatcher(idOrKey, watcher) {
let headers = {
"Content-Type": "application/json;charset=UTF-8",
};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.issue}/${idOrKey}/watchers`;
let params = new URLSearchParams();
params.append("username", watcher);
await this.httpReq({
method: "delete",
url,
data: JSON.stringify(watcher),
headers,
params,
});
}
async getTransitions(idOrKey) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.issue}/${idOrKey}/transitions`;
let res = await this.httpReq({
method: "get",
url,
headers,
});
let transitions = {};
for (let transition of res.data.transitions) {
transitions[transition.name] = transition.id;
}
return transitions;
}
async doTransition(idOrKey, transitionIdOrName, fields, comment) {
var _a;
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
// transition may be the Transition ID or name so check
let availableTransitions = await this.getTransitions(idOrKey);
let transitionId = availableTransitions[transitionIdOrName];
if (transitionId === undefined) {
transitionId = transitionIdOrName;
}
let dfields = {};
if (fields !== undefined) {
// Convert any field names to field IDs
await this.getFieldDict();
for (let fname in fields) {
let fid = (_a = this._fieldDict.byName[fname]) === null || _a === void 0 ? void 0 : _a.id;
if (fid !== undefined) {
dfields[fid] = { name: fields[fname] };
}
else {
dfields[fname] = { name: fields[fname] };
}
}
}
let dcomment = { comment: [{ add: { body: comment } }] };
let data = {
update: comment === undefined ? undefined : dcomment,
fields: fields === undefined || fields.length === 0 ? undefined : dfields,
transition: { id: transitionId },
};
let url = `${this._resourceUrls.issue}/${idOrKey}/transitions`;
await this.httpReq({
method: "post",
url,
data,
headers,
});
}
async runJql(jql) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.search}?jql=${encodeURI(jql)}`;
let res = await this.httpReq({
method: "get",
url,
headers,
});
if (res === undefined) {
return [];
}
return res.data.issues;
}
async jqlGetAll(jql) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let issues = [];
let startAt = 0;
let maxResults = 1000; // 1000 is the max you can get
while (true) {
let url = `${this._resourceUrls.search}?jql=${encodeURI(jql)}&startAt=${startAt}&maxResults=${maxResults}&fields=key`;
let res = await this.httpReq({
method: "get",
url,
headers,
}).catch(e => {
this.error(e);
});
if (res === undefined) {
break;
}
// Append the results to what we already have
let results = res.data;
for (let issue of results.issues) {
issues.push(issue.key);
}
// Increment by maxResults
startAt += maxResults;
// If we are beyond the total then we have everything so break,
// otherwise go again
if (startAt > results.total) {
break;
}
}
return issues;
}
async getUserDashboardIds(userId) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._server}/${SCRIPTRUNNER_DASHBOARDS_N_FILTERS_URL}/params`;
let res = await this.httpReq({
method: "post",
url,
data: {
FIELD_FROM_USER_ID: userId,
},
headers,
});
let dashboardIds = [];
let data = res.data;
for (let obj of data) {
if (obj.name === "FIELD_DASHBOARD_IDS") {
for (let value of obj.values) {
dashboardIds.push(value[0]);
}
}
}
return dashboardIds;
}
async getUserFilterIds(userId) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._server}/${SCRIPTRUNNER_DASHBOARDS_N_FILTERS_URL}/params`;
let res = await this.httpReq({
method: "post",
url,
data: {
FIELD_FROM_USER_ID: userId,
},
headers,
});
let filterIds = [];
let data = res.data;
for (let obj of data) {
if (obj.name === "FIELD_FILTER_IDS") {
for (let value of obj.values) {
filterIds.push(value[0].toString());
}
}
}
return filterIds;
}
async migrateDashboards(fromUserId, toUserId, dashboardIds) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._server}/${SCRIPTRUNNER_DASHBOARDS_N_FILTERS_URL}`;
let res = await this.httpReq({
method: "post",
url,
data: {
FIELD_FROM_USER_ID: fromUserId,
FIELD_TO_USER_ID: toUserId,
FIELD_DASHBOARD_IDS: dashboardIds,
FIELD_FILTER_IDS: [],
},
headers,
});
this.info("%s", res.data);
}
async migrateFilters(fromUserId, toUserId, filterIds) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._server}/${SCRIPTRUNNER_DASHBOARDS_N_FILTERS_URL}`;
let res = await this.httpReq({
method: "post",
url,
data: {
FIELD_FROM_USER_ID: fromUserId,
FIELD_TO_USER_ID: toUserId,
FIELD_DASHBOARD_IDS: [],
FIELD_FILTER_IDS: filterIds,
},
headers,
});
this.info("%s", res.data);
}
async getUser(user, byKey, includeGroups = false) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = this._resourceUrls.user;
let params = new URLSearchParams();
if (byKey) {
params.append("key", user);
}
else {
params.append("username", user);
}
if (includeGroups) {
params.append("expand", "groups");
}
let res = await this.httpReq({
method: "get",
url,
params,
headers,
});
return res.data;
}
async addUserToGroup(user, group) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.group}/user`;
let params = new URLSearchParams();
params.append("groupname", group);
let res = await this.httpReq({
method: "post",
url,
params,
headers,
data: { name: user },
});
return res.data;
}
async getUserGroups(user) {
var _a;
let details = await this.getUser(user, false, true);
let groups = [];
let groupItems = (_a = details === null || details === void 0 ? void 0 : details.groups) === null || _a === void 0 ? void 0 : _a.items;
if (groups !== undefined) {
for (let group of groupItems) {
groups.push(group.name);
}
}
return groups;
}
async addUserToApplication(user, applicationKey) {
let headers = {};
if (this._jiraSessionId !== undefined) {
headers.cookie = `JSESSIONID=${this._jiraSessionId}`;
}
else {
let token = Buffer.from(`${this._user}:${this._password}`).toString("base64");
headers.Authorization = `Basic ${token}`;
}
let url = `${this._resourceUrls.user}/application`;
let params = new URLSearchParams();
params.append("username", user);
params.append("applicationKey", applicationKey);
await this.httpReq({
method: "post",
url,
params,
headers,
data: {},
}).catch(e => {
this.error(e);
});
}
}
exports.CNJira = CNJira;