Jira-Scripte/Postfunctions/[CoE] Transition linked CS-Ticket.groovy

123 lines
4.7 KiB
Groovy
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* -----------------------------------------------------------------------------
* Workflow Postfunction (ScriptRunner for Jira Cloud)
* -----------------------------------------------------------------------------
*
* Name
* ----------------
* [CoE] Transition linked CSD ticket on close
*
* Zweck
* -----
* Beim Ausführen der Transition im CoE-Ticket soll ein eindeutig verlinktes
* Ticket im Zielprojekt (z.B. CSD-xxxx) automatisch per Transition
* weitergeschaltet werden (z.B. Status "Back from CoE").
*
* Prozess-Annahme
* ---------------
* - Es existiert genau EIN Link vom CoE-Ticket zu einem Ticket im Zielprojekt.
* - Der Linktyp (Name) ist bekannt, z.B. "is cloned by".
*
* Technischer Ansatz
* ------------------
* - HTTP-Calls (get/post) bleiben im Workflow-Kontext, weil ScriptRunner Cloud
* diese Helper dort zuverlässig bereitstellt.
* - Die Ermittlung des Ziel-Tickets ist in eine Script-Manager-Utility ausgelagert:
* utils.LinkedIssueTransitions.findSingleLinkedTargetKey(...)
*
* Konfiguration
* -------------
* - LINK_TYPE_NAME: Name der Link-Richtung (inward oder outward), wie er in Jira
* angezeigt wird (z.B. "is cloned by").
* - TRANSITION_ID: Die ID der Transition, die im Ziel-Ticket ausgeführt werden soll.
* - TARGET_PROJECT_KEY: Projekt-Key des Zielprojekts (z.B. "CSD").
*
* Logging
* -------
* Das Skript loggt:
* - Start und Konfiguration
* - Fehlerzustände (kein Source-Key, HTTP Fehler, kein eindeutiges Target)
* - Erfolg/Misserfolg der Transition im Ziel-Ticket
*
* -----------------------------------------------------------------------------
*/
import utils.LinkedIssueTransitions
// ------------------------- Konfiguration ------------------------------------
// Linktyp-Name (Richtung) z.B. "is cloned by"
final String LINK_TYPE_NAME = "is cloned by"
// Transition im Zielprojekt z.B. "CoE erledigt" (ID = 441)
final String TRANSITION_ID = "441"
// Zielprojekt, in dem das verlinkte Ticket liegt
final String TARGET_PROJECT_KEY = "CSD"
// Einheitlicher Log-Prefix (macht das Filtern in Logs leichter)
final String LOG_PREFIX = "[CoE->Linked Transition]"
// ------------------------- Guard: Source Issue Key --------------------------
// issue kommt aus dem Workflow-Kontext der Postfunction.
def sourceKey = issue?.key?.toString()
if (!sourceKey) {
logger.warn("${LOG_PREFIX} Kein issue.key im Kontext. Abbruch.")
return
}
logger.info("${LOG_PREFIX} Start. Source=${sourceKey}, linkType='${LINK_TYPE_NAME}', transitionId=${TRANSITION_ID}, targetProject=${TARGET_PROJECT_KEY}")
// ------------------------- 1) Source Issue laden ----------------------------
// Wir brauchen die Issue-Links (issuelinks), weil dort die verknüpften Tickets stehen.
// Hinweis: Wir laden nur das Feld "issuelinks", um Payload klein und schnell zu halten.
def issueResp = get("/rest/api/3/issue/${sourceKey}")
.queryString("fields", "issuelinks")
.asObject(Map)
// Jira REST: 200 = OK
if (issueResp.status != 200) {
logger.warn("${LOG_PREFIX} Konnte ${sourceKey} nicht laden (${issueResp.status}). Body=${issueResp.body}")
return
}
// ------------------------- 2) Zielkey finden (Utility) ----------------------
// In der Utility stecken unsere Regeln:
// - Filter nach Linktyp-Name (inward/outward)
// - Filter nach Zielprojekt-Key-Prefix (z.B. "CSD-")
// - Es muss GENAU ein Treffer sein, sonst null.
def targetKey = LinkedIssueTransitions.findSingleLinkedTargetKey(
issueResp.body,
LINK_TYPE_NAME,
TARGET_PROJECT_KEY
)
if (!targetKey) {
logger.warn("${LOG_PREFIX} Kein eindeutiges Ziel-Ticket gefunden (erwartet genau 1 Link ins Projekt ${TARGET_PROJECT_KEY}). Abbruch.")
return
}
logger.info("${LOG_PREFIX} Ziel-Ticket: ${targetKey}. Führe Transition aus…")
// ------------------------- 3) Transition im Ziel-Ticket ausführen -----------
// Jira REST Transition Endpoint:
// POST /rest/api/3/issue/{issueIdOrKey}/transitions
//
// Body:
// { "transition": { "id": "441" } }
//
// Erfolg: typischerweise 204 (No Content)
def transResp = post("/rest/api/3/issue/${targetKey}/transitions")
.header("Content-Type", "application/json")
.body([ transition: [ id: TRANSITION_ID ] ])
.asObject(Map)
if (transResp.status == 204) {
logger.info("${LOG_PREFIX} OK: ${targetKey} erfolgreich transitioniert (ID=${TRANSITION_ID}).")
} else {
// Häufige Fehlerursachen:
// - Run-as User / Add-on User hat keine Berechtigung im Zielprojekt
// - Transition-ID passt nicht zum Workflow/Status des Ziel-Tickets
// - Ziel-Ticket ist in einem Status, in dem die Transition nicht verfügbar ist
logger.warn("${LOG_PREFIX} Transition fehlgeschlagen für ${targetKey}: status=${transResp.status}, body=${transResp.body}")
}