225 lines
7.1 KiB
Groovy
225 lines
7.1 KiB
Groovy
// -----------------------------------------------------------------------------
|
|
// Housekeeping: Inaktive Workflow Schemes (ohne Projektzuordnung) löschen
|
|
// Jira Cloud - ScriptRunner Console
|
|
// -----------------------------------------------------------------------------
|
|
|
|
import groovy.json.JsonOutput
|
|
|
|
// --- Konfiguration -----------------------------------------------------------
|
|
|
|
// false -> inaktive Workflow Schemes (ohne EXCLUDED_IDS) werden GELÖSCHT
|
|
// true -> nur Testlauf, es wird NICHT gelöscht
|
|
final boolean DRY_RUN = true
|
|
|
|
// Workflow-Scheme-IDs, die NIEMALS gelöscht werden sollen
|
|
// (z.B. Default-System-Schema; ID bitte ggf. anpassen/ergänzen)
|
|
final Set<Long> EXCLUDED_IDS = [10000L] as Set
|
|
|
|
// --- Schritt 1: Alle Workflow Schemes laden (paginiert) ---------------------
|
|
|
|
List<Map> allSchemes = []
|
|
int startAt = 0
|
|
int maxResults = 50
|
|
boolean finished = false
|
|
|
|
while (!finished) {
|
|
def resp = get("/rest/api/3/workflowscheme?startAt=${startAt}&maxResults=${maxResults}")
|
|
.asObject(Map)
|
|
|
|
if (resp.status != 200) {
|
|
logger.error("Konnte Workflow Schemes nicht laden (startAt=${startAt}): ${resp.status} - ${resp.body}")
|
|
return "Fehler beim Laden der Workflow Schemes. Siehe Log."
|
|
}
|
|
|
|
def body = resp.body ?: [:]
|
|
def values = (body.values ?: []) as List<Map>
|
|
|
|
allSchemes.addAll(values)
|
|
|
|
boolean isLast = (body.isLast == true)
|
|
int total = (body.total ?: (startAt + values.size())) as int
|
|
|
|
logger.info "Workflow Schemes geladen: ${allSchemes.size()} (total ~ ${total}), isLast=${isLast}"
|
|
|
|
if (isLast || values.isEmpty()) {
|
|
finished = true
|
|
} else {
|
|
startAt += maxResults
|
|
if (startAt >= total) {
|
|
finished = true
|
|
}
|
|
}
|
|
}
|
|
|
|
logger.info "Anzahl Workflow Schemes insgesamt: ${allSchemes.size()}"
|
|
|
|
// Map: schemeId -> [scheme: <Objekt>, used: boolean, projects: Set<projectKey>]
|
|
def schemeUsage = allSchemes.collectEntries { scheme ->
|
|
Long id = (scheme.id as Long)
|
|
[
|
|
(id): [
|
|
scheme : scheme,
|
|
used : false,
|
|
projects: [] as Set<String>
|
|
]
|
|
]
|
|
}
|
|
|
|
// --- Schritt 2: Mappings Workflow Scheme <-> Projekte laden -----------------
|
|
//
|
|
// GET /rest/api/3/workflowscheme/project
|
|
// liefert PageBean mit values[ { workflowSchemeId, projectId, projectKey, ... } ]
|
|
|
|
List<Map> allMappings = []
|
|
startAt = 0
|
|
finished = false
|
|
|
|
while (!finished) {
|
|
def resp = get("/rest/api/3/workflowscheme/project?startAt=${startAt}&maxResults=${maxResults}")
|
|
.asObject(Map)
|
|
|
|
if (resp.status != 200) {
|
|
logger.error("Konnte Workflow-Scheme-Mappings nicht laden (startAt=${startAt}): ${resp.status} - ${resp.body}")
|
|
break
|
|
}
|
|
|
|
def body = resp.body ?: [:]
|
|
def values = (body.values ?: []) as List<Map>
|
|
|
|
allMappings.addAll(values)
|
|
|
|
boolean isLast = (body.isLast == true)
|
|
int total = (body.total ?: (startAt + values.size())) as int
|
|
|
|
logger.info "Workflow-Scheme-Mappings geladen: ${allMappings.size()} (total ~ ${total}), isLast=${isLast}"
|
|
|
|
if (isLast || values.isEmpty()) {
|
|
finished = true
|
|
} else {
|
|
startAt += maxResults
|
|
if (startAt >= total) {
|
|
finished = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mappings in schemeUsage eintragen
|
|
allMappings.each { m ->
|
|
Long schemeId = (m.workflowSchemeId as Long)
|
|
String projKey = m.projectKey?.toString()
|
|
|
|
def entry = schemeUsage[schemeId]
|
|
if (entry) {
|
|
entry.used = true
|
|
if (projKey) {
|
|
entry.projects << projKey
|
|
}
|
|
} else {
|
|
logger.warn "Mapping gefunden für Workflow Scheme ID=${schemeId}, das nicht in allSchemes war. Projekt=${projKey}"
|
|
}
|
|
}
|
|
|
|
def projectsWithWorkflowScheme = allMappings.collect { it.projectKey }.findAll { it }.toSet()
|
|
logger.info "Anzahl Projekte mit Workflow Scheme: ${projectsWithWorkflowScheme.size()}"
|
|
|
|
// --- Schritt 3: Inaktive (unbenutzte & nicht ausgeschlossene) Schemes -------
|
|
|
|
def inactive = schemeUsage.values()
|
|
.findAll { entry ->
|
|
Long id = (entry.scheme.id as Long)
|
|
!entry.used && !EXCLUDED_IDS.contains(id)
|
|
}
|
|
.sort { it.scheme.name?.toString()?.toLowerCase() }
|
|
|
|
logger.info "Ausgeschlossene Workflow-Scheme-IDs : ${EXCLUDED_IDS.join(', ')}"
|
|
logger.info "Inaktive Workflow Schemes (Kandidaten): ${inactive.size()}"
|
|
|
|
// --- Schritt 4: Optional löschen --------------------------------------------
|
|
|
|
List<Map> deleted = []
|
|
List<Map> failed = []
|
|
|
|
if (!DRY_RUN) {
|
|
inactive.each { entry ->
|
|
def s = entry.scheme
|
|
Long id = (s.id as Long)
|
|
|
|
logger.info "Lösche Workflow Scheme ID=${id}, Name=\"${s.name}\" ..."
|
|
|
|
def delResp = delete("/rest/api/3/workflowscheme/${id}")
|
|
.asString()
|
|
|
|
if (delResp.status in [200, 204]) {
|
|
logger.info "Erfolgreich gelöscht: ID=${id}, Name=\"${s.name}\""
|
|
deleted << [
|
|
id : id,
|
|
name : s.name,
|
|
description: s.description
|
|
]
|
|
} else {
|
|
logger.warn "Löschen fehlgeschlagen für ID=${id}, Name=\"${s.name}\": Status=${delResp.status}, Body=${delResp.body}"
|
|
failed << [
|
|
id : id,
|
|
name : s.name,
|
|
status : delResp.status,
|
|
body : delResp.body
|
|
]
|
|
}
|
|
}
|
|
} else {
|
|
logger.info "DRY_RUN = true -> Es wird NICHT gelöscht, nur Kandidaten ermittelt."
|
|
}
|
|
|
|
// --- Schritt 5: Zusammenfassung ---------------------------------------------
|
|
|
|
def lines = []
|
|
lines << "=== Workflow Schemes Housekeeping ==="
|
|
lines << "DRY_RUN : ${DRY_RUN}"
|
|
lines << "Gesamt Workflow Schemes : ${allSchemes.size()}"
|
|
lines << "Projekte mit Scheme-Mapping : ${projectsWithWorkflowScheme.size()}"
|
|
lines << "Ausgeschlossene IDs : ${EXCLUDED_IDS.join(', ')}"
|
|
lines << "Inaktive Kandidaten : ${inactive.size()}"
|
|
if (!DRY_RUN) {
|
|
lines << "Gelöscht : ${deleted.size()}"
|
|
lines << "Fehlgeschlagen : ${failed.size()}"
|
|
}
|
|
lines << ""
|
|
lines << "Inaktive (unbenutzte) Schemes, exkl. EXCLUDED_IDS:"
|
|
inactive.each { entry ->
|
|
def s = entry.scheme
|
|
lines << String.format(
|
|
"- ID=%s | Name=\"%s\" | Beschreibung=\"%s\" | Projekte=%s",
|
|
s.id,
|
|
s.name ?: "",
|
|
(s.description ?: "").replaceAll('\\s+', ' ').trim(),
|
|
entry.projects ?: []
|
|
)
|
|
}
|
|
|
|
def result = [
|
|
summary : [
|
|
dryRun : DRY_RUN,
|
|
totalWorkflowSchemes : allSchemes.size(),
|
|
projectsWithMapping : projectsWithWorkflowScheme.size(),
|
|
excludedIDs : EXCLUDED_IDS,
|
|
inactiveCandidates : inactive.size(),
|
|
deleted : deleted.size(),
|
|
failed : failed.size()
|
|
],
|
|
inactiveWorkflowSchemes: inactive.collect { e ->
|
|
def s = e.scheme
|
|
[
|
|
id : s.id,
|
|
name : s.name,
|
|
description : s.description,
|
|
projectsUsing: e.projects
|
|
]
|
|
},
|
|
deletedWorkflowSchemes: deleted,
|
|
failedDeletions : failed
|
|
]
|
|
|
|
logger.info lines.join("\n")
|
|
|
|
return lines.join("\n") + "\n\nJSON:\n" + JsonOutput.prettyPrint(JsonOutput.toJson(result))
|