You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求协助:实现分支合并/禁用时关闭关联JIRA工单的Python脚本

Solution: Python Script to Automate JIRA Ticket Closure for Git Events

Got it, let's break down how to build this solution step by step. We'll create two core components: one that closes linked JIRA tickets when a branch is merged into master, and another that checks for disabled branches during the pre-receive hook and closes their associated tickets.

First, let's set up the dependencies and core JIRA integration.

Prerequisites

  • Install the JIRA Python library to handle API interactions:
    pip install jira
    
  • You'll need a JIRA API token (generate this from your JIRA account settings), your JIRA email, and your team's JIRA server URL.

Step 1: Core JIRA Utility Functions

We'll start with a reusable module to handle JIRA connections and ticket closures. This keeps our code clean and easy to reuse across hooks.

from jira import JIRA
from jira.exceptions import JIRAError
import re

# JIRA Configuration - replace these with your team's details
JIRA_SERVER = "https://your-jira-instance.atlassian.net"
JIRA_EMAIL = "your-work-email@company.com"
JIRA_API_TOKEN = "your-generated-api-token"

def get_jira_connection():
    """Establish and return a valid JIRA connection."""
    try:
        return JIRA(
            server=JIRA_SERVER,
            basic_auth=(JIRA_EMAIL, JIRA_API_TOKEN)
        )
    except JIRAError as e:
        print(f"Failed to connect to JIRA: {e.response.text}")
        raise

def close_jira_ticket(ticket_key):
    """Close a JIRA ticket by transitioning it to your team's 'Done' status (adjust as needed)."""
    jira = get_jira_connection()
    try:
        ticket = jira.issue(ticket_key)
        # Find the correct transition ID for closing tickets (match your workflow status)
        transitions = jira.transitions(ticket)
        close_transition = next(t for t in transitions if t['name'] == 'Done')
        
        jira.transition_issue(
            ticket, 
            close_transition['id'], 
            comment="Ticket closed automatically: Branch merged to master or marked as disabled."
        )
        print(f"Successfully closed JIRA ticket {ticket_key}")
    except JIRAError as e:
        print(f"Failed to close ticket {ticket_key}: {e}")
    except StopIteration:
        print(f"No 'Done' transition found for {ticket_key} - check your JIRA workflow settings.")

def extract_jira_keys(text):
    """Pull JIRA ticket keys (e.g., PROJ-123) from branch names or commit messages."""
    pattern = r'([A-Z]{2,}-\d+)'  # Adjust regex to match your team's ticket format
    return re.findall(pattern, text)

Step 2: Pre-Receive Hook for Disabled Branches

The pre-receive hook runs on the Git server before accepting any pushes. We'll use this to check if the pushed branch is disabled, then close its linked JIRA tickets.

Create a file named pre-receive in your Git repo's .git/hooks directory, and add this code:

#!/usr/bin/env python3
import sys
from jira_utils import close_jira_ticket, extract_jira_keys

# Define your team's disabled branches (or load from a config file for scalability)
DISABLED_BRANCHES = ["feature/legacy-module", "bugfix/deprecated-api"]

def handle_pre_receive():
    """Process incoming pushes and close tickets for disabled branches."""
    # Git passes push details via stdin: each line is <old-ref> <new-ref> <branch-name>
    for line in sys.stdin:
        old_ref, new_ref, branch_name = line.strip().split()
        
        # Check if the branch is in our disabled list
        if branch_name in DISABLED_BRANCHES:
            print(f"Detected push to disabled branch: {branch_name}")
            # Extract JIRA keys from the branch name
            jira_keys = extract_jira_keys(branch_name)
            if jira_keys:
                for key in jira_keys:
                    close_jira_ticket(key)
            else:
                print(f"No JIRA keys found in branch name {branch_name}")
            
            # Optional: Reject the push to prevent changes to disabled branches
            # print(f"Push rejected: {branch_name} is marked as disabled")
            # sys.exit(1)

if __name__ == "__main__":
    handle_pre_receive()

Don't forget to make the script executable:

chmod +x .git/hooks/pre-receive

Step 3: Close Tickets When Merging to Master

For this, we'll use a post-receive hook (runs after the push is accepted) to detect when master is updated, extract JIRA keys from commit messages, and close those tickets.

Create .git/hooks/post-receive with this code:

#!/usr/bin/env python3
import sys
import subprocess
from jira_utils import close_jira_ticket, extract_jira_keys

def handle_master_merge():
    """Check for master branch updates and close linked JIRA tickets."""
    # Read push details from stdin
    for line in sys.stdin:
        old_ref, new_ref, branch_name = line.strip().split()
        
        # Only process pushes to the master branch
        if branch_name != "refs/heads/master":
            continue
        
        # Fetch all commit messages between the old and new master ref
        commit_range = f"{old_ref}..{new_ref}"
        try:
            result = subprocess.run(
                ["git", "log", "--oneline", commit_range],
                capture_output=True,
                text=True,
                check=True
            )
            commit_messages = result.stdout.splitlines()
            
            # Collect all unique JIRA keys from commit messages
            all_jira_keys = set()
            for msg in commit_messages:
                keys = extract_jira_keys(msg)
                all_jira_keys.update(keys)
            
            # Close each linked ticket
            if all_jira_keys:
                print(f"Closing JIRA tickets linked to master merge: {', '.join(all_jira_keys)}")
                for key in all_jira_keys:
                    close_jira_ticket(key)
            else:
                print("No JIRA keys found in commit messages for this master merge.")
        except subprocess.CalledProcessError as e:
            print(f"Failed to fetch commit logs: {e}")

if __name__ == "__main__":
    handle_master_merge()

Make this script executable too:

chmod +x .git/hooks/post-receive

Customization Tips

  • JIRA Workflow: Update the transition name ('Done') in close_jira_ticket to match your team's actual ticket-closing status (e.g., 'Resolved', 'Closed').
  • Disabled Branches: Replace the hardcoded DISABLED_BRANCHES list with a config file or database lookup for easier management.
  • Security: Store JIRA credentials in environment variables instead of hardcoding them for production environments.
  • Branch/Commit Format: Adjust the regex in extract_jira_keys if your team uses a different ticket naming pattern.

内容的提问来源于stack exchange,提问作者Pavan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:06:07