0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Redmineにチケットを登録してみる

Last updated at Posted at 2025-07-15

初めに

Redmine向けチケット作成ソフトを扱ったときに, きちんと動作するかcurlを使ってテストしたのでその方法を説明します.

ここでは, 以下のチケット作成ソフトをもとにしています.
Github redmine-ticket-creater

環境

Python(3.12.3)
Redmine(6.0.4)

Pythonライブラリ

fastAPI(0.116.1)
requests
json
os

チケット作成プログラム

以下がチケット作成プログラムです.

#app.py

# --- 設定 ---

from fastapi import FastAPI, Request
import requests
import os

# --- 設定はすべて環境変数で ---
REDMINE_URL = os.getenv("REDMINE_URL")
API_KEY = os.getenv("REDMINE_API_KEY")
PROJECT_ID = os.getenv("REDMINE_PROJECT_ID")
TRACKER_ID = int(os.getenv("REDMINE_TRACKER_ID"))  # 例: 1=Bug, 10=1次調査 など
OPEN_STATUS_ID = int(os.getenv("REDMINE_OPEN_STATUS_ID"))    # 例: 1=未着手
CLOSE_STATUS_ID = int(os.getenv("REDMINE_CLOSE_STATUS_ID"))  # 例: 8=完了

app = FastAPI()

# チケット作成
def create_redmine_issue(subject, description):
    url = f"{REDMINE_URL}/issues.json"
    headers = {"X-Redmine-API-Key": API_KEY, "Content-Type": "application/json"}
    payload = {
        "issue": {
            "project_id": PROJECT_ID,
            "tracker_id": TRACKER_ID,
            "subject": subject,
            "description": description,
            "status_id": OPEN_STATUS_ID
        }
    }
    r = requests.post(url, json=payload, headers=headers)
    if r.status_code == 201:
        return r.json()["issue"]["id"]
    else:
        print(f"Create error: {r.text}")
        return None

# チケット検索(未完了のみ)
def find_existing_issue(subject):
    url = f"{REDMINE_URL}/issues.json?project_id={PROJECT_ID}&subject=~{subject}&status_id=open"
    headers = {"X-Redmine-API-Key": API_KEY}
    r = requests.get(url, headers=headers)
    if r.status_code == 200 and r.json()["issues"]:
        return r.json()["issues"][0]
    return None

# チケットを完了に
def close_redmine_issue(issue_id):
    url = f"{REDMINE_URL}/issues/{issue_id}.json"
    headers = {"X-Redmine-API-Key": API_KEY, "Content-Type": "application/json"}
    payload = {"issue": {"status_id": CLOSE_STATUS_ID}}
    r = requests.put(url, json=payload, headers=headers)
    return r.status_code == 200

@app.post("/webhook")
async def webhook(request: Request):
    data = await request.json()
    alerts = data.get("alerts", [])
    result = []
    for alert in alerts:
        labels = alert.get("labels", {})
        alertname = labels.get("alertname", "unknown")
        instance = labels.get("instance", "unknown")
        status = alert.get("status", "")
        subject = f"{alertname}:{instance}"
        description = alert.get("annotations", {}).get("summary", "")

        if status == "firing":
            # firing時は同じsubjectの未完了チケットがなければ新規作成
            issue = find_existing_issue(subject)
            if not issue:
                issue_id = create_redmine_issue(subject, description)
                result.append({"created": issue_id})
            else:
                result.append({"already_exists": issue["id"]})
        elif status == "resolved":
            # resolved時は同じsubjectの未完了チケットがあれば完了にする
            issue = find_existing_issue(subject)
            if issue:
                close_redmine_issue(issue["id"])
                result.append({"closed": issue["id"]})
            else:
                result.append({"no_open_issue": subject})
    return {"result": result}

ディレクトリ構成

c0117304@c0117304-test:~$s
└─tickets-auto-close/
  ├─app.py
  └─venv

準備

python3を使って仮想環境で動かすので, 諸々インストールが必要です.

既にインストールしてある環境でもう一度実行しているので, 若干出力が違う場合があります.

・python3の確認
 UbuntuではPythonがあらかじめ入っています.

c0117304@c0117304-test:~$ sudo apt install python3
[sudo] password for c0117304:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
python3 is already the newest version (3.12.3-0ubuntu2).
0 upgraded, 0 newly installed, 0 to remove and 75 not upgraded.
c0117304@c0117304-test:~$

以下でバージョンを確認できます.

c0117304@c0117304-test:~$ python3 --version
Python 3.12.3
c0117304@c0117304-test:~$ 

・仮想環境をインストールします

c0117304@c0117304-test:~/tickets-auto-close$ sudo apt update
                                             sudo apt install python3-venv
Hit:1 http://jp.archive.ubuntu.com/ubuntu noble InRelease
Get:2 http://jp.archive.ubuntu.com/ubuntu noble-updates InRelease [126 kB]
Get:3 http://jp.archive.ubuntu.com/ubuntu noble-backports InRelease [126 kB]
Get:4 http://jp.archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages [1,238 kB]
Get:5 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]
Get:6 http://jp.archive.ubuntu.com/ubuntu noble-updates/main amd64 Components [163 kB]
Get:7 http://jp.archive.ubuntu.com/ubuntu noble-updates/restricted amd64 Components [212 B]
Get:8 http://jp.archive.ubuntu.com/ubuntu noble-updates/universe amd64 Packages [1,106 kB]
Get:9 http://jp.archive.ubuntu.com/ubuntu noble-updates/universe Translation-en [282 kB]
Get:10 http://jp.archive.ubuntu.com/ubuntu noble-updates/universe amd64 Components [377 kB]
Get:11 http://jp.archive.ubuntu.com/ubuntu noble-updates/multiverse amd64 Components [940 B]
Get:12 http://jp.archive.ubuntu.com/ubuntu noble-backports/main amd64 Components [7,060 B]
Get:13 http://jp.archive.ubuntu.com/ubuntu noble-backports/restricted amd64 Components [216 B]
Get:14 http://jp.archive.ubuntu.com/ubuntu noble-backports/universe amd64 Components [28.4 kB]
Get:15 http://jp.archive.ubuntu.com/ubuntu noble-backports/multiverse amd64 Components [212 B]
Get:16 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages [986 kB]
Get:17 http://security.ubuntu.com/ubuntu noble-security/main Translation-en [175 kB]
Get:18 http://security.ubuntu.com/ubuntu noble-security/main amd64 Components [21.5 kB]
Get:19 http://security.ubuntu.com/ubuntu noble-security/restricted amd64 Packages [1,373 kB]
Get:20 http://security.ubuntu.com/ubuntu noble-security/restricted Translation-en [294 kB]
Get:21 http://security.ubuntu.com/ubuntu noble-security/restricted amd64 Components [212 B]
Get:22 http://security.ubuntu.com/ubuntu noble-security/universe amd64 Packages [872 kB]
Get:23 http://security.ubuntu.com/ubuntu noble-security/universe Translation-en [192 kB]
Get:24 http://security.ubuntu.com/ubuntu noble-security/universe amd64 Components [52.3 kB]
Get:25 http://security.ubuntu.com/ubuntu noble-security/multiverse amd64 Components [212 B]
Fetched 7,547 kB in 10s (748 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
86 packages can be upgraded. Run 'apt list --upgradable' to see them.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
python3-venv is already the newest version (3.12.3-0ubuntu2).
0 upgraded, 0 newly installed, 0 to remove and 86 not upgraded.
(venv) c0117304@c0117304-test:~/tickets-auto-close$ 

venvは実行したディレクトリにインストールされるので注意してください.

・仮想環境を作成する
 venvがあるディレクトリで実行してください

c0117304@c0117304-test:~/tickets-auto-close$ python3 -m venv venv
(venv)  c0117304@c0117304-test:~/tickets-auto-close$

・仮想環境を有効化する

c0117304@c0117304-test:~/tickets-auto-close$ source venv/bin/activate
(venv)  c0117304@c0117304-test:~/tickets-auto-close$

・fastapi, uvicorn, requestをインストールする

c0117304@c0117304-test:~/tickets-auto-close$ pip install fastapi uvicorn requests
Requirement already satisfied: fastapi in ./venv/lib/python3.12/site-packages (0.116.1)
Requirement already satisfied: uvicorn in ./venv/lib/python3.12/site-packages (0.35.0)
Requirement already satisfied: requests in ./venv/lib/python3.12/site-packages (2.32.4)
Requirement already satisfied: starlette<0.48.0,>=0.40.0 in ./venv/lib/python3.12/site-packages (from fastapi) (0.47.1)
Requirement already satisfied: pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4 in ./venv/lib/python3.12/site-packages (from fastapi) (2.11.7)
Requirement already satisfied: typing-extensions>=4.8.0 in ./venv/lib/python3.12/site-packages (from fastapi) (4.14.1)
Requirement already satisfied: click>=7.0 in ./venv/lib/python3.12/site-packages (from uvicorn) (8.2.1)
Requirement already satisfied: h11>=0.8 in ./venv/lib/python3.12/site-packages (from uvicorn) (0.16.0)
Requirement already satisfied: charset_normalizer<4,>=2 in ./venv/lib/python3.12/site-packages (from requests) (3.4.2)
Requirement already satisfied: idna<4,>=2.5 in ./venv/lib/python3.12/site-packages (from requests) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in ./venv/lib/python3.12/site-packages (from requests) (2.5.0)
Requirement already satisfied: certifi>=2017.4.17 in ./venv/lib/python3.12/site-packages (from requests) (2025.7.9)
Requirement already satisfied: annotated-types>=0.6.0 in ./venv/lib/python3.12/site-packages (from pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4->fastapi) (0.7.0)
Requirement already satisfied: pydantic-core==2.33.2 in ./venv/lib/python3.12/site-packages (from pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4->fastapi) (2.33.2)
Requirement already satisfied: typing-inspection>=0.4.0 in ./venv/lib/python3.12/site-packages (from pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4->fastapi) (0.4.1)
Requirement already satisfied: anyio<5,>=3.6.2 in ./venv/lib/python3.12/site-packages (from starlette<0.48.0,>=0.40.0->fastapi) (4.9.0)
Requirement already satisfied: sniffio>=1.1 in ./venv/lib/python3.12/site-packages (from anyio<5,>=3.6.2->starlette<0.48.0,>=0.40.0->fastapi) (1.3.1)
(venv) c0117304@c0117304-test:~/tickets-auto-close$

・REDMINE_URL, REDMINE_API_KEY, REDMINE_PROJECT_ID, REDMINE_TRACKER_ID, REDMINE_OPEN_STATUS_ID, REDMINE_CLOSE_STATUS_IDの環境変数をexportで入力します

export REDMINE_URL="http://your-redmine-server:port_number"
export REDMINE_API_KEY="your_redmine_api_key"
export REDMINE_PROJECT_ID="your_project_id"
export REDMINE_TRACKER_ID="project_tracker_id"
export REDMINE_OPEN_STATUS_ID="open_status_id"
export REDMINE_CLOSE_STATUS_ID="close_status_id"

REDMINE_URL → <"redmineがあるIPアドレスorホスト名":"ポート番号">
REDMINE_API_KEY → redmineにログインし, 右上の個人設定を開くと右側に"APIアクセスキー"があります.
REDMINE_PROJECT_I → redmineでチケットを登録するプロジェクトの識別子をいれてください.
REDMINE_TRACKER_ID → チケットトラッキングのどこに出力するか.デフォルトなら1でBugに登録されます.
REDMINE_OPEN_STATUS_ID → チケットが作成されたときのステータスID. 1なら未着手になります.
REDMINE_CLOSE_STATUS_ID → チケットがResolvedされたときのステータスID. 8なら完了になります.

↓Redmine API Keyの場所
スクリーンショット 2025-07-16 143023.png

・fastAPIを実行する

c0117304@c0117304-test:~/tickets-auto-close$ uvicorn app:app --reload --host 0.0.0.0 --port 5005
INFO:     Will watch for changes in these directories: ['/home/c0117304/Alert-Ticket-Grouping']
INFO:     Uvicorn running on http://0.0.0.0:5005 (Press CTRL+C to quit)
INFO:     Started reloader process [4225] using StatReload
INFO:     Started server process [4227]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

これでfastAPIが立ち上がりました.

テストしてみる

以下の入力で実際にAlertmanagerからくる情報を想定してJSON方式で直接入力します. http://localhost:5005/webhookの部分は実行する環境にあわせてIPアドレスやポート番号を変更してください.
statusは現在もアラートの状態になっていることを示すfiring,
alertnameはアラートの名前, instanceはホストの名前を入れます.
summaryは何も入ってなくても大丈夫です.

curl -X POST http://localhost:5005/webhook \
-H "Content-Type: application/json" \
-d '{
  "alerts": [
    {
      "status": "firing",
      "labels": {
        "alertname": "Qiita_Manual_Alert",
        "instance": "testhost"
      },
      "annotations": {
        "summary": "Webhookテスト"
      }
    }
  ]
}'

これでテストチケットを発行してみます.
スクリーンショット 2025-07-14 124625.png

チケットが作成されたかを確認します. Redmineをブラウザ( http://<redmineの配置されている対象のIP or Host名>:<公開したPort>)で開き, 自分で指定したプロジェクトを開いてください.

スクリーンショット 2025-07-15 130232.png

スクリーンショット 2025-07-15 130647.png

きちんとQiita_Manual_Alertのチケットが作成されました.

おわりに

これでチケットをきちんと作成できるかテストできるので, 導入の際は試してみてください.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?