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.
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Exportiert Jira-Daten fuer pathOS (O2CBS Projekt)
|
||||
.DESCRIPTION
|
||||
Zieht Boards, Sprints, Backlog-Items und Team-Zuordnungen.
|
||||
Kompatibel mit PowerShell 5.1.
|
||||
.USAGE
|
||||
powershell -ExecutionPolicy Bypass -File ".\project-audit\scripts\jira-export.ps1"
|
||||
#>
|
||||
|
||||
$JiraUrl = "https://arija.jaas.service.deutschebahn.com"
|
||||
$ProjectKey = "O2CBS"
|
||||
$ApiBase = "$JiraUrl/rest"
|
||||
$OutputDir = "project-audit\data\jira-export"
|
||||
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
Write-Host "============================================================"
|
||||
Write-Host " pathOS Jira Export - Projekt $ProjectKey"
|
||||
Write-Host "============================================================"
|
||||
Write-Host ""
|
||||
|
||||
$Token = Read-Host "Jira PAT (Personal Access Token)"
|
||||
$Headers = @{ "Authorization" = "Bearer $Token"; "Content-Type" = "application/json" }
|
||||
|
||||
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
|
||||
|
||||
function Invoke-JiraApi {
|
||||
param([string]$Uri)
|
||||
try {
|
||||
$Resp = Invoke-WebRequest -Uri $Uri -Headers $Headers -UseBasicParsing -ErrorAction Stop
|
||||
return ($Resp.Content | ConvertFrom-Json)
|
||||
} catch {
|
||||
Write-Host " FEHLER: $($_.Exception.Message)" -ForegroundColor Red
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
# 1. Projekt-Info
|
||||
Write-Host ">> Projekt-Info..." -ForegroundColor Yellow
|
||||
$Project = Invoke-JiraApi "$ApiBase/api/2/project/$ProjectKey"
|
||||
if ($null -eq $Project) { Write-Host "Verbindung fehlgeschlagen. Token pruefen." -ForegroundColor Red; exit 1 }
|
||||
Write-Host " Projekt: $($Project.name) ($($Project.key))" -ForegroundColor Green
|
||||
|
||||
# 2. Boards finden
|
||||
Write-Host ">> Boards suchen..." -ForegroundColor Yellow
|
||||
$Boards = Invoke-JiraApi "$ApiBase/agile/1.0/board?projectKeyOrId=$ProjectKey&maxResults=50"
|
||||
if ($Boards -and $Boards.values) {
|
||||
Write-Host " $($Boards.values.Count) Boards gefunden" -ForegroundColor Green
|
||||
$Boards.values | ForEach-Object { Write-Host " - $($_.name) (ID: $($_.id), Typ: $($_.type))" }
|
||||
$Boards | ConvertTo-Json -Depth 5 | Out-File "$OutputDir\boards.json" -Encoding UTF8
|
||||
}
|
||||
|
||||
# 3. Aktuelle Sprints pro Board
|
||||
Write-Host ">> Sprints laden..." -ForegroundColor Yellow
|
||||
$AllSprints = @()
|
||||
if ($Boards -and $Boards.values) {
|
||||
foreach ($Board in $Boards.values) {
|
||||
$Sprints = Invoke-JiraApi "$ApiBase/agile/1.0/board/$($Board.id)/sprint?state=active,closed&maxResults=10"
|
||||
if ($Sprints -and $Sprints.values) {
|
||||
foreach ($S in $Sprints.values) {
|
||||
$S | Add-Member -NotePropertyName "boardName" -NotePropertyValue $Board.name -Force
|
||||
$S | Add-Member -NotePropertyName "boardId" -NotePropertyValue $Board.id -Force
|
||||
$AllSprints += $S
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Write-Host " $($AllSprints.Count) Sprints gefunden" -ForegroundColor Green
|
||||
$AllSprints | ConvertTo-Json -Depth 5 | Out-File "$OutputDir\sprints.json" -Encoding UTF8
|
||||
|
||||
# 4. Backlog-Items mit Team-Labels (JQL)
|
||||
Write-Host ">> Backlog-Items laden (letzte 2 PIs)..." -ForegroundColor Yellow
|
||||
$Jql = "project = $ProjectKey AND updated >= -90d ORDER BY updated DESC"
|
||||
$StartAt = 0
|
||||
$AllIssues = @()
|
||||
do {
|
||||
$SearchUri = "$ApiBase/api/2/search?jql=$([Uri]::EscapeDataString($Jql))&startAt=$StartAt&maxResults=100&fields=summary,status,issuetype,assignee,labels,components,fixVersions,priority,created,updated,customfield_10100"
|
||||
$Result = Invoke-JiraApi $SearchUri
|
||||
if ($null -eq $Result) { break }
|
||||
$AllIssues += $Result.issues
|
||||
$StartAt += 100
|
||||
Write-Host " $($AllIssues.Count) / $($Result.total) Issues geladen..."
|
||||
} while ($AllIssues.Count -lt $Result.total -and $AllIssues.Count -lt 1000)
|
||||
|
||||
Write-Host " $($AllIssues.Count) Issues geladen" -ForegroundColor Green
|
||||
$AllIssues | ConvertTo-Json -Depth 10 | Out-File "$OutputDir\issues.json" -Encoding UTF8
|
||||
|
||||
# 5. Komponenten (= Teams?)
|
||||
Write-Host ">> Komponenten laden..." -ForegroundColor Yellow
|
||||
$Components = Invoke-JiraApi "$ApiBase/api/2/project/$ProjectKey/components"
|
||||
if ($Components) {
|
||||
Write-Host " $($Components.Count) Komponenten" -ForegroundColor Green
|
||||
$Components | ForEach-Object { Write-Host " - $($_.name) (Lead: $(if ($_.lead) { $_.lead.displayName } else { '-' }))" }
|
||||
$Components | ConvertTo-Json -Depth 5 | Out-File "$OutputDir\components.json" -Encoding UTF8
|
||||
}
|
||||
|
||||
# 6. Versionen (Releases)
|
||||
Write-Host ">> Versionen laden..." -ForegroundColor Yellow
|
||||
$Versions = Invoke-JiraApi "$ApiBase/api/2/project/$ProjectKey/versions"
|
||||
if ($Versions) {
|
||||
$RecentVersions = $Versions | Where-Object { $_.released -eq $true -or $_.archived -eq $false } | Sort-Object -Property releaseDate -Descending | Select-Object -First 20
|
||||
Write-Host " $($Versions.Count) Versionen ($($RecentVersions.Count) aktuelle)" -ForegroundColor Green
|
||||
$Versions | ConvertTo-Json -Depth 5 | Out-File "$OutputDir\versions.json" -Encoding UTF8
|
||||
}
|
||||
|
||||
# 7. Analyse: Issues nach Team/Komponente
|
||||
Write-Host ""
|
||||
Write-Host ">> Analyse..." -ForegroundColor Yellow
|
||||
|
||||
$ByType = $AllIssues | Group-Object { $_.fields.issuetype.name }
|
||||
$ByStatus = $AllIssues | Group-Object { $_.fields.status.name }
|
||||
$ByComponent = @{}
|
||||
foreach ($Issue in $AllIssues) {
|
||||
if ($Issue.fields.components) {
|
||||
foreach ($Comp in $Issue.fields.components) {
|
||||
$ByComponent[$Comp.name] = ($ByComponent[$Comp.name]) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
$ByLabel = @{}
|
||||
foreach ($Issue in $AllIssues) {
|
||||
if ($Issue.fields.labels) {
|
||||
foreach ($Label in $Issue.fields.labels) {
|
||||
$ByLabel[$Label] = ($ByLabel[$Label]) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Ergebnis-Markdown
|
||||
$Md = @()
|
||||
$Md += "# Jira-Analyse pathOS ($ProjectKey)"
|
||||
$Md += ""
|
||||
$Md += "> Exportiert: $(Get-Date -Format 'yyyy-MM-dd HH:mm')"
|
||||
$Md += "> Issues (letzte 90 Tage): $($AllIssues.Count)"
|
||||
$Md += ""
|
||||
$Md += "## Issues nach Typ"
|
||||
foreach ($G in ($ByType | Sort-Object Count -Descending)) { $Md += "- $($G.Name): $($G.Count)" }
|
||||
$Md += ""
|
||||
$Md += "## Issues nach Status"
|
||||
foreach ($G in ($ByStatus | Sort-Object Count -Descending)) { $Md += "- $($G.Name): $($G.Count)" }
|
||||
$Md += ""
|
||||
$Md += "## Issues nach Komponente (Team)"
|
||||
foreach ($E in ($ByComponent.GetEnumerator() | Sort-Object Value -Descending)) { $Md += "- $($E.Key): $($E.Value)" }
|
||||
$Md += ""
|
||||
$Md += "## Issues nach Label"
|
||||
foreach ($E in ($ByLabel.GetEnumerator() | Sort-Object Value -Descending | Select-Object -First 30)) { $Md += "- $($E.Key): $($E.Value)" }
|
||||
$Md += ""
|
||||
$Md += "## Boards"
|
||||
if ($Boards -and $Boards.values) { foreach ($B in $Boards.values) { $Md += "- $($B.name) (ID: $($B.id), Typ: $($B.type))" } }
|
||||
$Md += ""
|
||||
$Md += "## Aktuelle Sprints"
|
||||
foreach ($S in ($AllSprints | Sort-Object startDate -Descending | Select-Object -First 10)) {
|
||||
$Md += "- $($S.name) | Board: $($S.boardName) | Status: $($S.state) | $($S.startDate) - $($S.endDate)"
|
||||
}
|
||||
$Md += ""
|
||||
$Md += "## Letzte Releases"
|
||||
if ($RecentVersions) { foreach ($V in $RecentVersions) { $Md += "- $($V.name) | Released: $($V.released) | Datum: $($V.releaseDate)" } }
|
||||
|
||||
$Md -join "`n" | Out-File "$OutputDir\jira-analyse.md" -Encoding UTF8
|
||||
|
||||
# CSV fuer Issues
|
||||
$CsvData = $AllIssues | ForEach-Object {
|
||||
$Comps = if ($_.fields.components) { ($_.fields.components | ForEach-Object { $_.name }) -join ", " } else { "" }
|
||||
$Labels = if ($_.fields.labels) { $_.fields.labels -join ", " } else { "" }
|
||||
$Fix = if ($_.fields.fixVersions) { ($_.fields.fixVersions | ForEach-Object { $_.name }) -join ", " } else { "" }
|
||||
[PSCustomObject]@{
|
||||
Key = $_.key
|
||||
Typ = $_.fields.issuetype.name
|
||||
Status = $_.fields.status.name
|
||||
Prioritaet = if ($_.fields.priority) { $_.fields.priority.name } else { "" }
|
||||
Zusammenfassung = $_.fields.summary
|
||||
Komponenten = $Comps
|
||||
Labels = $Labels
|
||||
FixVersion = $Fix
|
||||
Assignee = if ($_.fields.assignee) { $_.fields.assignee.displayName } else { "" }
|
||||
Erstellt = $_.fields.created
|
||||
Aktualisiert = $_.fields.updated
|
||||
}
|
||||
}
|
||||
$CsvData | Export-Csv "$OutputDir\issues.csv" -Delimiter ";" -Encoding UTF8 -NoTypeInformation
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "============================================================" -ForegroundColor Green
|
||||
Write-Host " FERTIG! Ergebnisse in $OutputDir" -ForegroundColor Green
|
||||
Write-Host "============================================================" -ForegroundColor Green
|
||||
Reference in New Issue
Block a user