gitlink-cli/workflows/04-multi-repo-collab.ps1

210 lines
8.4 KiB
PowerShell

# ----------------------------------------------------------------
# Scenario 4: Multi-Repo Collaboration
# Flow: Cross-repo issue tracking -> PR status dashboard -> Coordinated release
#
# Commands chained:
# 1. repo +list -- list all repos in org
# 2. issue +list -- fetch issues from each repo
# 3. pr +list -- fetch PRs from each repo
# 4. release +list -- check release status across repos
# 5. release +create -- coordinated release (optional)
# 6. Generate HTML dashboard
# ----------------------------------------------------------------
#Requires -Version 5.1
param(
[Parameter(Mandatory=$true)]
[string]$Org,
[string]$Repos = "",
[string]$Release = "",
[string]$Output = "dashboard.html",
[switch]$DryRun,
[switch]$Help
)
$ErrorActionPreference = "Stop"
Import-Module "$PSScriptRoot/lib/common.psm1" -Force -WarningAction SilentlyContinue
if ($Help) {
Write-Host "Usage: powershell 04-multi-repo-collab.ps1 -Org ORG [-Repos 'repo1,repo2'] [-Release TAG] [-Output FILE] [-DryRun]"
exit 0
}
Check-Auth
# -- Step 1: List Repositories --
Log-Title "Multi-Repo Collaboration Dashboard"
Log-Step "Fetching repositories for org: $Org..."
$reposJson = Invoke-GLCheck "repo", "+list", "--user", $Org, "--limit", "100"
if (-not $reposJson) { Log-Err "Failed to fetch repos"; exit 1 }
$allRepos = @()
$rd = $reposJson.data
if ($rd.projects) { $allRepos = @($rd.projects) }
elseif ($rd -is [array]) { $allRepos = $rd }
Log-Ok "Found $($allRepos.Count) repositories"
$repoList = @()
if ($Repos) {
$repoList = $Repos -split ','
Log-Info "Filtering to specified repos: $($repoList -join ', ')"
} else {
foreach ($r in $allRepos) {
$rname = if ($r.name) { $r.name } elseif ($r.identifier) { $r.identifier } else { $null }
if ($rname) { $repoList += $rname }
}
}
Log-Ok "Will process $($repoList.Count) repositories"
# -- Step 2-3: Collect Issues and PRs from each repo --
Log-Title "Collecting Data Across Repos"
$totalIssues = 0; $totalOpenIssues = 0; $totalPRs = 0; $totalOpenPRs = 0
$dashboardRows = ""
foreach ($repo in $repoList) {
Divider
Log-Step "Processing $Org/$repo..."
$issuesJson = Invoke-GL "issue", "+list", "--owner", $Org, "--repo", $repo, "--state", "open", "--limit", "50"
$openIssues = if ($issuesJson) { @($issuesJson.data.issues).Count } else { 0 }
$closedJson = Invoke-GL "issue", "+list", "--owner", $Org, "--repo", $repo, "--state", "closed", "--limit", "50"
$closedIssues = if ($closedJson) { @($closedJson.data.issues).Count } else { 0 }
$prsJson = Invoke-GL "pr", "+list", "--owner", $Org, "--repo", $repo, "--state", "open", "--limit", "50"
$openPRs = 0
if ($prsJson) {
$pd = $prsJson.data
if ($pd.issues) { $openPRs = @($pd.issues).Count }
elseif ($pd.pulls) { $openPRs = @($pd.pulls).Count }
elseif ($pd -is [array]) { $openPRs = $pd.Count }
}
$mergedJson = Invoke-GL "pr", "+list", "--owner", $Org, "--repo", $repo, "--state", "merged", "--limit", "50"
$mergedPRs = 0
if ($mergedJson) {
$md = $mergedJson.data
if ($md.issues) { $mergedPRs = @($md.issues).Count }
elseif ($md.pulls) { $mergedPRs = @($md.pulls).Count }
elseif ($md -is [array]) { $mergedPRs = $md.Count }
}
$releaseJson = Invoke-GL "release", "+list", "--owner", $Org, "--repo", $repo, "--limit", "1"
$latestRelease = "none"
if ($releaseJson -and $releaseJson.data.releases) {
$releases = @($releaseJson.data.releases)
if ($releases.Count -gt 0) {
$latestRelease = if ($releases[0].tag_name) { $releases[0].tag_name } elseif ($releases[0].name) { $releases[0].name } else { "none" }
}
}
Log-Ok "$repo : Issues(open:$openIssues closed:$closedIssues) PRs(open:$openPRs merged:$mergedPRs) Release:$latestRelease"
$statusColor = "green"
$healthText = "Healthy"
if ($openIssues -gt 10) { $statusColor = "orange"; $healthText = "Moderate" }
if ($openIssues -gt 20) { $statusColor = "red"; $healthText = "Needs Attention" }
$dashboardRows += "<tr>`n"
$dashboardRows += " <td><a href=`"https://gitlink.org.cn/$Org/$repo`">$repo</a></td>`n"
$dashboardRows += " <td>$openIssues</td><td>$closedIssues</td>`n"
$dashboardRows += " <td>$openPRs</td><td>$mergedPRs</td><td>$latestRelease</td>`n"
$dashboardRows += " <td style=`"color:$statusColor;font-weight:bold;`">$healthText</td>`n"
$dashboardRows += "</tr>`n"
$totalIssues += $openIssues + $closedIssues
$totalOpenIssues += $openIssues
$totalPRs += $openPRs + $mergedPRs
$totalOpenPRs += $openPRs
}
# -- Step 4: Generate HTML Dashboard --
Log-Title "Generating Dashboard"
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$repoCount = $repoList.Count
$html = '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multi-Repo Collaboration Dashboard</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #f5f5f5; padding: 20px; }
.container { max-width: 1200px; margin: 0 auto; }
h1 { color: #333; margin-bottom: 20px; }
.summary { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 30px; }
.card { background: white; border-radius: 8px; padding: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.card h3 { color: #666; font-size: 14px; margin-bottom: 8px; }
.card .value { font-size: 32px; font-weight: bold; color: #333; }
.card.blue .value { color: #2196F3; }
.card.green .value { color: #4CAF50; }
.card.orange .value { color: #FF9800; }
.card.purple .value { color: #9C27B0; }
table { width: 100%; border-collapse: collapse; background: white; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
th { background: #2196F3; color: white; padding: 12px 16px; text-align: left; }
td { padding: 12px 16px; border-bottom: 1px solid #eee; }
tr:hover { background: #f9f9f9; }
a { color: #2196F3; text-decoration: none; }
a:hover { text-decoration: underline; }
.timestamp { color: #999; font-size: 14px; margin-bottom: 20px; }
</style>
</head>
<body>
<div class="container">
<h1>Multi-Repo Collaboration Dashboard</h1>
<p class="timestamp">Generated: ' + $timestamp + ' | Organization: ' + $Org + '</p>
<div class="summary">
<div class="card blue"><h3>Total Repos</h3><div class="value">' + $repoCount + '</div></div>
<div class="card orange"><h3>Open Issues</h3><div class="value">' + $totalOpenIssues + '</div></div>
<div class="card purple"><h3>Open PRs</h3><div class="value">' + $totalOpenPRs + '</div></div>
<div class="card green"><h3>Total Activity</h3><div class="value">' + $totalIssues + '</div></div>
</div>
<table>
<thead><tr><th>Repository</th><th>Open Issues</th><th>Closed Issues</th><th>Open PRs</th><th>Merged PRs</th><th>Latest Release</th><th>Health</th></tr></thead>
<tbody>
' + $dashboardRows + '
</tbody>
</table>
</div>
</body>
</html>'
$html | Out-File -FilePath $Output -Encoding UTF8
Log-Ok "Dashboard saved to: $Output"
# -- Step 5: Coordinated Release --
if ($Release) {
Log-Title "Coordinated Release: $Release"
foreach ($repo in $repoList) {
Log-Step "Creating release for $Org/$repo..."
$relBody = "Coordinated release $Release for $Org/$repo"
$relResult = Invoke-GL "release", "+create", "--owner", $Org, "--repo", $repo, "--tag", $Release, "--name", "Release $Release", "--body", $relBody
if ($relResult -and (Get-JsonOk $relResult)) {
Log-Ok "Release $Release created for $repo"
} else {
Log-Warn "Release creation failed for $repo (tag may already exist)"
}
}
}
# ----------------------------------------------------------------
Log-Title "Multi-Repo Dashboard Complete"
# ----------------------------------------------------------------
Write-Host " Repos processed: $repoCount" -ForegroundColor Green
Write-Host " Total issues: $totalIssues (open: $totalOpenIssues)" -ForegroundColor Green
Write-Host " Total PRs: $totalPRs (open: $totalOpenPRs)" -ForegroundColor Green
Write-Host " Dashboard: $Output" -ForegroundColor Green
if ($Release) { Write-Host " Coordinated release: $Release" -ForegroundColor Green }
Write-Host ""
Write-Host "Open dashboard:" -ForegroundColor Cyan
Write-Host " Start-Process $Output"