redmineで定例会議チケットを発行してもらうスクリプト

ChatGPTさんに作ってもらいました

2023/04/13
冗長になったので、リライトしています。

# Python-Redmine利用版

## 質問

あなたはPythonエンジニアです。
redmineに週次の定例会議のチケットを発行したいです。
以下の条件を満たすPythonプログラムを作ってください。
cronに関する回答は不要です。

・プログラムはcronで毎日実行される
・以下のcsvファイルをインプットとする。
　開催曜日,チケット発行曜日,雛形チケット
・雛形チケットをコピーして、タイトルにある(yyyy/mm/dd)の記載を開催日(チケット発行日以降、直近となる開催曜日)に書き換え
・雛形チケットに子チケットがある場合は子チケットもすべて同様に処理
・python-redmineモジュールを使う。バージョンは2.4.0とする。
・作成したチケットの開始日はチケット発行日、期日は開催曜日に設定する


## 回答

redmine.issue.copyを使わず、新しいチケットを作成し、属性をコピーするプログラムを以下に示します。

```python
import csv
import datetime
from redminelib import Redmine

# Redmine接続設定
redmine_url = 'https://your_redmine_url'
api_key = 'your_api_key'
redmine = Redmine(redmine_url, key=api_key)

# 曜日を数値に変換する辞書
day_name_to_number = {
    '月': 0,
    '火': 1,
    '水': 2,
    '木': 3,
    '金': 4,
    '土': 5,
    '日': 6,
}

def create_new_ticket(template_ticket, due_date):
    new_ticket = redmine.issue.new()
    new_ticket.project_id = template_ticket.project.id
    new_ticket.tracker_id = template_ticket.tracker.id
    new_ticket.subject = template_ticket.subject.replace('(yyyy/mm/dd)', due_date.strftime('%Y/%m/%d'))
    new_ticket.description = template_ticket.description
    new_ticket.status_id = template_ticket.status.id
    new_ticket.priority_id = template_ticket.priority.id
    new_ticket.assigned_to_id = template_ticket.assigned_to.id if hasattr(template_ticket, 'assigned_to') else None
    new_ticket.start_date = datetime.date.today()
    new_ticket.due_date = due_date
    new_ticket.save()

    return new_ticket

def process_template_ticket(template_ticket, due_date):
    new_ticket = create_new_ticket(template_ticket, due_date)

    for child in template_ticket.children:
        child_template_ticket = redmine.issue.get(child.id)
        process_template_ticket(child_template_ticket, due_date)

with open('input.csv', newline='', encoding='utf-8') as csvfile:
    reader = csv.reader(csvfile)
    next(reader, None)  # ヘッダ行をスキップ

    for row in reader:
        meeting_day, issue_day, template_ticket_id = row
        meeting_day_number = day_name_to_number[meeting_day]
        issue_day_number = day_name_to_number[issue_day]

        today = datetime.date.today()
        today_day_number = today.weekday()

        if today_day_number == issue_day_number:
            days_until_meeting = (meeting_day_number - today_day_number) % 7
            meeting_date = today + datetime.timedelta(days=days_until_meeting)

            template_ticket = redmine.issue.get(template_ticket_id)
            process_template_ticket(template_ticket, meeting_date)
```


# Python-Redmine APIを使えない場合(requests利用)

## 質問

python-redmine を使わないバージョンを作ってください

## 回答

```Python
import csv
import datetime
import requests

# Redmine接続設定
redmine_url = 'https://your_redmine_url'
api_key = 'your_api_key'

# 曜日を数値に変換する辞書
day_name_to_number = {
    '月': 0,
    '火': 1,
    '水': 2,
    '木': 3,
    '金': 4,
    '土': 5,
    '日': 6,
}

headers = {'Content-Type': 'application/json', 'X-Redmine-API-Key': api_key}

def create_new_ticket(template_ticket, due_date):
    new_ticket = {
        'issue': {
            'project_id': template_ticket['project']['id'],
            'tracker_id': template_ticket['tracker']['id'],
            'subject': template_ticket['subject'].replace('(yyyy/mm/dd)', due_date.strftime('%Y/%m/%d')),
            'description': template_ticket['description'],
            'status_id': template_ticket['status']['id'],
            'priority_id': template_ticket['priority']['id'],
            'assigned_to_id': template_ticket['assigned_to']['id'] if 'assigned_to' in template_ticket else None,
            'start_date': datetime.date.today().isoformat(),
            'due_date': due_date.isoformat(),
        }
    }

    response = requests.post(f'{redmine_url}/issues.json', json=new_ticket, headers=headers)
    return response.json()['issue']

def process_template_ticket(template_ticket, due_date):
    new_ticket = create_new_ticket(template_ticket, due_date)

    if 'children' in template_ticket:
        for child in template_ticket['children']:
            child_template_ticket = requests.get(f'{redmine_url}/issues/{child["id"]}.json', headers=headers).json()['issue']
            process_template_ticket(child_template_ticket, due_date)

with open('input.csv', newline='', encoding='utf-8') as csvfile:
    reader = csv.reader(csvfile)
    next(reader, None)  # ヘッダ行をスキップ

    for row in reader:
        meeting_day, issue_day, template_ticket_id = row
        meeting_day_number = day_name_to_number[meeting_day]
        issue_day_number = day_name_to_number[issue_day]

        today = datetime.date.today()
        today_day_number = today.weekday()

        if today_day_number == issue_day_number:
            days_until_meeting = (meeting_day_number - today_day_number) % 7
            meeting_date = today + datetime.timedelta(days=days_until_meeting)

            template_ticket = requests.get(f'{redmine_url}/issues/{template_ticket_id}.json?include=children', headers=headers).json()['issue']
            process_template_ticket(template_ticket, meeting_date)

```