Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/ISSUE_TEMPLATE/qa-task.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: QA Task
description: QA용 이슈 템플릿입니다.(기존 JIRA의 이슈와 연동됩니다)
title: "qa] "
labels: ["🛠️ qa"]
body:
- type: input
id: parentKey
attributes:
label: '🎟️ 작업 (Ticket Number)'
description: '연동할 작업의 Ticket Number를 기입해주세요'
placeholder: 'BOOK-00'
validations:
required: true

- type: input
id: description
attributes:
label: "🛠️ qa 설명"
description: "어떤 qa 항목에 대한 수정사항인지 명확히 작성해주세요"
validations:
required: true

- type: textarea
id: tasks
attributes:
label: "🔧 수정할 작업 목록"
description: "수정해야 할 항목들을 체크리스트로 작성해주세요"
value: |
- [ ] ..
validations:
required: true

- type: input
id: links
attributes:
label: "🔗 참고 링크"
description: "관련 문서, 스크린샷, 로그 등이 있다면 첨부해주세요 (선택)"
placeholder: "https://..."
validations:
required: false

42 changes: 24 additions & 18 deletions .github/workflows/PR_Label_Assign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,49 @@ on:
jobs:
label-pr:
runs-on: ubuntu-latest

# 기본 GITHUB_TOKEN 대신 PAT을 쓰기 때문에 permissions 블록은 생략 가능
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
token: ${{ secrets.PAT_TOKEN }}

- name: Label PR based on title
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
github-token: ${{ secrets.PAT_TOKEN }}
script: |
const title = context.payload.pull_request.title || "";

console.log(`📋 PR Title: ${title}`);

const labelMap = [
{ pattern: /^feat:/i, label: '✨ feat' },
{ pattern: /^fix:/i, label: '🐞 fix' },
{ pattern: /^refactor:/i, label: '🔨 refactor' },
{ pattern: /^docs:/i, label: '📃 docs' },
{ pattern: /^chore:/i, label: '⚙️ chore' },
{ pattern: /^chore:/i, label: '⚙️ chore' },
{ pattern: /^test:/i, label: '✅ test' },
{ pattern: /^style:/i, label: '🎨 style' }
{ pattern: /^style:/i, label: '🎨 style' },
{ pattern: /^qa:/i, label: '🛠️ qa' }
];

// 매칭되는 라벨 찾기
const labelsToAdd = labelMap
.filter(entry => entry.pattern.test(title))
.map(entry => entry.label);

if (labelsToAdd.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: labelsToAdd
});
core.info(`Added labels: ${labelsToAdd.join(', ')}`);
console.log(`✅ Adding labels: ${labelsToAdd.join(', ')}`);

try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: labelsToAdd
});

console.log(`✅ Successfully added labels: ${labelsToAdd.join(', ')}`);
} catch (error) {
console.error(`❌ Failed to add labels: ${error.message}`);
core.setFailed(`Failed to add labels: ${error.message}`);
}
} else {
core.info('No matching labels found for PR title.');
console.log('⚠️ No matching labels found for PR title.');
console.log('💡 Tip: Use prefixes like "feat:", "fix:", "qa:", etc.');
}
89 changes: 78 additions & 11 deletions .github/workflows/close-jira-issue.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Close Jira issue
name: Close Jira Issue

on:
issues:
Expand All @@ -8,7 +8,6 @@ on:
jobs:
close-issue:
runs-on: ubuntu-latest

steps:
- name: Login to Jira
uses: atlassian/gajira-login@v3
Expand All @@ -20,22 +19,90 @@ jobs:
- name: Extract Jira issue key from GitHub issue title
id: extract-key
run: |
ISSUE_TITLE="${{ github.event.issue.title }}"
JIRA_KEY=$(echo "$ISSUE_TITLE" | grep -oE '[A-Z]+-[0-9]+' || true)
echo "JIRA_KEY=$JIRA_KEY" >> $GITHUB_ENV
ISSUE_TITLE=$(cat <<'EOF'
${{ github.event.issue.title }}
EOF
)

echo "📋 Issue Title: $ISSUE_TITLE"

# 대괄호 안의 Jira 키 우선 추출 (예: [BOOK-123] 작업명)
JIRA_KEY=$(echo "$ISSUE_TITLE" | grep -oP '(?<=\[)[A-Z]+-\d+(?=\])' | head -1)

# 없으면 일반 패턴으로 추출
if [ -z "$JIRA_KEY" ]; then
JIRA_KEY=$(echo "$ISSUE_TITLE" | grep -oP '\b[A-Z]+-\d+\b' | head -1)
fi

if [ -z "$JIRA_KEY" ]; then
echo "⚠️ No Jira key found in issue title"
echo "JIRA_KEY=" >> $GITHUB_ENV
echo "found=false" >> $GITHUB_OUTPUT
else
echo "✅ Found Jira key: $JIRA_KEY"
echo "JIRA_KEY=$JIRA_KEY" >> $GITHUB_ENV
echo "found=true" >> $GITHUB_OUTPUT
fi

Comment on lines 19 to +46
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🔒 신뢰할 수 없는 입력값 처리: 환경 변수 사용 권장

GitHub Actions 보안 가이드라인에 따르면, 신뢰할 수 없는 입력값(github.event.issue.title)은 환경 변수를 통해 전달하는 것이 권장됩니다. HERE 문서 방식보다 환경 변수를 사용하면 스크립트 인젝션 위험을 더 효과적으로 완화할 수 있습니다.

      - name: Extract Jira issue key from GitHub issue title
        id: extract-key
+       env:
+         ISSUE_TITLE: ${{ github.event.issue.title }}
        run: |
-         ISSUE_TITLE=$(cat <<'EOF'
-         ${{ github.event.issue.title }}
-         EOF
-         )
+         ISSUE_TITLE="${ISSUE_TITLE}"
          
          echo "📋 Issue Title: $ISSUE_TITLE"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Extract Jira issue key from GitHub issue title
id: extract-key
run: |
ISSUE_TITLE="${{ github.event.issue.title }}"
JIRA_KEY=$(echo "$ISSUE_TITLE" | grep -oE '[A-Z]+-[0-9]+' || true)
echo "JIRA_KEY=$JIRA_KEY" >> $GITHUB_ENV
ISSUE_TITLE=$(cat <<'EOF'
${{ github.event.issue.title }}
EOF
)
echo "📋 Issue Title: $ISSUE_TITLE"
# 대괄호 안의 Jira 키 우선 추출 (예: [BOOK-123] 작업명)
JIRA_KEY=$(echo "$ISSUE_TITLE" | grep -oP '(?<=\[)[A-Z]+-\d+(?=\])' | head -1)
# 없으면 일반 패턴으로 추출
if [ -z "$JIRA_KEY" ]; then
JIRA_KEY=$(echo "$ISSUE_TITLE" | grep -oP '\b[A-Z]+-\d+\b' | head -1)
fi
if [ -z "$JIRA_KEY" ]; then
echo "⚠️ No Jira key found in issue title"
echo "JIRA_KEY=" >> $GITHUB_ENV
echo "found=false" >> $GITHUB_OUTPUT
else
echo "✅ Found Jira key: $JIRA_KEY"
echo "JIRA_KEY=$JIRA_KEY" >> $GITHUB_ENV
echo "found=true" >> $GITHUB_OUTPUT
fi
- name: Extract Jira issue key from GitHub issue title
id: extract-key
env:
ISSUE_TITLE: ${{ github.event.issue.title }}
run: |
ISSUE_TITLE="${ISSUE_TITLE}"
echo "📋 Issue Title: $ISSUE_TITLE"
# 대괄호 안의 Jira 키 우선 추출 (예: [BOOK-123] 작업명)
JIRA_KEY=$(echo "$ISSUE_TITLE" | grep -oP '(?<=\[)[A-Z]+-\d+(?=\])' | head -1)
# 없으면 일반 패턴으로 추출
if [ -z "$JIRA_KEY" ]; then
JIRA_KEY=$(echo "$ISSUE_TITLE" | grep -oP '\b[A-Z]+-\d+\b' | head -1)
fi
if [ -z "$JIRA_KEY" ]; then
echo "⚠️ No Jira key found in issue title"
echo "JIRA_KEY=" >> $GITHUB_ENV
echo "found=false" >> $GITHUB_OUTPUT
else
echo "✅ Found Jira key: $JIRA_KEY"
echo "JIRA_KEY=$JIRA_KEY" >> $GITHUB_ENV
echo "found=true" >> $GITHUB_OUTPUT
fi
🧰 Tools
🪛 actionlint (1.7.8)

21-21: "github.event.issue.title" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)

- name: Stop if no Jira key
if: steps.extract-key.outputs.found == 'false'
run: |
echo "⚠️ No Jira key found. Skipping Jira transition."
exit 0

- name: Get available transitions
if: ${{ env.JIRA_KEY != '' }}
if: steps.extract-key.outputs.found == 'true'
id: transitions
continue-on-error: true
run: |
curl -u ${{ secrets.JIRA_USER_EMAIL }}:${{ secrets.JIRA_API_TOKEN }} \
echo "🔍 Checking available transitions for ${{ env.JIRA_KEY }}"

RESPONSE=$(curl -s -u ${{ secrets.JIRA_USER_EMAIL }}:${{ secrets.JIRA_API_TOKEN }} \
-X GET \
-H "Content-Type: application/json" \
"${{ secrets.JIRA_BASE_URL }}/rest/api/3/issue/${{ env.JIRA_KEY }}/transitions" \
| jq '.transitions[] | {id, name, to: .to.name}'

"${{ secrets.JIRA_BASE_URL }}/rest/api/3/issue/${{ env.JIRA_KEY }}/transitions")

echo "$RESPONSE" | jq '.transitions[] | {id, name, to: .to.name}'

# 개발 완료 transition이 있는지 확인
HAS_TRANSITION=$(echo "$RESPONSE" | jq -r '.transitions[] | select(.name == "개발 완료") | .id')

if [ -n "$HAS_TRANSITION" ]; then
echo "transition_available=true" >> $GITHUB_OUTPUT
echo "✅ '개발 완료' transition is available (ID: $HAS_TRANSITION)"
else
echo "transition_available=false" >> $GITHUB_OUTPUT
echo "⚠️ '개발 완료' transition is not available"
echo "Available transitions:"
echo "$RESPONSE" | jq -r '.transitions[] | .name'
fi

- name: Close Jira issue
if: ${{ env.JIRA_KEY != '' }}
if: |
steps.extract-key.outputs.found == 'true' &&
steps.transitions.outputs.transition_available == 'true'
uses: atlassian/gajira-transition@v3
with:
issue: ${{ env.JIRA_KEY }}
transition: 개발 완료

- name: Add comment to GitHub issue
if: |
steps.extract-key.outputs.found == 'true' &&
steps.transitions.outputs.transition_available == 'true'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
✅ **Jira Issue Closed:** [${{ env.JIRA_KEY }}](${{ secrets.JIRA_BASE_URL }}/browse/${{ env.JIRA_KEY }})
Status transitioned to: **개발 완료**

- name: Log transition failure
if: |
steps.extract-key.outputs.found == 'true' &&
steps.transitions.outputs.transition_available == 'false'
run: |
echo "❌ Failed to transition ${{ env.JIRA_KEY }} to '개발 완료'"
echo "The issue might already be in that state or the transition is not available."
Loading