Jira-Scripte/Console - Maintenance/Issue Type Screen Schemes – Unused Cleaner.groovy
2025-12-14 19:17:45 +01:00

116 lines
4.2 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.

import groovy.json.JsonOutput
// ------------------ Konfig ------------------
boolean DRY_RUN = true
int PAGE_SIZE = 50
Set<String> EXCLUDE_BY_NAME = [] as Set // optional Namen schützen
// ------------------ Logging -----------------
void logInfo(String m){ try{ logger.info(m) }catch(e){ println m } }
void logWarn(String m){ try{ logger.warn(m) }catch(e){ println "WARN: " + m } }
void logErr (String m){ try{ logger.error(m)}catch(e){ println "ERR: " + m } }
// ------------------ HTTP Helpers -----------
Map getAsMap(String path, Map q=[:]) {
def req = get(path)
q.each{ k,v -> req = req.queryString(k, v) }
def r = req.asObject(Map)
if (r.status != 200) throw new RuntimeException("GET " + path + " failed: HTTP " + r.status + " :: " + r.body)
(r.body ?: [:]) as Map
}
List<Map> pagedGetValues(String path, int pageSize=50) {
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
}
all
}
// ------------------ Fetchers ----------------
List<Map> fetchITSS(int pageSize){
logInfo("Lade Issue Type Screen Schemes…")
def list = pagedGetValues("/rest/api/3/issuetypescreenscheme", pageSize)
logInfo("ITSS gefunden: " + list.size())
list
}
List<Map> fetchProjects(int pageSize){
logInfo("Lade Projekte…")
def list = pagedGetValues("/rest/api/3/project/search", pageSize)
logInfo("Projekte gefunden: " + list.size())
list
}
Long fetchITSSForProject(Long projectId){
// Liefert die ITSS-ID, die einem Projekt zugewiesen ist
def m = getAsMap("/rest/api/3/project/${projectId}/issuetypescreenscheme")
def id = m.get("issueTypeScreenSchemeId")
return (id == null ? null : Long.valueOf(id.toString()))
}
// ------------------ Delete ------------------
boolean deleteITSS(long id, String name){
def resp = delete("/rest/api/3/issuetypescreenscheme/${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}")
false
}
// ------------------ Main --------------------
void runITSSCleanup(boolean dryRun, int pageSize, Set<String> excludeByName){
def itss = fetchITSS(pageSize)
if (itss.isEmpty()){ logInfo("Keine ITSS vorhanden nichts zu tun."); return }
Map<Long,Map> itssById = [:]
itss.each{ Map x -> if (x.id!=null) itssById[Long.valueOf(x.id.toString())] = x }
def projects = fetchProjects(pageSize)
Set<Long> referenced = new LinkedHashSet<>()
projects.each{ Map p ->
def pid = p.get("id"); if (pid==null) return
try {
Long ref = fetchITSSForProject(Long.valueOf(pid.toString()))
if (ref!=null) referenced << ref
} catch (Exception ex) {
logWarn("ITSS-Mapping für Projekt ${p.key ?: pid} nicht lesbar: " + ex.message)
}
}
logInfo("Referenzierte ITSS gesamt: " + referenced.size())
List<Map> candidates = []
itssById.each{ Long id, Map row ->
String name = (row.name ?: "") as String
if (!referenced.contains(id) && !excludeByName.contains(name)){
candidates << [id:id, name:name, description:(row.description ?: "")]
}
}
candidates.sort{ a,b -> a.name <=> b.name }
if (candidates.isEmpty()){ logInfo("Keine ungenutzten ITSS gefunden. ✅"); return }
logWarn("Ungenutzte ITSS (${candidates.size()}):")
candidates.each{ c -> logWarn(" - [${c.id}] ${c.name}") }
if (dryRun){
logInfo("Dry-Run aktiv → nichts gelöscht.")
logInfo("JSON:\n" + JsonOutput.prettyPrint(JsonOutput.toJson(candidates)))
return
}
int deleted=0, skipped=0
candidates.each{ c ->
try {
if (deleteITSS((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 ----
runITSSCleanup(DRY_RUN, PAGE_SIZE, EXCLUDE_BY_NAME)