cleanUrl: "/jira"
사내 API를 활용해서, 지라 계정에 임직원 정보를 맵핑해주는 배치를 Groovy 로 작성


import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.issue.*;
import com.atlassian.jira.issue.customfields.*;
import com.atlassian.jira.user.UserPropertyManager;
import com.atlassian.jira.user.*;
import com.atlassian.jira.user.util.UserUtil;
import groovy.json.*;
import org.apache.http.client.methods.*;
import org.apache.http.entity.*;
import org.apache.http.impl.client.*;
def userPropertyManager = ComponentAccessor.userPropertyManager;
UserUtil userUtil = ComponentAccessor.getUserUtil();
def url = "<https://xxxxx.com/api/service/findByEmail?email=>"
int qty = 0
int activeCount = 0;
int inactiveCount = 0;
int failCount = 0;
for(ApplicationUser u in userUtil.getUsers())
{
if(!u.isActive()) {
inactiveCount++;
continue;
}
else activeCount++;
//log.warn(u)
//log.warn(u.emailAddress)
if(u.emailAddress != null) {
def get = new HttpGet(url+u.emailAddress)
get.addHeader("host", "xxxxxxx.com")
get.addHeader("apikey", "xxxxxxxxxxxxxxxxxx")
get.addHeader("content-type", "application/json")
def client = HttpClientBuilder.create().build()
def response = client.execute(get)
if(response.getStatusLine().getStatusCode() == 200) {
def bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))
def jsonResponse = bufferedReader.getText()
def slurper = new JsonSlurper()
def resultMap = slurper.parseText(jsonResponse)
if(resultMap["recordset"] != null) {
try {
resultMap["recordset"]["teamName"] != null ? userPropertyManager.getPropertySet(u).setString('jira.meta.team', resultMap.recordset[0].teamName) : null;
resultMap["recordset"]["jobClassCode"] != null ? userPropertyManager.getPropertySet(u).setString('jira.meta.jobClassCode', resultMap.recordset[0].jobClassCode) : null;
}
catch(Exception e)
{
failCount++;
log.warn("error user:"+u)
log.error(e)
}
}
}
}
}
log.warn("active: "+activeCount + "\\nfail: "+failCount + "\\ninactive: "+inactiveCount);
사용자의 특성, 프로젝트 별, 필드 조건에 맞게, 지라내에서 수정 또는 볼 수 없도록 세세한 조정 가능


특정 사용자 제외

특정 컨디션에 맞게 스크립트 실행



Javascript 를 지라의 특정 페이지, 프로젝트에 주입해서 사용 할 수 있음



/*
Created by Phil 2020.07.06
WORKING VERSION
jsincluder issues in function footer column
*/
try {
let currentIdx = 0, ghxIssuesInEpicTableTRRows = 1, estimate = 0;
function timedevide(value) {
var week = 0;
var day = 0;
var hour = 0;
hour = parseFloat(value % 40); //시간 계산
day = parseInt(hour / 8); //날 계산
week = parseInt((value - hour) / 40); // 주 계산
if (9 < hour < 40) { // 시간이 9~40시간 사이일 경우 계산
hour = hour - (day * 8)
}
else if (8 <= hour <= 9) { // 시간이 8~9 시간일 경우 계산
hour = hour - 8
}
return { // 결과값 리턴
h: +hour.toFixed(4),
d: +day.toFixed(4),
w: +week.toFixed(4)
}
}
const loopForever = () => {
if (currentIdx < ghxIssuesInEpicTableTRRows) {
// console.log('currentIdx: '+currentIdx+' ghxIssuesInEpicTableTRRows: '+ghxIssuesInEpicTableTRRows);
setTimeout(loopForever, 500);
// console.log('loop');
} else {
// console.log('currentIdx: '+currentIdx+' ghxIssuesInEpicTableTRRows: '+ghxIssuesInEpicTableTRRows);
var actions2 = AJS.$('#ghx-issues-in-epic-table tbody');
AJS.$(actions2).before('<thead><tr class="issuerow"><th></th><th>Key</th><th>Summary</th><th></th><th>Status</th><th>Assignee</th><th>Due Date</th><th>Original<br/>Estimate</th><th></th></tr></thead>');
AJS.$(actions2).after('<tfoot><tr class="issuerow"><td></td><td></td><td></td><td></td><td>총공수</td><td>' + +(estimate / 160).toFixed(4) + '</td><td>Sum</td><td>' + timedevide(estimate).w + "Week " + timedevide(estimate).d + "Day " + timedevide(estimate).h + "Hour " + '</td><td></td></tr></tfoot>');
}
}
AJS.$(document).ready(function () {
try {
//Updated 2020.07.06 by Phil
let rows = AJS.$('#ghx-issues-in-epic-table tr');
ghxIssuesInEpicTableTRRows = rows.length;
// console.log("total row: "+ghxIssuesInEpicTableTRRows);
if (rows.length > 0) {
loopForever();
}
rows.each(function () {
// 여기에 있으면 getJson 보다 먼저 처리됨
// currentIdx = currentIdx + 1;
var row = this;
var value;
var issueKey = AJS.$(this).attr("data-issuekey");
if (issueKey) {
AJS.$.getJSON(AJS.contextPath() + '/rest/api/latest/issue/' + issueKey, function (data) {
value = 0;
if (data.fields.aggregatetimeoriginalestimate) {
value = data.fields.aggregatetimeoriginalestimate / 3600;
estimate = estimate + value;
}
else
{
value = 0;
}
var actions = AJS.$(row).find('td.issue_actions');
duedate = data.fields.duedate;
AJS.$(actions).before('<td class="nav">' + duedate + '</td>');
AJS.$(actions).before('<td class="nav">' + timedevide(value).w + "Week " + timedevide(value).d + "Day " + timedevide(value).h + "Hour " + '</td>');
// console.log("index: "+currentIdx + " value:" +value);
currentIdx = currentIdx + 1;
});
}
else
{
// console.log(AJS.$(this));
currentIdx = currentIdx + 1;
}
// console.log('estimate: '+estimate);
});
} catch (error1) {
alert(`다음과 같은 에러가 발생했습니다: ${error1.name}: ${error1.message}`);
// console.log(error1);
}
});
} catch (error) {
alert(`다음과 같은 에러가 발생했습니다: ${error.name}: ${error.message}`);
// console.log(error);
}