YouTrack과 Azure DevOps를 통합하는 방법
43854 단어 javascriptyoutrackazuredevops
그러나 YouTrack에 대한 경험이 있다면 엄청난 잠재력을 가지고 있고 확장 지점 역할을 할 수 있는 워크플로우의 개념에 익숙해야 합니다. 스크립트는 Javascript로 작성되며 일정에 따라 트리거를 기반으로 실행할 수 있습니다.
우리의 아이디어는 이슈가 진행 중이 되면 이슈 ID 이름으로 기능 분기를 자동으로 생성하고 이슈가 풀 요청 상태에 있으면 풀 요청을 생성하는 것이었습니다. 분기 및 풀 요청에 대한 링크가 이슈에 필드로 추가됩니다.
먼저 여러 스크립트 간에 공유되는 리소스에 대한 공통 파일을 만들었습니다.
var http = require('@jetbrains/youtrack-scripting-api/http');
function issueUrl(id) {
return "https://youryoutrackinstanceurl/issue/" + id;
}
class Azure {
constructor() {
this.organization = "your-azure-devops-organization";
this.project = "Name of the Azure DevOps project";
this.repository = "Name of the repository";
this.defaultReviewers = [{
"id": "ccd7d2cf-7120-4655-836e-a3ae28256dbd",
}];
this.login = "[email protected]";
this.PAT = "fdewqk321n55l55x7qmsfnlgdpbqnyhvdakdfsnczpwbriqjbhxvq";
}
url(api, item, operation, api_version) {
var link = "https://dev.azure.com/" + this.organization + "/" + this.project + "/_apis/" + api;
if (item)
link += "/" + item;
if (operation)
link += "/" + operation;
if (api_version)
link += (link.includes("?") ? "&" : "?") + "api-version=" + api_version;
return link;
}
branchUrl(branchName) {
return "https://dev.azure.com/" + this.organization + "/" + this.project + "/_git/" + this.repository + "?version=GB" + branchName;
}
prUrl(id) {
return "https://dev.azure.com/" + this.organization + "/" + this.project + "/_git/" + this.repository + "/pullrequest/" + id;
}
connection() {
var connection = new http.Connection("", null, 2000);
connection.basicAuth(this.login, this.PAT);
return connection;
}
getFrom(url) {
var connection = this.connection();
var resp = connection.getSync(url);
if (!resp.isSuccess) {
throw new Error("" + resp.code);
}
return JSON.parse(resp.response);
}
sendTo(url, data, mimeType = "application/json", action = "post") {
var connection = this.connection();
connection.addHeader({
name: "Content-Type",
value: mimeType
});
var resp = action == "patch" ? connection.patchSync(url, null, data) : connection.postSync(url, null, data);
if (!resp.isSuccess) {
throw new Error("" + resp.code);
}
return JSON.parse(resp.response);
}
}
module.exports.Azure = Azure;
module.exports.issueUrl = issueUrl;
Azure의 생성자에서 projectName 매개 변수를 전달하면 보다 유연한 솔루션을 얻을 수 있지만 간단하게 하기 위해 샘플에 추가하지 않았습니다. 그리고 같은 이유로 이 예에서 PAT 인증을 사용했습니다.
다음으로 문제에 대한 작업이 시작되면 분기를 생성하는 스크립트를 추가했습니다. 우리의 경우 진행 중 상태로 푸시하여 표시됩니다.
var common = require('./common');
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: "Create branch for issue",
guard: function(ctx) {
return ctx.issue.becomes(ctx.State, ctx.State.InProgress);
},
action: function(ctx) {
logger.log("Creating branch for issue " + ctx.issue.id);
try {
const azure = new common.Azure();
var issueBranchName = ctx.issue.id;
var issueBranch = azure.getFrom(azure.url("git/repositories", azure.repository, "refs?filter=heads/&filterContains=" + issueBranchName, "6.0"));
if (issueBranch && issueBranch.count && (issueBranch.value[0].name == "refs/heads/" + issueBranchName)) {
ctx.issue.fields.Branch = azure.branchUrl(issueBranchName);
return;
}
var parentBranchName = "main";
var repository = azure.getFrom(azure.url("git/repositories", azure.repository, null, "6.0"));
var createBranchUrl = azure.url("git/repositories", repository.id, "refs", "6.0");
var parentBranch = azure.getFrom(azure.url("git/repositories", azure.repository, "refs?filter=heads/&filterContains=" + parentBranchName, "6.0"));
if (!parentBranch.count) {
workflow.message(workflow.i18n('Branch ' + parentBranchName + " not found in repository"));
return;
}
var parentObjectId = parentBranch.value[0].objectId;
var data = [{
"name": "refs/heads/" + issueBranchName,
"oldObjectId": "0000000000000000000000000000000000000000",
"newObjectId": parentObjectId
}];
var response = azure.sendTo(createBranchUrl, JSON.stringify(data));
if (!response || (response.count != 1) || !response.value[0].success) {
workflow.message(workflow.i18n('Failed to create Azure DevOps branch ') + issueBranchName);
workflow.message(response);
return;
}
workflow.message(workflow.i18n('Created Azure DevOps branch ') + issueBranchName);
ctx.issue.fields.Branch = azure.branchUrl(issueBranchName);
} catch (e) {
workflow.message(workflow.i18n('Failed to access Azure DevOps') + "\n" + e.message);
}
},
requirements: {
State: {
name: "State",
type: entities.State.fieldType,
InProgress: {
name: "In Progress"
}
},
BranchField: {
name: "Branch",
type: entities.Field.stringType
}
}
});
마지막 단계는 양수인이 문제의 상태를 풀 요청으로 설정하면 풀 요청을 생성하는 것입니다.
var common = require('./common');
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: "Create PR for issue",
guard: function(ctx) {
return ctx.issue.becomes(ctx.State, ctx.StateState.PullRequest);
},
action: function(ctx) {
try {
const azure = new common.Azure();
var issueBranchName = ctx.issue.id;
var issueBranch = azure.getFrom(azure.url("git/repositories", azure.repository, "refs?filter=heads/&filterContains=" + issueBranchName, "6.0"));
if (!issueBranch || !issueBranch.count || (issueBranch.value[0].name != "refs/heads/" + issueBranchName)) {
workflow.message(workflow.i18n('Issue branch ' + issueBranchName + ' not found'));
return;
}
var parentBranchName = "main";
var repository = azure.getFrom(azure.url("git/repositories", azure.repository, null, "6.0"));
var existingPr = azure.getFrom(azure.url("git/repositories", repository.id, "pullrequests?searchCriteria.sourceRefName=refs/heads/" + issueBranchName + "&searchCriteria.status=active&searchCriteria.targetRefName=refs/heads/" + parentBranchName, "6.0"));
if (existingPr && existingPr.count && existingPr.value[0]) {
var prId = existingPr.value[0].pullRequestId;
workflow.message(workflow.i18n('PR ' + prId + ' already active'));
ctx.issue.fields.PR = azure.prUrl(prId);
return;
}
var createPrUrl = azure.url("git/repositories", repository.id, "pullrequests", "6.0");
var data = {
"sourceRefName": "refs/heads/" + issueBranchName,
"targetRefName": "refs/heads/" + parentBranchName,
"title": ctx.issue.id + " " + ctx.issue.summary,
"description": common.issueUrl(ctx.issue.id),
"reviewers": azure.defaultReviewers
};
var response = azure.sendTo(createPrUrl, JSON.stringify(data));
if (!response || !response.pullRequestId) {
workflow.message(workflow.i18n('Failed to create PR for branch ') + issueBranchName);
return;
}
var prId = r.pullRequestId;
workflow.message(workflow.i18n('Created PR ') + prId);
ctx.issue.fields.PR = azure.prUrl(prId);
} catch (e) {
workflow.message(workflow.i18n('Failed to access Azure DevOps') + "\n" + e.message);
}
},
requirements: {
State: {
name: "State",
type: entities.State.fieldType,
PullRequest: {
name: "Pull request"
},
}
}
});
그게 다야! 로깅을 추가하는 것이 좋습니다. 모든 티켓이 통합 워크플로를 트리거하지 않도록 티켓 유형에 제약 조건을 추가할 수 있습니다.
가능성은 무한합니다.
Reference
이 문제에 관하여(YouTrack과 Azure DevOps를 통합하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/darkym/how-to-integrate-youtrack-and-azure-devops-5hcj텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)