195 lines
6.4 KiB
Groovy
195 lines
6.4 KiB
Groovy
// -----------------------------------------------------------------------------
|
|
// Housekeeping: Unbenutzte Berechtigungsschemata finden UND löschen
|
|
// Jira Cloud - ScriptRunner Console
|
|
// -----------------------------------------------------------------------------
|
|
|
|
import groovy.json.JsonOutput
|
|
|
|
// --- Konfiguration -----------------------------------------------------------
|
|
|
|
// 🔥 Wenn true -> nur Testlauf, nichts wird gelöscht.
|
|
// 🔥 Wenn false -> unbenutzte Schemas (ohne EXCLUDED_IDS) werden gelöscht.
|
|
final boolean DRY_RUN = true
|
|
|
|
// IDs, die niemals gelöscht werden sollen (z. B. Default/System-Schemata)
|
|
final Set<Long> EXCLUDED_IDS = [0] as Set // bei Bedarf ergänzen, z.B. 10000L etc.
|
|
|
|
// --- Schritt 1: Alle Berechtigungsschemata holen ----------------------------
|
|
|
|
def schemesResp = get("/rest/api/3/permissionscheme").asObject(Map)
|
|
|
|
if (schemesResp.status != 200) {
|
|
logger.error("Konnte Berechtigungsschemata nicht laden: ${schemesResp.status} - ${schemesResp.body}")
|
|
return "Fehler beim Laden der Berechtigungsschemata. Siehe Log."
|
|
}
|
|
|
|
def schemes = schemesResp.body?.permissionSchemes ?: []
|
|
logger.info "Anzahl Berechtigungsschemata insgesamt: ${schemes.size()}"
|
|
|
|
// Map: schemeId -> [scheme: <Objekt>, used: boolean, projects: [keys]]
|
|
def schemeUsage = schemes.collectEntries { scheme ->
|
|
def id = (scheme.id ?: scheme["id"]) as Long
|
|
[
|
|
(id): [
|
|
scheme : scheme,
|
|
used : false,
|
|
projects: []
|
|
]
|
|
]
|
|
}
|
|
|
|
// --- Schritt 2: Alle Projekte holen & Permission-Scheme je Projekt ermitteln --
|
|
|
|
int startAt = 0
|
|
int maxResults = 50
|
|
int totalProjects = 0
|
|
boolean finished = false
|
|
|
|
while (!finished) {
|
|
def projResp = get("/rest/api/3/project/search?startAt=${startAt}&maxResults=${maxResults}")
|
|
.asObject(Map)
|
|
|
|
if (projResp.status != 200) {
|
|
logger.error("Konnte Projekte nicht laden (startAt=${startAt}): ${projResp.status} - ${projResp.body}")
|
|
break
|
|
}
|
|
|
|
def body = projResp.body ?: [:]
|
|
def projects = body.values ?: []
|
|
totalProjects += projects.size()
|
|
|
|
projects.each { proj ->
|
|
def projectKey = proj.key
|
|
def projectId = proj.id
|
|
|
|
def permResp = get("/rest/api/3/project/${projectId}/permissionscheme")
|
|
.asObject(Map)
|
|
|
|
if (permResp.status == 200) {
|
|
def schemeId = permResp.body?.id
|
|
if (schemeId) {
|
|
def idLong = (schemeId as Long)
|
|
def entry = schemeUsage[idLong]
|
|
if (entry) {
|
|
entry.used = true
|
|
entry.projects << projectKey
|
|
} else {
|
|
logger.warn "Projekt ${projectKey} nutzt Berechtigungsschema ${schemeId}, das nicht in der globalen Liste war."
|
|
}
|
|
}
|
|
} else if (permResp.status == 404) {
|
|
// Team-managed-Projekte -> haben kein klassisches Permission Scheme
|
|
} else {
|
|
logger.warn "Konnte Permission Scheme für Projekt ${projectKey} nicht laden: ${permResp.status}"
|
|
}
|
|
}
|
|
|
|
int total = (body.total ?: totalProjects) as int
|
|
startAt += maxResults
|
|
if (startAt >= total) {
|
|
finished = true
|
|
}
|
|
}
|
|
|
|
// --- Schritt 3: Unbenutzte (und nicht ausgeschlossene) Schemata bestimmen ---
|
|
|
|
def unused = schemeUsage.values()
|
|
.findAll { entry ->
|
|
def id = (entry.scheme.id ?: 0L) as Long
|
|
!entry.used && !EXCLUDED_IDS.contains(id)
|
|
}
|
|
.sort { it.scheme.name?.toString()?.toLowerCase() }
|
|
|
|
logger.info "Projekte insgesamt : ${totalProjects}"
|
|
logger.info "Ausgeschlossene Schema-IDs : ${EXCLUDED_IDS.join(', ')}"
|
|
logger.info "Unbenutzte Schemata (Kandidaten): ${unused.size()}"
|
|
|
|
// --- Schritt 4: Optional löschen --------------------------------------------
|
|
|
|
def deleted = []
|
|
def failed = []
|
|
|
|
if (!DRY_RUN) {
|
|
unused.each { entry ->
|
|
def s = entry.scheme
|
|
def id = (s.id as Long)
|
|
|
|
logger.info "Lösche Berechtigungsschema ID=${id}, Name=\"${s.name}\" ..."
|
|
|
|
def delResp = delete("/rest/api/3/permissionscheme/${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 nichts gelöscht, nur Kandidaten ermittelt."
|
|
}
|
|
|
|
// --- Schritt 5: Zusammenfassung zurückgeben ---------------------------------
|
|
|
|
def lines = []
|
|
lines << "=== Berechtigungsschemata Housekeeping ==="
|
|
lines << "DRY_RUN : ${DRY_RUN}"
|
|
lines << "Gesamt-Schemata : ${schemes.size()}"
|
|
lines << "Gesamt-Projekte : ${totalProjects}"
|
|
lines << "Ausgeschlossene IDs : ${EXCLUDED_IDS.join(', ')}"
|
|
lines << "Kandidaten (unused) : ${unused.size()}"
|
|
if (!DRY_RUN) {
|
|
lines << "Gelöscht : ${deleted.size()}"
|
|
lines << "Fehlgeschlagen : ${failed.size()}"
|
|
}
|
|
lines << ""
|
|
lines << "Kandidaten (unbenutzte Schemas, exkl. EXCLUDED_IDS):"
|
|
unused.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,
|
|
totalSchemes : schemes.size(),
|
|
totalProjects : totalProjects,
|
|
excludedIDs : EXCLUDED_IDS,
|
|
candidateUnused : unused.size(),
|
|
deleted : deleted.size(),
|
|
failed : failed.size()
|
|
],
|
|
deletedPermissionSchemes: deleted,
|
|
failedDeletions : failed,
|
|
candidateUnusedSchemes : unused.collect { e ->
|
|
def s = e.scheme
|
|
[
|
|
id : s.id,
|
|
name : s.name,
|
|
description : s.description,
|
|
projectsUsing: e.projects
|
|
]
|
|
}
|
|
]
|
|
|
|
logger.info lines.join("\n")
|
|
|
|
return lines.join("\n") + "\n\nJSON:\n" + JsonOutput.prettyPrint(JsonOutput.toJson(result))
|