Files
ankn a5f8fb49ab Migrate all repos into monorepo context folders
Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
      Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
      Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)

Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
2026-06-30 20:39:52 +02:00

155 lines
6.4 KiB
PowerShell

<#
.SYNOPSIS
Bug-Verursachungs-Analyse (Bulk-Ansatz)
Holt alle Bugs + Features der letzten 6 Monate in 2 Bulk-Abfragen
und korreliert lokal.
#>
$JiraUrl = "https://arija.jaas.service.deutschebahn.com"
$ApiBase = "$JiraUrl/rest"
$OutputDir = "project-audit\data\jira-bugs"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Write-Host "============================================================"
Write-Host " Bug-Verursachungs-Analyse (Bulk)"
Write-Host " 2 API-Calls statt 60+"
Write-Host "============================================================"
$Token = $null
$SecretsPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "..\.secrets"
if (Test-Path $SecretsPath) {
Get-Content $SecretsPath | ForEach-Object {
if ($_ -match "^JIRA_TOKEN=(.+)$") {
$val = $Matches[1].Trim()
if ($val -ne "HIER_TOKEN_EINTRAGEN") { $Token = $val }
}
}
}
if (-not $Token) { $Token = Read-Host "Jira PAT" }
$Headers = @{ "Authorization" = "Bearer $Token"; "Content-Type" = "application/json" }
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
function Invoke-JiraBulk {
param([string]$Jql, [int]$MaxTotal = 5000)
$AllIssues = @()
$StartAt = 0
$PageSize = 1000
do {
$Uri = "$ApiBase/api/2/search?jql=$([Uri]::EscapeDataString($Jql))&startAt=$StartAt&maxResults=$PageSize&fields=summary,created,resolutiondate,assignee,issuetype,project,reporter"
Write-Host " Lade $StartAt..." -NoNewline
try {
$R = Invoke-WebRequest -Uri $Uri -Headers $Headers -UseBasicParsing -ErrorAction Stop
$Data = $R.Content | ConvertFrom-Json
$AllIssues += $Data.issues
$Total = $Data.total
Write-Host " $($AllIssues.Count)/$Total" -ForegroundColor Green
$StartAt += $PageSize
Start-Sleep -Seconds 2
} catch {
$StatusCode = 0
if ($_.Exception.Response) { $StatusCode = [int]$_.Exception.Response.StatusCode }
if ($StatusCode -eq 429) {
Write-Host " [429 - warte 30s]" -ForegroundColor Yellow
Start-Sleep -Seconds 30
} else {
Write-Host " FEHLER: $($_.Exception.Message)" -ForegroundColor Red
break
}
}
} while ($AllIssues.Count -lt $Total -and $AllIssues.Count -lt $MaxTotal)
return $AllIssues
}
$Projects = "O2C404, O2CCIB, O2CZERO"
# Abfrage 1: Alle Bugs (6 Monate)
Write-Host ""
Write-Host ">> Bugs (6 Monate)..." -ForegroundColor Yellow
$BugJql = "project in ($Projects) AND issuetype = Bug AND created >= -180d ORDER BY created DESC"
$Bugs = Invoke-JiraBulk -Jql $BugJql -MaxTotal 2000
Write-Host " $($Bugs.Count) Bugs geladen"
# Abfrage 2: Abgeschlossene Features/Stories (6 Monate)
Write-Host ""
Write-Host ">> Features/Stories (6 Monate, abgeschlossen)..." -ForegroundColor Yellow
$FeatureJql = "project in ($Projects) AND issuetype in (Feature, Enabler, Story, Aufgabe, Unteraufgabe) AND status in (Fertig, Done, Closed) AND resolved >= -180d ORDER BY resolved DESC"
$Features = Invoke-JiraBulk -Jql $FeatureJql -MaxTotal 3000
Write-Host " $($Features.Count) Features geladen"
# Lokale Analyse pro Team
Write-Host ""
Write-Host ">> Korrelationsanalyse..." -ForegroundColor Yellow
foreach ($ProjectKey in @("O2C404", "O2CCIB", "O2CZERO")) {
$TeamName = switch ($ProjectKey) { "O2C404" { "Team 404" }; "O2CCIB" { "Team CIB" }; "O2CZERO" { "Team Zero" } }
Write-Host ""
Write-Host " === $TeamName ===" -ForegroundColor Cyan
$TeamBugs = $Bugs | Where-Object { $_.fields.project.key -eq $ProjectKey }
$TeamFeatures = $Features | Where-Object { $_.fields.project.key -eq $ProjectKey }
Write-Host " $($TeamBugs.Count) Bugs, $($TeamFeatures.Count) Features"
# Korrelation: Wer hat in 14 Tagen vor Bug-Erstellung Features abgeschlossen?
$Causation = @{}
foreach ($Bug in $TeamBugs) {
$BugCreated = [DateTime]::Parse($Bug.fields.created)
$WindowStart = $BugCreated.AddDays(-14)
$RecentFeatures = $TeamFeatures | Where-Object {
$_.fields.resolutiondate -and
[DateTime]::Parse($_.fields.resolutiondate) -ge $WindowStart -and
[DateTime]::Parse($_.fields.resolutiondate) -le $BugCreated
}
foreach ($F in $RecentFeatures) {
if ($F.fields.assignee) {
$Dev = $F.fields.assignee.displayName
if (-not $Causation[$Dev]) { $Causation[$Dev] = @{ Features = 0; BugKeys = @() } }
if ($Causation[$Dev].BugKeys -notcontains $Bug.key) {
$Causation[$Dev].BugKeys += $Bug.key
}
}
}
}
# Feature-Count pro Dev
foreach ($F in $TeamFeatures) {
if ($F.fields.assignee) {
$Dev = $F.fields.assignee.displayName
if (-not $Causation[$Dev]) { $Causation[$Dev] = @{ Features = 0; BugKeys = @() } }
$Causation[$Dev].Features++
}
}
# Ausgabe Top 10
Write-Host " --- Potenzielle Bug-Verursachung (14-Tage-Fenster) ---"
$Sorted = $Causation.GetEnumerator() | Sort-Object { $_.Value.BugKeys.Count } -Descending
foreach ($E in ($Sorted | Select-Object -First 10)) {
$UniqueBugs = $E.Value.BugKeys.Count
$Feats = $E.Value.Features
$Rate = if ($Feats -gt 0) { [Math]::Round($UniqueBugs / $Feats * 100, 0) } else { 0 }
Write-Host (" {0,-30} Features:{1,4} | Bugs:{2,4} | Rate:{3,3}%" -f $E.Key, $Feats, $UniqueBugs, $Rate)
}
# CSV
$CsvData = $Sorted | ForEach-Object {
[PSCustomObject]@{
Team = $TeamName
Developer = $_.Key
Features = $_.Value.Features
CorrelatedBugs = $_.Value.BugKeys.Count
BugRate = if ($_.Value.Features -gt 0) { [Math]::Round($_.Value.BugKeys.Count / $_.Value.Features * 100, 0) } else { 0 }
}
}
$CsvData | Export-Csv "$OutputDir\$ProjectKey-causation.csv" -Delimiter ";" -Encoding UTF8 -NoTypeInformation
}
Write-Host ""
Write-Host "============================================================" -ForegroundColor Green
Write-Host " FERTIG! API-Calls: ~$([Math]::Ceiling(($Bugs.Count + $Features.Count) / 1000) + 2)" -ForegroundColor Green
Write-Host " Ergebnisse in $OutputDir" -ForegroundColor Green
Write-Host "============================================================" -ForegroundColor Green