181 lines
5.6 KiB
Groovy
181 lines
5.6 KiB
Groovy
/**
|
||
* Screen Scheme Housekeeping (Cloud) – über Issue Type Screen Scheme Mappings (zuverlässig)
|
||
* --------------------------------------------------------------------------------------
|
||
* Löschen nur, wenn ein Screen Scheme nirgendwo in IssueTypeScreenScheme-Mappings referenziert ist.
|
||
* Jira verhindert Delete sowieso, wenn es noch referenziert wird. :contentReference[oaicite:2]{index=2}
|
||
*/
|
||
|
||
def PROJECT_KEYS = ["NIN","NICS","NINPDS","NINPDSARC","CS","CRON"]
|
||
|
||
def PROTECTED_SCHEME_IDS = [
|
||
// "1" // Default Screen Scheme ggf. hart schützen
|
||
]
|
||
def PROTECTED_NAME_PATTERNS = [
|
||
"default",
|
||
"system",
|
||
"jira"
|
||
]
|
||
|
||
def DRY_RUN = true
|
||
def PROJECT_PAGE_SIZE = 50
|
||
def SCREEN_SCHEME_PAGE_SIZE = 100
|
||
def MAPPING_PAGE_SIZE = 100
|
||
|
||
logger.info("=== Screen Scheme Housekeeping (via IssueTypeScreenScheme mappings) ===")
|
||
logger.info("Projects: ${PROJECT_KEYS}")
|
||
logger.info("Protected scheme IDs: ${PROTECTED_SCHEME_IDS}")
|
||
logger.info("Protected name patterns: ${PROTECTED_NAME_PATTERNS}")
|
||
logger.info("DRY_RUN: ${DRY_RUN}")
|
||
|
||
def isNameProtected = { String name ->
|
||
def n = (name ?: "").toLowerCase()
|
||
PROTECTED_NAME_PATTERNS.any { p -> n.contains((p ?: "").toLowerCase()) }
|
||
}
|
||
def isIdProtected = { String id ->
|
||
PROTECTED_SCHEME_IDS.any { it?.toString() == id?.toString() }
|
||
}
|
||
|
||
/**
|
||
* 1) Project Key -> Project ID
|
||
*/
|
||
def projectIds = [:] // key -> id
|
||
PROJECT_KEYS.each { key ->
|
||
def resp = get("/rest/api/3/project/${key}").asObject(Map)
|
||
if (resp.status == 200) {
|
||
projectIds[key] = resp.body?.id?.toString()
|
||
logger.info("INFO|PROJECT|${key}|id=${projectIds[key]}")
|
||
} else {
|
||
logger.warn("WARN|PROJECT_LOOKUP_FAILED|${key}|status=${resp.status}")
|
||
}
|
||
}
|
||
def validProjectIds = projectIds.values().findAll { it != null }.unique()
|
||
|
||
/**
|
||
* 2) Aus Projekten die IssueTypeScreenSchemeIds einsammeln
|
||
* GET /rest/api/3/issuetypescreenscheme/project?projectId=...
|
||
*/
|
||
def issueTypeScreenSchemeIds = [] as Set
|
||
|
||
validProjectIds.each { pid ->
|
||
def resp = get("/rest/api/3/issuetypescreenscheme/project?projectId=${pid}")
|
||
.asObject(Map)
|
||
|
||
if (resp.status != 200) {
|
||
logger.warn("WARN|ITSCS_FOR_PROJECT_FAILED|projectId=${pid}|status=${resp.status}")
|
||
return
|
||
}
|
||
|
||
(resp.body?.values ?: []).each { row ->
|
||
def itscsId = row?.issueTypeScreenScheme?.id?.toString()
|
||
if (itscsId) issueTypeScreenSchemeIds << itscsId
|
||
}
|
||
}
|
||
|
||
logger.info("INFO|ISSUETYPE_SCREENSCHEME_IDS|count=${issueTypeScreenSchemeIds.size()}|ids=${issueTypeScreenSchemeIds}")
|
||
|
||
/**
|
||
* 3) Für jedes IssueTypeScreenSchemeId: Mappings holen und alle screenSchemeIds sammeln
|
||
* GET /rest/api/3/issuetypescreenscheme/mapping?issueTypeScreenSchemeId=... (paging)
|
||
*/
|
||
def referencedScreenSchemeIds = [] as Set
|
||
|
||
issueTypeScreenSchemeIds.each { itscsId ->
|
||
def startAt = 0
|
||
while (true) {
|
||
def resp = get("/rest/api/3/issuetypescreenscheme/mapping?issueTypeScreenSchemeId=${itscsId}&startAt=${startAt}&maxResults=${MAPPING_PAGE_SIZE}")
|
||
.asObject(Map)
|
||
|
||
if (resp.status != 200) {
|
||
logger.warn("WARN|ITSCS_MAPPING_FAILED|itscsId=${itscsId}|status=${resp.status}")
|
||
break
|
||
}
|
||
|
||
def values = resp.body?.values ?: []
|
||
values.each { m ->
|
||
def screenSchemeId = m?.screenSchemeId?.toString()
|
||
if (screenSchemeId) referencedScreenSchemeIds << screenSchemeId
|
||
}
|
||
|
||
def isLast = resp.body?.isLast
|
||
if (isLast == true || values.isEmpty()) break
|
||
startAt += MAPPING_PAGE_SIZE
|
||
}
|
||
}
|
||
|
||
logger.info("INFO|REFERENCED_SCREENSCHEME_IDS|count=${referencedScreenSchemeIds.size()}")
|
||
|
||
/**
|
||
* 4) Alle Screen Schemes holen, Kandidaten bestimmen
|
||
*/
|
||
def allScreenSchemes = []
|
||
def startAt = 0
|
||
while (true) {
|
||
def resp = get("/rest/api/3/screenscheme?startAt=${startAt}&maxResults=${SCREEN_SCHEME_PAGE_SIZE}")
|
||
.asObject(Map)
|
||
|
||
if (resp.status != 200) {
|
||
logger.error("ERROR|SCREENSCHEME_LIST_FAILED|status=${resp.status}|body=${resp.body}")
|
||
break
|
||
}
|
||
|
||
def values = resp.body?.values ?: []
|
||
allScreenSchemes.addAll(values)
|
||
|
||
def isLast = resp.body?.isLast
|
||
if (isLast == true || values.isEmpty()) break
|
||
startAt += SCREEN_SCHEME_PAGE_SIZE
|
||
}
|
||
|
||
logger.info("INFO|TOTAL_SCREEN_SCHEMES|${allScreenSchemes.size()}")
|
||
|
||
def keptReferenced = 0
|
||
def keptProtected = 0
|
||
def candidates = [] // [id,name,reason]
|
||
|
||
allScreenSchemes.each { ss ->
|
||
def id = ss?.id?.toString()
|
||
def name = ss?.name?.toString()
|
||
|
||
def nameProtected = isNameProtected(name)
|
||
def idProtected = isIdProtected(id)
|
||
|
||
if (nameProtected || idProtected) {
|
||
keptProtected++
|
||
def why = []
|
||
if (idProtected) why << "ID_PROTECTED"
|
||
if (nameProtected) why << "NAME_PROTECTED"
|
||
logger.info("KEEP|screenSchemeId=${id}|name=${name}|reason=${why}")
|
||
return
|
||
}
|
||
|
||
if (referencedScreenSchemeIds.contains(id)) {
|
||
keptReferenced++
|
||
logger.info("KEEP|screenSchemeId=${id}|name=${name}|reason=REFERENCED_BY_ISSUETYPE_SCREENSCHEME")
|
||
return
|
||
}
|
||
|
||
logger.info("DEL?|screenSchemeId=${id}|name=${name}|reason=NOT_REFERENCED_ANYWHERE")
|
||
candidates << [id, name, "NOT_REFERENCED_ANYWHERE"]
|
||
|
||
if (!DRY_RUN) {
|
||
def delResp = delete("/rest/api/3/screenscheme/${id}").asString()
|
||
if (delResp.status == 204) {
|
||
logger.info("DEL|OK|screenSchemeId=${id}|name=${name}")
|
||
} else {
|
||
logger.error("DEL|FAIL|screenSchemeId=${id}|name=${name}|status=${delResp.status}|body=${delResp.body}")
|
||
}
|
||
}
|
||
}
|
||
|
||
logger.info("=== SUMMARY ===")
|
||
logger.info("Total screen schemes: ${allScreenSchemes.size()}")
|
||
logger.info("Kept (referenced): ${keptReferenced}")
|
||
logger.info("Kept (protected by rules): ${keptProtected}")
|
||
logger.info("Delete candidates: ${candidates.size()}")
|
||
|
||
candidates.each { c ->
|
||
logger.info("CANDIDATE|screenSchemeId=${c[0]}|name=${c[1]}|reason=${c[2]}")
|
||
}
|
||
|
||
logger.info("=== DONE ===")
|