성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - JIRA에 등록된 Project의 Version 항목 추가하는 방법</h1> <p> 사내에서 이슈 관리 시스템인 JIRA를 사용하면서 불편한 점이 하나 나왔는데요. 이슈 생성할 때, Version 항목이 미리 등록되어 있지 않으면 그걸 또 등록하러 가야 한다는 것입니다. 이런 불편함을, 제품의 빌드 스크립트에서 버전을 JIRA에 등록하는 방법으로 해결할 수 있습니다. 그리고 이를 위해 JIRA REST API를 사용하게 된 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - JIRA REST API 사용 정리 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11566'>http://www.sysnet.pe.kr/2/0/11566</a> </pre> <br /> 자, 그럼 시작해 볼까요? ^^<br /> <br /> 우선, 해당 프로젝트에 등록된 모든 버전을 가져오는 version API를,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > /rest/api/2/project/{projectIdOrKey}/versions ; <a target='tab' href='https://docs.atlassian.com/software/jira/docs/api/REST/6.1.4/#d2e231'>https://docs.atlassian.com/software/jira/docs/api/REST/6.1.4/#d2e231</a> </pre> <br /> 다음과 같이 작성할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public async Task<string> GetVersions(string projectKey) { string url = _baseUrl + $"project/{projectKey}/versions"; HttpResponseMessage hrm = await _httpClient.GetAsync(url); string text = await hrm.Content.ReadAsStringAsync(); return text; } </pre> <br /> 출력 결과로부터 <a target='tab' href='http://json2csharp.com/'>json2csharp</a>을 통해 다음과 같은 Entity 클래스를 구하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public class Version /* RootObject */ { public string self { get; set; } public string id { get; set; } public string name { get; set; } public bool archived { get; set; } public bool released { get; set; } public string releaseDate { get; set; } public string userReleaseDate { get; set; } public int projectId { get; set; } public bool? overdue { get; set; } public string description { get; set; } public string startDate { get; set; } public string userStartDate { get; set; } } </pre> <br /> API를 다시 다음과 같은 코드로 바꿀 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public async <span style='color: blue; font-weight: bold'>Task<Version[]></span> GetVersions(string projectKey) { string url = _baseUrl + $"project/{projectKey}/versions"; HttpResponseMessage hrm = await _httpClient.GetAsync(url); string text = await hrm.Content.ReadAsStringAsync(); <span style='color: blue; font-weight: bold'>Version [] versionList = Newtonsoft.Json.JsonConvert.DeserializeObject<Version[]>(text);</span> return versionList; } </pre> <br /> 이를 기반으로, "버전 이름"에 해당하는 항목이 등록되어 있는지 알 수 있는 API를 제공할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public async Task<Version> GetVersionByName(string projectKey, string versionName) { Version [] versions = await GetVersions(projectKey); return versions.FirstOrDefault((e) => e.name == versionName); } </pre> <br /> 만약 없다면 새롭게 등록해야 하는데요, 이를 위한 REST API는 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > /rest/api/2/version ; <a target='tab' href='https://docs.atlassian.com/software/jira/docs/api/REST/6.1.4/#d2e3548'>https://docs.atlassian.com/software/jira/docs/api/REST/6.1.4/#d2e3548</a> </pre> <br /> 이때 POST로 Json 데이터를 보내야 하는데 다음과 같은 형식입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > { "description": "An excellent version", "name": "New Version 1", "archived": false, "released": true, "releaseDate": "2010-07-06", "userReleaseDate": "6/Jul/2010", "project": "PXA", "projectId": 10000 } </pre> <br /> POST 데이터의 예제가 저렇게 나오긴 하지만 약간의 규칙이 있습니다.<br /> <br /> <ul> <li>releaseDate와 userReleaseDate는 동시에 보낼 수 없음. (즉, releaseDate만 보내면 됨)</li> <li>projectId가 있으면 project 항목은 안 보내도 됨</li> <li>만약 startDate 필드가 있다면 반드시 releaseDate 날짜 보다 이전이어야 함.</li> </ul> <br /> 여기서 애매한 것이, "projectId" 필드입니다. 보통 "project"는 JIRA 웹 사이트에서 이슈 번호를 통해 쉽게 인지를 하고 있지만 projectId의 경우에는 모르는 경우가 많습니다. 따라서 projectKey로 Id를 구해주는 API를 하나 만들어 두는 것이 좋습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > /rest/api/2/project/{projectIdOrKey} ; <a target='tab' href='https://docs.atlassian.com/software/jira/docs/api/REST/6.1.4/#d2e208'>https://docs.atlassian.com/software/jira/docs/api/REST/6.1.4/#d2e208</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public async Task<Project> GetProjectByKey(string projectKey) { string url = _baseUrl + $"project/{projectKey}"; HttpResponseMessage hrm = await _httpClient.GetAsync(url); string text = await hrm.Content.ReadAsStringAsync(); Project project = Newtonsoft.Json.JsonConvert.DeserializeObject<Project>(text); return project; } </pre> <br /> 이쯤에서 우리가 구현하고 싶은 코드를 정리해 보면 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > { string newVersionName = "myapp-1.0.1"; string projectKey = "myProject"; Project project = await jira.GetProjectByKey(projectKey); if (project == null) { Console.WriteLine("NO Project: " + projectKey); return; } <span style='color: blue; font-weight: bold'>JiraEntity.Version result = await jira.GetVersionByName(projectKey, newVersionName);</span> if (result == null) { // 기존에 등록된 버전이 없다면 신규 등록 JiraEntity.Version version = new JiraEntity.Version(); version.name = newVersionName; version.projectId = Int32.Parse(project.id); version.description = versionDesc; version.startDate = DateTime.Now.ToString("yyyy-MM-dd"); SetReleaseDate(version, releaseDate); result = <span style='color: blue; font-weight: bold'>await jira.CreateVersion(version);</span> if (result != null) { return; } } else { // 기존에 등록된 버전이 있다면 업데이트 result.description = versionDesc; SetReleaseDate(result, releaseDate); result = <span style='color: blue; font-weight: bold'>await jira.UpdateVersion(result);</span> if (result != null) { return; } } } static void SetReleaseDate(JiraEntity.Version version, string releaseDate) { if (releaseDate == null) { return; } version.releaseDate = releaseDate; version.released = true; } </pre> <br /> 이를 위해 새로운 버전을 등록하는 CreateVersion 메서드는 이렇게 만들어 주고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public async Task<JiraEntity.Version> CreateVersion(JiraEntity.Version version) { string url = _baseUrl + "version"; string postData = Newtonsoft.Json.JsonConvert.SerializeObject(version); StringContent content = new StringContent(postData, Encoding.UTF8, "application/json"); HttpResponseMessage hrm = await _httpClient.PostAsync(url, content); string text = await hrm.Content.ReadAsStringAsync(); JiraEntity.Version registeredVersion = Newtonsoft.Json.JsonConvert.DeserializeObject<JiraEntity.Version>(text); return registeredVersion; } </pre> <br /> 기존 버전 정보를 업데이트하는 UpdateVersion 메서드는 다음의 REST API를,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > /rest/api/2/version/{id} ; https://docs.atlassian.com/software/jira/docs/api/REST/6.1.4/#d2e3578 </pre> <br /> PUT으로 호출하면 되므로 이렇게 만들어 줍니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > public async Task<JiraEntity.Version> UpdateVersion(JiraEntity.Version version) { string url = _baseUrl + "version/" + version.id; MakeVersionPutValid(version); string postData = Newtonsoft.Json.JsonConvert.SerializeObject(version); StringContent content = new StringContent(postData, Encoding.UTF8, "application/json"); HttpResponseMessage hrm = await _httpClient.PutAsync(url, content); string text = await hrm.Content.ReadAsStringAsync(); JiraEntity.Version registeredVersion = Newtonsoft.Json.JsonConvert.DeserializeObject<JiraEntity.Version>(text); return registeredVersion; } </pre> <br /> 뭐... 이 정도까지 했으니, 이제 JIRA 정도는 자유자재로 다루실 수 있겠죠?!!! ^^<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1283&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 참고로, REST API에 Post 호출을 했는데 다음과 같은 "HTTP Status 415 - Unsupported Media Type" 오류가 반환된다면?<br /> <br /> <pre style='white-space: pre-wrap; margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <html><head><title>Apache Tomcat/7.0.29 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1><span style='color: blue; font-weight: bold'>HTTP Status 415 - Unsupported Media Type</span></h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>Unsupported Media Type</u></p><p><b>description</b> <u>The server refused this request because the request entity is in a format not supported by the requested resource for the requested method (Unsupported Media Type).</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.29</h3></body></html> </pre> <br /> Post 요청 헤더에 "application/json"을 설정하지 않아서 그런 것입니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
2257
(왼쪽의 숫자를 입력해야 합니다.)