Skip to content
Draft
Changes from 2 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
114 changes: 114 additions & 0 deletions .github/workflows/ticket-issue-number-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: ticket-issue-number-sync

on:
pull_request:
types: [opened, synchronize]

jobs:
ticket-issue-number-sync:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Extract JIRA ticket number from PR title
id: extract_ticket
run: |
# Extract JIRA ticket number from PR title (e.g., "fix(BA-1234): aaaa" -> "BA-1234")
TITLE="${{ github.event.pull_request.title }}"
echo "PR Title: $TITLE"

# Extract ticket number using regex pattern BA-XXXX format
TICKET_NUMBER=$(echo "$TITLE" | grep -oE 'BA-[0-9]+' | head -1)

if [ -n "$TICKET_NUMBER" ]; then
echo "Extracted ticket: $TICKET_NUMBER"
echo "ticket_number=$TICKET_NUMBER" >> $GITHUB_OUTPUT
echo "has_ticket=true" >> $GITHUB_OUTPUT
else
echo "No JIRA ticket number found in PR title"
echo "has_ticket=false" >> $GITHUB_OUTPUT
fi

- name: Get GitHub Issue URL from JIRA
if: steps.extract_ticket.outputs.has_ticket == 'true'
id: get_jira_issue
env:
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
JIRA_USERNAME: ${{ secrets.JIRA_USERNAME }}
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
run: |
TICKET_NUMBER="${{ steps.extract_ticket.outputs.ticket_number }}"
echo "Fetching GitHub Issue URL for JIRA ticket: $TICKET_NUMBER"

# Get ticket information through JIRA API
JIRA_RESPONSE=$(curl -s -u "$JIRA_USERNAME:$JIRA_API_TOKEN" \
-H "Accept: application/json" \
"$JIRA_BASE_URL/rest/api/3/issue/$TICKET_NUMBER")

echo "JIRA API Response: $JIRA_RESPONSE"

# Extract issue number from GitHub Issue URL field
# Find field that exactly matches "GitHub Issue URL" in JIRA
GITHUB_ISSUE_URL=$(echo "$JIRA_RESPONSE" | jq -r '.fields | to_entries[] | select(.key == "GitHub Issue URL") | .value' 2>/dev/null | head -1)
Copy link

Copilot AI Oct 24, 2025

Choose a reason for hiding this comment

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

The jq query uses .key == "GitHub Issue URL" which attempts to match field keys as literal strings, but JIRA custom field keys are typically in the format customfield_XXXXX, not human-readable names. This query will likely fail to find the field. You should either use the actual custom field ID (e.g., customfield_10001) or query by field name using .fields["GitHub Issue URL"] if the field name is mapped correctly.

Suggested change
GITHUB_ISSUE_URL=$(echo "$JIRA_RESPONSE" | jq -r '.fields | to_entries[] | select(.key == "GitHub Issue URL") | .value' 2>/dev/null | head -1)
# Replace customfield_12345 with your actual custom field ID for "GitHub Issue URL"
GITHUB_ISSUE_URL=$(echo "$JIRA_RESPONSE" | jq -r '.fields["customfield_12345"]' 2>/dev/null)

Copilot uses AI. Check for mistakes.

# Fail immediately if GitHub Issue URL is not found
if [ -z "$GITHUB_ISSUE_URL" ] || [ "$GITHUB_ISSUE_URL" = "null" ]; then
echo "No GitHub Issue URL found in JIRA ticket"
exit 1
fi

echo "Found GitHub Issue URL: $GITHUB_ISSUE_URL"
# Extract GitHub issue number (e.g., https://github.com/owner/repo/issues/123 -> 123)
GITHUB_ISSUE_NUMBER=$(echo "$GITHUB_ISSUE_URL" | grep -oE '/issues/[0-9]+' | grep -oE '[0-9]+' | head -1)

if [ -n "$GITHUB_ISSUE_NUMBER" ]; then
echo "Extracted GitHub Issue Number: $GITHUB_ISSUE_NUMBER"
echo "github_issue_number=$GITHUB_ISSUE_NUMBER" >> $GITHUB_OUTPUT
echo "has_github_issue=true" >> $GITHUB_OUTPUT
else
echo "❌ Could not extract issue number from GitHub Issue URL: $GITHUB_ISSUE_URL"
echo "Please verify the GitHub Issue URL format is correct."
exit 1
fi

- name: Update PR body with resolves clause
if: steps.extract_ticket.outputs.has_ticket == 'true' && steps.get_jira_issue.outputs.has_github_issue == 'true'
env:
TICKET_NUMBER: ${{ steps.extract_ticket.outputs.ticket_number }}
GITHUB_ISSUE_NUMBER: ${{ steps.get_jira_issue.outputs.github_issue_number }}
run: |
echo "Using GitHub issue number: $GITHUB_ISSUE_NUMBER from JIRA"

# Get current PR body
PR_BODY=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }}" | \
jq -r '.body // ""')

echo "Current PR body: $PR_BODY"

# Generate resolves clause
RESOLVES_CLAUSE="resolves #$GITHUB_ISSUE_NUMBER ($TICKET_NUMBER)"
echo "Generated resolves clause: $RESOLVES_CLAUSE"

# Replace existing resolves clause or add new one
if echo "$PR_BODY" | grep -qi "resolves #.*("; then
Copy link

Copilot AI Oct 24, 2025

Choose a reason for hiding this comment

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

The regex pattern resolves #.*( is missing proper escaping for the parenthesis. The ( character should be escaped as \( in grep, otherwise it's treated as a literal character to match. The correct pattern should be resolves #.*\(.

Suggested change
if echo "$PR_BODY" | grep -qi "resolves #.*("; then
if echo "$PR_BODY" | grep -qi "resolves #.*\("; then

Copilot uses AI. Check for mistakes.
# Replace existing resolves clause
NEW_BODY=$(echo "$PR_BODY" | sed -E "s/resolves #[0-9]+ \([^)]+\)/$RESOLVES_CLAUSE/gi")
Copy link

Copilot AI Oct 24, 2025

Choose a reason for hiding this comment

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

The sed command uses the gi flags, but g (global) and i (case-insensitive) flags are not both available in the same sed command syntax. The correct approach in GNU sed is to use I (uppercase) for case-insensitive matching with the -E flag, so this should be s/resolves #[0-9]+ \([^)]+\)/$RESOLVES_CLAUSE/gI.

Suggested change
NEW_BODY=$(echo "$PR_BODY" | sed -E "s/resolves #[0-9]+ \([^)]+\)/$RESOLVES_CLAUSE/gi")
NEW_BODY=$(echo "$PR_BODY" | sed -E "s/resolves #[0-9]+ \([^)]+\)/$RESOLVES_CLAUSE/gI")

Copilot uses AI. Check for mistakes.
echo "Replaced existing resolves clause"
else
# Add new resolves clause
NEW_BODY=$(printf "%s\n\n%s" "$PR_BODY" "$RESOLVES_CLAUSE")
echo "Added new resolves clause"
fi

# Update PR body
curl -s -X PATCH \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
-H "Content-Type: application/json" \
"https://api.github.com/repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }}" \
-d "{\"body\": $(echo "$NEW_BODY" | jq -R -s .)}"

echo "✅ Added resolves clause: $RESOLVES_CLAUSE"
Comment on lines +9 to +124

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI 4 months ago

To fix this, add an explicit permissions block so the GITHUB_TOKEN used by this workflow follows the principle of least privilege. This workflow needs to read PR metadata and update the PR body via the GitHub API, which maps to pull-requests: write. It does not need to push commits or modify repository contents, so contents can be limited to read. The cleanest fix is to add a job-level permissions block under the ticket-issue-number-sync job, above runs-on. This keeps the scope tight and avoids affecting other workflows.

Concretely, in .github/workflows/ticket-issue-number-sync.yml, under jobs:, inside the ticket-issue-number-sync: job, insert:

permissions:
  contents: read
  pull-requests: write

indented to match other job keys. No imports or additional methods are required, since this is purely a workflow configuration change.

Suggested changeset 1
.github/workflows/ticket-issue-number-sync.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/ticket-issue-number-sync.yml b/.github/workflows/ticket-issue-number-sync.yml
--- a/.github/workflows/ticket-issue-number-sync.yml
+++ b/.github/workflows/ticket-issue-number-sync.yml
@@ -6,6 +6,9 @@
 
 jobs:
   ticket-issue-number-sync:
+    permissions:
+      contents: read
+      pull-requests: write
     runs-on: ubuntu-latest
     steps:
     - name: Checkout code
EOF
@@ -6,6 +6,9 @@

jobs:
ticket-issue-number-sync:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: Checkout code
Copilot is powered by AI and may make mistakes. Always verify output.
Loading