Jira-Scripte/Console - Maintenance/02. Unused permission Schemes cleaner.groovy

125 lines
4.0 KiB
Groovy
Raw Permalink 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.

/**
* Permission Scheme Housekeeping (Cloud) Report + optional Delete
* ----------------------------------------------------------------
* Delete rule:
* - Scheme darf nur gelöscht werden, wenn:
* 1) es in keinem PROTECTED_PROJECT verwendet wird
* 2) es nicht über PROTECTED_SCHEME_IDS geschützt ist
* 3) es nicht über PROTECTED_NAME_PATTERNS geschützt ist
*/
def PROTECTED_PROJECT_KEYS = ["NIN","NICS","NINPDS","NINPDSARC","CS","CRON"]
// Zusätzliche Sicherung:
def PROTECTED_SCHEME_IDS = [
// "10000", // <- optional: hier IDs eintragen, die NIE gelöscht werden dürfen
]
def PROTECTED_NAME_PATTERNS = [
"default",
"system"
]
def DRY_RUN = true // erst auf false, wenn der Report passt
logger.info("=== Permission Scheme Housekeeping ===")
logger.info("Protected projects: ${PROTECTED_PROJECT_KEYS}")
logger.info("Protected scheme IDs: ${PROTECTED_SCHEME_IDS}")
logger.info("Protected name patterns: ${PROTECTED_NAME_PATTERNS}")
logger.info("DRY_RUN: ${DRY_RUN}")
// Helper: Name-Schutz (case-insensitive)
def isNameProtected = { String name ->
def n = (name ?: "").toLowerCase()
return PROTECTED_NAME_PATTERNS.any { p -> n.contains((p ?: "").toLowerCase()) }
}
// Helper: ID-Schutz
def isIdProtected = { String id ->
return PROTECTED_SCHEME_IDS.any { it?.toString() == id?.toString() }
}
// 1) Project -> PermissionSchemeId (nur 6 Calls)
def projectToSchemeId = [:]
PROTECTED_PROJECT_KEYS.each { key ->
def resp = get("/rest/api/3/project/${key}/permissionscheme")
.asObject(Map)
if (resp.status == 200) {
// Jira liefert hier i.d.R. {id, name, ...}
projectToSchemeId[key] = resp.body?.id?.toString()
} else {
projectToSchemeId[key] = null
logger.warn("WARN|PROJECT_LOOKUP_FAILED|${key}|status=${resp.status}")
}
}
logger.info("INFO|PROJECT_SCHEME_MAP|${projectToSchemeId}")
// 2) Alle Permission Schemes holen
def schemesResp = get("/rest/api/3/permissionscheme")
.asObject(Map)
assert schemesResp.status == 200
// Je nach API-Response ist das typischerweise body.permissionSchemes
def schemes = schemesResp.body?.permissionSchemes ?: []
logger.info("INFO|TOTAL_SCHEMES|${schemes.size()}")
def candidates = [] // [id, name, reason]
def keptByUsage = 0
def keptByRule = 0
schemes.each { scheme ->
def schemeId = scheme.id?.toString()
def schemeName = scheme.name?.toString()
def usedBy = projectToSchemeId.findAll { k, v -> v == schemeId }*.key
def nameProtected = isNameProtected(schemeName)
def idProtected = isIdProtected(schemeId)
// Schutz greift immer (egal ob benutzt oder nicht)
if (idProtected || nameProtected) {
keptByRule++
def why = []
if (idProtected) why << "ID_PROTECTED"
if (nameProtected) why << "NAME_PROTECTED"
logger.info("KEEP|schemeId=${schemeId}|name=${schemeName}|usedBy=${usedBy}|reason=${why}")
return
}
// Projekt-Usage entscheidet
if (usedBy && !usedBy.isEmpty()) {
keptByUsage++
logger.info("KEEP|schemeId=${schemeId}|name=${schemeName}|usedBy=${usedBy}|reason=USED_BY_PROTECTED_PROJECT")
return
}
// Kandidat
logger.info("DEL?|schemeId=${schemeId}|name=${schemeName}|usedBy=[]|reason=UNUSED")
candidates << [schemeId, schemeName, "UNUSED"]
if (!DRY_RUN) {
def delResp = delete("/rest/api/3/permissionscheme/${schemeId}")
.asString()
if (delResp.status == 204) {
logger.info("DEL|OK|schemeId=${schemeId}|name=${schemeName}")
} else {
logger.error("DEL|FAIL|schemeId=${schemeId}|name=${schemeName}|status=${delResp.status}|body=${delResp.body}")
}
}
}
logger.info("=== SUMMARY ===")
logger.info("Total schemes: ${schemes.size()}")
logger.info("Kept (used by protected projects): ${keptByUsage}")
logger.info("Kept (protected by rules): ${keptByRule}")
logger.info("Delete candidates: ${candidates.size()}")
candidates.each { c ->
logger.info("CANDIDATE|schemeId=${c[0]}|name=${c[1]}|reason=${c[2]}")
}
logger.info("=== DONE ===")