136 lines
4.9 KiB
Groovy
136 lines
4.9 KiB
Groovy
import groovy.json.JsonOutput
|
||
|
||
// -------------------------- Konfiguration --------------------------
|
||
boolean DRY_RUN = true // erst prüfen; auf false stellen, wenn die Kandidatenliste stimmt
|
||
int PAGE_SIZE = 50
|
||
|
||
Set<String> EXCLUDE_BY_NAME = [
|
||
'Default Screen Scheme'
|
||
] as Set
|
||
|
||
// -------------------------- Logging -------------------------------
|
||
void logInfo(String msg){ try { logger.info(msg) } catch(e){ println msg } }
|
||
void logWarn(String msg){ try { logger.warn(msg) } catch(e){ println "WARN: " + msg } }
|
||
void logErr (String msg){ try { logger.error(msg)} catch(e){ println "ERR: " + msg } }
|
||
|
||
// -------------------------- HTTP Helpers --------------------------
|
||
Map getAsMap(String path, Map<String,Object> q=[:]) {
|
||
def req = get(path)
|
||
q.each { k,v -> req = req.queryString(k, v) }
|
||
def resp = req.asObject(Map)
|
||
if (resp.status != 200) {
|
||
throw new RuntimeException("GET " + path + " failed: HTTP " + resp.status + " :: " + resp.body)
|
||
}
|
||
return (resp.body ?: [:]) as Map
|
||
}
|
||
|
||
List<Map> pagedGetValues(String path, int pageSize) {
|
||
int startAt = 0
|
||
List<Map> all = []
|
||
while (true) {
|
||
Map body = getAsMap(path, [startAt: startAt, maxResults: pageSize])
|
||
List vals = (body.values ?: []) as List
|
||
all.addAll(vals as List<Map>)
|
||
int total = (body.total ?: (startAt + vals.size())) as int
|
||
int nextStart = startAt + ((body.maxResults ?: vals.size()) as int)
|
||
if (vals.isEmpty() || nextStart >= total) break
|
||
startAt = nextStart
|
||
}
|
||
return all
|
||
}
|
||
|
||
// -------------------------- Fetchers ------------------------------
|
||
List<Map> fetchScreenSchemes(int pageSize) {
|
||
logInfo("Lade Screen Schemes…")
|
||
List<Map> list = pagedGetValues("/rest/api/3/screenscheme", pageSize)
|
||
logInfo("Screen Schemes gefunden: " + list.size())
|
||
return list
|
||
}
|
||
|
||
List<Map> fetchIssueTypeScreenSchemes(int pageSize) {
|
||
logInfo("Lade Issue Type Screen Schemes…")
|
||
List<Map> list = pagedGetValues("/rest/api/3/issuetypescreenscheme", pageSize)
|
||
logInfo("Issue Type Screen Schemes gefunden: " + list.size())
|
||
return list
|
||
}
|
||
|
||
/**
|
||
* Holt alle Referenzen auf Screen Schemes:
|
||
* - defaultScreenSchemeId je ITSS
|
||
* - globale ITSS→IssueType→ScreenScheme Mappings aus /issuetypescreenscheme/mapping
|
||
*/
|
||
Set<Long> fetchReferencedScreenSchemeIds(int pageSize, List<Map> itssList) {
|
||
Set<Long> refs = new LinkedHashSet<>()
|
||
|
||
// 1) Default-Zuordnungen je ITSS
|
||
for (Map itss : itssList) {
|
||
def defId = itss.get("defaultScreenSchemeId")
|
||
if (defId != null) refs.add(Long.valueOf(defId.toString()))
|
||
}
|
||
|
||
// 2) Globale Mappings
|
||
logInfo("Lade globale IssueType→ScreenScheme Mappings…")
|
||
List<Map> globalMaps = pagedGetValues("/rest/api/3/issuetypescreenscheme/mapping", pageSize)
|
||
for (Map m : globalMaps) {
|
||
def ssId = m.get("screenSchemeId")
|
||
if (ssId != null) refs.add(Long.valueOf(ssId.toString()))
|
||
}
|
||
logInfo("Referenzierte Screen Schemes gesamt: " + refs.size())
|
||
return refs
|
||
}
|
||
|
||
// -------------------------- Delete -------------------------------
|
||
boolean deleteScreenScheme(long id, String name) {
|
||
def resp = delete("/rest/api/3/screenscheme/" + id).asString()
|
||
if (resp.status in [200,204]) {
|
||
logInfo("Gelöscht: [" + id + "] " + name)
|
||
return true
|
||
}
|
||
logWarn("Nicht gelöscht [" + id + "] " + name + " :: HTTP " + resp.status + " :: " + resp.body)
|
||
return false
|
||
}
|
||
|
||
// -------------------------- Main -------------------------------
|
||
void runCleanup(boolean dryRun, int pageSize, Set<String> excludeByName) {
|
||
List<Map> screenSchemes = fetchScreenSchemes(pageSize)
|
||
if (screenSchemes.isEmpty()) { logInfo("Keine Screen Schemes vorhanden – nichts zu tun."); return }
|
||
|
||
List<Map> itssList = fetchIssueTypeScreenSchemes(pageSize)
|
||
Set<Long> referenced = fetchReferencedScreenSchemeIds(pageSize, itssList)
|
||
|
||
List<Map> candidates = []
|
||
for (Map s : screenSchemes) {
|
||
long id = Long.valueOf(s.get("id").toString())
|
||
String name = (s.get("name") ?: "") as String
|
||
if (!referenced.contains(id) && !excludeByName.contains(name)) {
|
||
candidates.add([id: id, name: name, description: (s.get("description") ?: "")])
|
||
}
|
||
}
|
||
candidates.sort { a, b -> a.name <=> b.name }
|
||
|
||
if (candidates.isEmpty()) { logInfo("Keine ungenutzten Screen Schemes gefunden. ✅"); return }
|
||
|
||
logWarn("Ungenutzte Kandidaten (" + candidates.size() + "):")
|
||
for (Map c : candidates) logWarn(" - [" + c.id + "] " + c.name)
|
||
|
||
if (dryRun) {
|
||
logInfo("Dry-Run aktiv → nichts gelöscht.")
|
||
logInfo("JSON Dump:\n" + JsonOutput.prettyPrint(JsonOutput.toJson(candidates)))
|
||
return
|
||
}
|
||
|
||
int deleted = 0, skipped = 0
|
||
for (Map c : candidates) {
|
||
try {
|
||
if (deleteScreenScheme((c.id as Long), c.name.toString())) deleted++ else skipped++
|
||
} catch (Exception ex) {
|
||
skipped++
|
||
logErr("Fehler beim Löschen [" + c.id + "] " + c.name + " :: " + ex.message)
|
||
}
|
||
}
|
||
logWarn("Fertig. Ergebnis: deleted=" + deleted + ", skipped=" + skipped)
|
||
}
|
||
|
||
// ---- Start ----
|
||
runCleanup(DRY_RUN, PAGE_SIZE, EXCLUDE_BY_NAME)
|