안녕하세요. 저희 회사는 협업도구로 Attlasian 의 Jira, Confluence를 사용하고 있습니다.
업무중에 Jira 일감을 생성해야 하는 경우가 있는데, 그때마다 좀 불편한 부분이 있어서 이를 Python Script로 좀 편하게
만들면 좋겠다 싶어서 그 내용을 적으려고 합니다.
불편했던 점 중 가장 큰 것은
다음과 같은 화면에서 여러 항목들은 선택해야 하는 것이었습니다.
그리고 큰틀(Epic)과 스프린트를 선택해야 하는데, 내가 원하는 큰틀의 이름과 스프린트를 입력할 수 있고, 여러 내용들 중에 선택할 수도 있게 되어 있지만 정확한 이름은 아는데 선택할 수 있는 내용중에 그 이름이 없는 경우가 있습니다. 그래서 한 글자씩 타이핑하며 내가 원하는 내용이 자동검색 되면 그걸 선택해야 하는 일이 저한테는 매우 불편하게 느껴졌습니다.
현재 내가 생성하고 싶은 일감의 상위 Epic과 Sprint 이름을 정확히 알고 있고 있기 때문에 위의 화면에서 하나씩 선택하여 이슈를 생성하기 보다는 한방에 딱! 만들고 싶었습니다.
그래서 다음과 같이 코드를 만들어 냈습니다.
import requests
from requests.auth import HTTPBasicAuth
import json
import re
# JIRA 인스턴스 URL 및 API 엔드포인트
jira_url = 'https://jira.xxxxxxxx.com' #우리 회사에서 사용하고 있는 지라 URL
# 사용자 인증 정보
username = 'XXXX' #내 계정
api_token = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX' #내 계정으로 얻은 토큰
def get_epickey_sprintid(search_query):
# JIRA이슈 검색용
api_endpoint_search = '/rest/api/2/search'
# JQL 쿼리
jql_query = f'text ~ "{search_query}"'
# 검색에 필요한 데이터
search_data = {
"jql": jql_query,
"maxResults": 10,
"fields": ["key", "summary", "customfield_10104"]
}
# HTTP 요청 헤더
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": f"Bearer {api_token}"
}
# API요청
response = requests.post(
f"{jira_url}{api_endpoint_search}",
headers=headers,
data=json.dumps(search_data)
)
# 응답 처리
result_issue_key = 'None'
result_sprint = 'None'
if response.status_code == 200:
print("이슈 검색에 성공했습니다.")
search_results = response.json()
#print(search_results)
issues = search_results.get('issues', [])
for issue in issues:
customfield_data = issue['fields'].get('customfield_10104', None)
print(f"customfield_10104 데이터: {customfield_data}") # 데이터 구조 확인을 위한 출력
if customfield_data:
# 문자열에서 스프린트ID 값을 추출하기 위한 정규 표현식
match = re.search(r'id=([^,]+)', customfield_data[0])
if match:
id_value = match.group(1)
#print(f"이슈 키: {issue['key']}, 요약: {issue['fields']['summary']}, customfield_10104의 name 값: {name_value}")
result_issue_key = issue['key']
result_sprintid = id_value
else:
print(f"이슈 키: {issue['key']}, 요약: {issue['fields']['summary']}, customfield_10104 필드에서 name 값을 찾을 수 없습니다.")
result_issue_key = 'None'
result_sprintid = 0
else:
print(f"이슈 키: {issue['key']}, 요약: {issue['fields']['summary']}, customfield_10104 필드 값이 없습니다.")
result_issue_key = 'None'
result_sprintid = 0
else:
print(f"이슈 검색에 실패했습니다. 상태 코드: {response.status_code}")
response_data = response.json()
if response_data: # 응답 데이터가 None이 아닌지 확인
print(response_data)
else:
print("응답 데이터가 None입니다.")
result_issue_key = 'None'
result_sprintid = 0
return result_issue_key, result_sprintid
def create_jiraissus(summary, description, storypoint, epickey, sprintid):
api_endpoint_create = '/rest/api/2/issue/'
# 이슈 생성에 필요한 데이터
issue_data = {
"fields": {
"project": {
"key": "ProjectName" #내 이슈를 생성할 Project 이름을 넣어야 합니다.
},
"summary": f"{summary}",
"description": f"{description}",
"issuetype": {
"name": "Task"
},
"assignee": {
"name": f"{username}" # 생성한 나의 사용자명으로 변경
},
"customfield_10106": float(f"{storypoint}"), # 스토리포인트
"customfield_10100": f"{epickey}", # 킅틀
"customfield_10104": int(f"{sprintid}") # 스프린트
}
}
# HTTP 요청 헤더
headers = {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": f"Bearer {api_token}"
}
# set을 list로 변환
if isinstance(issue_data["fields"]["customfield_10106"], set):
issue_data["fields"]["customfield_10106"] = list(issue_data["fields"]["customfield_10106"])
if isinstance(issue_data["fields"]["customfield_10100"], set):
issue_data["fields"]["customfield_10100"] = list(issue_data["fields"]["customfield_10100"])
if isinstance(issue_data["fields"]["customfield_10104"], set):
issue_data["fields"]["customfield_10104"] = list(issue_data["fields"]["customfield_10104"])
# API 요청
response = requests.post(
jira_url + api_endpoint_create,
headers=headers,
data=json.dumps(issue_data)
)
# 응답 처리
if response.status_code == 201:
print("이슈가 성공적으로 생성되었습니다.")
else:
print(f"이슈 생성에 실패했습니다. 상태 코드: {response.status_code}")
response_data = response.json()
if response_data: # 응답 데이터가 None이 아닌지 확인
print(response_data)
else:
print("응답 데이터가 None입니다.")
def check_field():
# 프로젝트 및 이슈 유형에 대한 메타데이터 조회
api_endpoint_field = '/rest/api/2/issue/createmeta'
# HTTP 요청 헤더
headers = {
"Accept": "application/json",
"Authorization": f"Bearer {api_token}"
}
# API 요청
response = requests.get(
jira_url + api_endpoint_field,
headers=headers
)
# 응답 처리
if response.status_code == 200:
print("메타데이터 조회가 성공적으로 이루어졌습니다.")
metadata = response.json()
print(json.dumps(metadata, indent=2)) # 프로젝트 및 이슈 유형에 대한 메타데이터 출력
# JSON 데이터를 파일로 저장
with open('metadata.json', 'w', encoding='utf-8') as json_file:
json.dump(metadata, json_file, indent=2, ensure_ascii=False)
print("메타데이터가 'metadata.json' 파일로 저장되었습니다.")
else:
print(f"메타데이터 조회에 실패했습니다. 상태 코드: {response.status_code}")
EpicName = 'TestEpic' #이 이름으로 생성된 Epic이 있어야 합니다.
IssueName = 'Test Issue Name'
Description = 'Test Issue Description'
Storypoint = '1'
epickey, sprintid = get_epickey_sprintid(EpicName) #큰틀 및 스프린트 이름 검색
print(f"Epic Key: {epickey}, customfield_10104의 id 값: {sprintid}")
if epickey == 'None':
print("Epic을 검색할 수 없습니다.")
else:
create_jiraissus(IssueName, Description, Storypoint, epickey, sprintid)
위의 코드를 위해서는 선행적으로 알아와야 할 내용이 있습니다.
1. API토큰
이건 JIRA 페이지에서 아마 우측 상단에 있을텐데 내 계정이 표시된 것을 클릭하면 '프로파일' 이라는 메뉴가 있습니다. 이쪽으로 들어가면 '개인용 액세스 토큰' 이라는 메뉴에서 토클을 생성할 수 있습니다.
한번 생성하면 다시 볼 수는 없으니, 생성할때 잘 복사해놓아야 합니다.
2. Customfield
위 코드에서 다음과 같은 부분을 볼 수 있습니다.
"customfield_10106": float(f"{storypoint}"), # 스토리포인트
"customfield_10100": f"{epickey}", # 킅틀
이는 내가 사용하고 있는 Jira 페이지에서 직접 찾아서 넣어야 하는 부분입니다.
이는 F12를 눌러 Chrome의 개발자도구를 띄워서 확인할 수 있습니다.
우측의 개발자도구 화면에서 내가 원하는 내용이 있는 곳 까지 차근차근 찾아갈 수 있습니다. 우측화면에서 마우스 포인터가 위치하는 부분이 왼쪽 화면에서 하이라이트 되니까요.
위와 같이 하면 다른 Customfield 들도 찾아서 입력할 수 있도록 설정이 가능합니다.
여기까지하여 저는 그냥 한방에 이슈들을 생성할 수 있게 되었습니다.
'python' 카테고리의 다른 글
python, LSTM을 활용한 주식 가격 예측 (3) | 2024.08.30 |
---|---|
pyinstaller로 배포할 exe에 필요한 파일들 모두 포함시키는 방법 (0) | 2024.06.13 |
python 주식 가격 알림 메일 보내기 (59) | 2023.10.19 |
이미지로 좌표찾기 및 마우스클릭 - pyautogui (72) | 2023.10.11 |
파이썬 스크립트(.py 파일)를 실행 가능한(.exe) 파일로 변환 (2) | 2023.08.02 |