[Feat] jira 연동 작업 #9
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Sync GitHub Issues with Jira | |
on: | |
issues: | |
types: [opened, edited, labeled, unlabeled, closed, reopened] | |
issue_comment: | |
types: [created, edited, deleted] | |
jobs: | |
sync_with_jira: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Check out repository | |
uses: actions/checkout@v2 | |
- name: Set up Node.js | |
uses: actions/setup-node@v2 | |
with: | |
node-version: '14' | |
- name: Sync GitHub Issues with Jira | |
env: | |
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} | |
JIRA_EMAIL: ${{ secrets.JIRA_EMAIL }} | |
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
run: | | |
node <<EOF | |
const https = require('https'); | |
const jiraBaseUrl = process.env.JIRA_BASE_URL; | |
const jiraEmail = process.env.JIRA_EMAIL; | |
const jiraApiToken = process.env.JIRA_API_TOKEN; | |
const githubToken = process.env.GITHUB_TOKEN; | |
const issue = process.env.GITHUB_EVENT_PATH ? require(process.env.GITHUB_EVENT_PATH).issue : null; | |
const action = process.env.GITHUB_EVENT_PATH ? require(process.env.GITHUB_EVENT_PATH).action : null; | |
if (!issue) { | |
console.log('No issue information available.'); | |
process.exit(0); | |
} | |
const jiraAuth = Buffer.from(\`\${jiraEmail}:\${jiraApiToken}\`).toString('base64'); | |
const jiraSearchUrl = new URL('/rest/api/3/search', jiraBaseUrl); | |
function httpsRequest(url, options, data) { | |
return new Promise((resolve, reject) => { | |
const req = https.request(url, options, (res) => { | |
let body = ''; | |
res.on('data', (chunk) => { | |
body += chunk; | |
}); | |
res.on('end', () => { | |
if (res.statusCode >= 200 && res.statusCode < 300) { | |
resolve(JSON.parse(body)); | |
} else { | |
reject(new Error(body)); | |
} | |
}); | |
}); | |
req.on('error', reject); | |
if (data) { | |
req.write(data); | |
} | |
req.end(); | |
}); | |
} | |
async function getJiraIssueKey(issueTitle) { | |
try { | |
console.log("issueTitle" + issueTitle) | |
const jql = \`project=NOFFICE AND "Epic Link"=NOFFICE-33 AND summary~"\${issueTitle}"\`; | |
const searchParams = new URLSearchParams({ jql: jql }); | |
jiraSearchUrl.search = searchParams.toString(); | |
const options = { | |
method: 'GET', | |
headers: { | |
'Authorization': \`Basic \${jiraAuth}\`, | |
'Content-Type': 'application/json' | |
} | |
}; | |
const response = await httpsRequest(jiraSearchUrl, options); | |
const issues = response.issues; | |
if (issues.length > 0) { | |
return issues[0].key; | |
} else { | |
console.log('No matching Jira issue found.'); | |
return null; | |
} | |
} catch (error) { | |
console.error('Error fetching Jira issue:', error.message); | |
return null; | |
} | |
} | |
async function updateJiraIssue(jiraIssueKey) { | |
try { | |
const jiraIssueUrl = new URL(\`/rest/api/3/issue/\${jiraIssueKey}\`, jiraBaseUrl); | |
const githubIssueUrl = issue.html_url; | |
const updateData = JSON.stringify({ | |
fields: { | |
summary: issue.title, | |
description: issue.body + \`\n\n[View on GitHub](\${githubIssueUrl})\` | |
} | |
}); | |
const options = { | |
method: 'PUT', | |
headers: { | |
'Authorization': \`Basic \${jiraAuth}\`, | |
'Content-Type': 'application/json' | |
} | |
}; | |
await httpsRequest(jiraIssueUrl, options, updateData); | |
if (action === 'labeled' || action === 'unlabeled') { | |
const labels = issue.labels.map(label => label.name); | |
const updateLabelsData = JSON.stringify({ | |
update: { | |
labels: labels.map(label => ({ set: { value: label } })) | |
} | |
}); | |
await httpsRequest(jiraIssueUrl, options, updateLabelsData); | |
} | |
if (action === 'closed') { | |
const transitionData = JSON.stringify({ | |
transition: { | |
id: '31' // Transition ID for Done | |
} | |
}); | |
await httpsRequest(new URL(\`\${jiraIssueUrl}/transitions\`, jiraBaseUrl), { | |
method: 'POST', | |
headers: options.headers | |
}, transitionData); | |
} | |
if (action === 'reopened') { | |
const transitionData = JSON.stringify({ | |
transition: { | |
id: '11' // Transition ID for Reopened | |
} | |
}); | |
await httpsRequest(new URL(\`\${jiraIssueUrl}/transitions\`, jiraBaseUrl), { | |
method: 'POST', | |
headers: options.headers | |
}, transitionData); | |
} | |
console.log('Jira issue updated successfully.'); | |
} catch (error) { | |
console.error('Error updating Jira issue:', error.message); | |
} | |
} | |
async function main() { | |
const jiraIssueKey = await getJiraIssueKey(issue.title); | |
if (jiraIssueKey) { | |
await updateJiraIssue(jiraIssueKey); | |
} | |
} | |
main(); | |
EOF |