gitlink-cli/workflows/01-community-ops.ps1

305 lines
12 KiB
PowerShell
Raw 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.

# ----------------------------------------------------------------
# Scenario 1: Community Operations Automation (定时批量链路)
# Flow: 收集周期数据 → 10类关键词分类 → 生成 Release Notes + 社区周报
# 遵循 gitlink-changelog skill 的收集→分类→发布流程
# 条目格式: - 描述 (#编号) (@作者) [分类]
# ----------------------------------------------------------------
#Requires -Version 5.1
param(
[string]$Owner = "",
[string]$Repo = "",
[int]$PeriodHours = 6,
[string]$ReleaseVersion = "",
[switch]$DryRun,
[switch]$Help
)
$ErrorActionPreference = "Stop"
Import-Module "$PSScriptRoot/lib/common.psm1" -Force
if ($Help) {
Write-Host "Usage: powershell 01-community-ops.ps1 [-Owner O] [-Repo R] [-PeriodHours N] [-ReleaseVersion TAG] [-DryRun]"
exit 0
}
Check-Auth
$r = Resolve-OwnerRepo $Owner $Repo
$Owner = $r.Owner; $Repo = $r.Repo
# ================================================================
# Phase 1: 时间窗口和基线
# ================================================================
Log-Title "Phase 1: Time Window"
$periodStart = (Get-Date).AddHours(-$PeriodHours)
$periodEnd = Get-Date
$periodStartStr = $periodStart.ToString("yyyy-MM-dd HH:mm")
$periodEndStr = $periodEnd.ToString("yyyy-MM-dd HH:mm")
Log-Step "Finding previous release..."
$prevTag = ""
$releasesJson = Invoke-GL release,+list,--owner,$Owner,--repo,$Repo,--limit,5
if ($releasesJson) {
try {
$relData = ($releasesJson | ConvertFrom-Json).data
$releases = if ($relData.releases) { @($relData.releases) } elseif ($relData -is [array]) { @($relData) } else { @() }
if ($releases.Count -gt 0) {
$prevTag = if ($releases[0].tag_name) { $releases[0].tag_name } else { "" }
}
} catch {}
}
if (-not $prevTag) { $prevTag = "initial" }
$newVersion = if ($ReleaseVersion) { $ReleaseVersion } else { "weekly-$(Get-Date -Format 'yyyyMMdd')" }
Log-Ok "Period: $periodStartStr ~ $periodEndStr"
Log-Ok "Release: $prevTag -> $newVersion"
# ================================================================
# Phase 2: 收集数据
# ================================================================
Log-Title "Phase 2: Collect Data"
# -- Commits --
Log-Step "Collecting commits..."
$commitCount = 0
$commitList = "(无 commit 数据)"
if ($prevTag -ne "initial") {
$compareJson = Invoke-GL api,GET,"/v1/$Owner/$Repo/compare/$prevTag...master"
if ($compareJson) {
try {
$cData = ($compareJson | ConvertFrom-Json).data
if ($cData.commits) {
$commits = @($cData.commits)
$commitCount = $commits.Count
$lines = @()
$show = [Math]::Min($commitCount, 50)
for ($i = 0; $i -lt $show; $i++) {
$msg = if ($commits[$i].commit.message) { ($commits[$i].commit.message -split "`n")[0] } else { "N/A" }
$author = if ($commits[$i].commit.author.name) { $commits[$i].commit.author.name } else { "unknown" }
$lines += "- $msg ($author)"
}
$commitList = $lines -join "`n"
}
} catch {}
}
}
Log-Ok "Commits: $commitCount"
# -- Merged PRs --
Log-Step "Collecting merged PRs..."
$prItems = @()
$prContributors = @{}
$prsJson = Invoke-GL pr,+list,--owner,$Owner,--repo,$Repo,--state,merged,--limit,100
if ($prsJson) {
try {
$prData = ($prsJson | ConvertFrom-Json).data
$prs = if ($prData.issues) { @($prData.issues) } elseif ($prData.pulls) { @($prData.pulls) } elseif ($prData -is [array]) { @($prData) } else { @() }
foreach ($pr in $prs) {
$prTitle = if ($pr.subject) { $pr.subject } elseif ($pr.title) { $pr.title } else { "N/A" }
$prNum = if ($pr.pull_request_number) { $pr.pull_request_number } elseif ($pr.number) { $pr.number } else { "?" }
$prAuthor = if ($pr.author_login) { $pr.author_login } elseif ($pr.author.login) { $pr.author.login } else { "?" }
$prItems += "- $prTitle (#$prNum) (@$prAuthor)"
$prContributors[$prAuthor] = $true
}
} catch {}
}
$prCount = $prItems.Count
$prText = if ($prCount -gt 0) { ($prItems -join "`n") } else { "(本周期无 PR 合并)" }
Log-Ok "Merged PRs: $prCount"
# -- Issues (新增 + 关闭) --
Log-Step "Collecting issues..."
$bugLines = @()
$featLines = @()
$docLines = @()
$otherLines = @()
$issContributors = @{}
$issCount = 0
$today = (Get-Date -Format "yyyy-MM-dd")
$yesterday = ((Get-Date).AddDays(-1)).ToString("yyyy-MM-dd")
foreach ($state in @("open","closed")) {
$issJson = Invoke-GL issue,+list,--owner,$Owner,--repo,$Repo,--state,$state,--limit,100
if (-not $issJson) { continue }
try {
$issData = ($issJson | ConvertFrom-Json).data
$issues = if ($issData.issues) { @($issData.issues) } elseif ($issData -is [array]) { @($issData) } else { @() }
foreach ($iss in $issues) {
$num = if ($iss.project_issues_index) { $iss.project_issues_index } elseif ($iss.number) { $iss.number } else { "?" }
$title = if ($iss.subject) { $iss.subject } elseif ($iss.title) { $iss.title } else { "N/A" }
$desc = if ($iss.description) { $iss.description } else { "" }
$author = if ($iss.author.login) { $iss.author.login } elseif ($iss.author.username) { $iss.author.username } else { "?" }
$created = if ($iss.created_at) { $iss.created_at } else { "" }
$closed = if ($iss.closed_at) { $iss.closed_at } else { "" }
$stateName = if ($iss.status.name) { $iss.status.name } elseif ($iss.state) { $iss.state } else { "?" }
# 时间筛选created 或 closed >= periodStart
$inPeriod = $false
if ($created) { try { if (([DateTime]$created) -ge $periodStart) { $inPeriod = $true } } catch {} }
if (-not $inPeriod -and $closed) { try { if (([DateTime]$closed) -ge $periodStart) { $inPeriod = $true } } catch {} }
if (-not $inPeriod) { continue }
$line = "- $title (#$num) (@$author)"
if ($stateName -match "关闭|closed") { $line += " [已关闭]" }
# 标题+描述 关键词分类 (10 个标准类别)
$combined = "$title $desc".ToLower()
if ($combined -match '(?i)bug|error|crash|fault|fix|缺陷|错误|异常|崩溃|修复|故障') {
$line += " [缺陷]"; $bugLines += $line
} elseif ($combined -match '(?i)feature|enhancement|add|新增|建议|功能|特性|新功能|支持|request') {
$line += " [功能]"; $featLines += $line
} elseif ($combined -match '(?i)doc|readme|guide|wiki|tutorial|文档|说明|教程|手册') {
$line += " [文档]"; $docLines += $line
} elseif ($combined -match '(?i)test|测试|用例|覆盖|验证') {
$line += " [测试]"; $docLines += $line
} elseif ($combined -match '(?i)duplicate|重复|重复的') {
$line += " [重复]"; $docLines += $line
} elseif ($combined -match '(?i)question|疑问|不确定|讨论|澄清|是否|可否') {
$line += " [疑问]"; $docLines += $line
} elseif ($combined -match '(?i)help|协助|帮助|协作|请求帮助|互助') {
$line += " [协助]"; $docLines += $line
} elseif ($combined -match '(?i)postpone|wontfix|暂缓|搁置|低优|不重要|不紧急|暂不|delay') {
$line += " [搁置]"; $docLines += $line
} elseif ($combined -match '(?i)task|todo|任务|待办|计划|安排') {
$line += " [任务]"; $docLines += $line
} elseif ($combined -match '(?i)support|兼容|环境|依赖|平台|适配') {
$line += " [支持]"; $docLines += $line
} else {
$line += " [其他]"; $otherLines += $line
}
if ($author -ne "?") { $issContributors[$author] = $true }
$issCount++
}
} catch {}
}
$bugSection = if ($bugLines.Count -gt 0) { ($bugLines -join "`n") } else { "_无_" }
$featSection = if ($featLines.Count -gt 0) { ($featLines -join "`n") } else { "_无_" }
$docSection = if ($docLines.Count -gt 0) { ($docLines -join "`n") } else { "_无_" }
$otherSection = if ($otherLines.Count -gt 0) { ($otherLines -join "`n") } else { "_无_" }
Log-Ok "Issues in period: $issCount"
# -- 贡献者汇总 --
$allContribs = @($prContributors.Keys; $issContributors.Keys) | Select-Object -Unique | Sort-Object
$contribText = if ($allContribs.Count -gt 0) { ($allContribs | ForEach-Object { "- @$_" }) -join "`n" } else { "(无活跃贡献者)" }
# ================================================================
# Phase 3: 生成 Release Notes (changelog skill 模板)
# ================================================================
Log-Title "Phase 3: Generate Release Notes"
$releaseBody = @"
# 🎉 Release $newVersion
## 📊
- ****: $periodStartStr ~ $periodEndStr
- ** PR**: $prCount
- **Issue **: $issCount /
- **Commits**: $commitCount
## 📝 Issue
### 🐛 / Bug
$bugSection
### / Feature
$featSection
### 📖 /
$docSection
### 💡
$otherSection
## 🔀 PR
$prText
## 🙏
$contribText
---
****: https://www.gitlink.org.cn/$Owner/$Repo/compare/$prevTag...$newVersion
*Auto-generated by gitlink-cli community-ops workflow (gitlink-changelog skill)*
"@
Write-Host $releaseBody
Write-Host ""
# ================================================================
# Phase 4: 发布 Release
# ================================================================
Log-Title "Phase 4: Publish Release"
if ($DryRun) {
Log-Warn "[DRY RUN] Would create release: $newVersion"
} else {
Log-Step "Creating release $newVersion..."
$relResult = Invoke-GL release,+create,--owner,$Owner,--repo,$Repo,--tag,$newVersion,--name,"Release $newVersion",--body,$releaseBody
if ($relResult -and (Get-JsonOk ($relResult | ConvertFrom-Json))) {
Log-Ok "Release $newVersion published!"
Log-Info "View: https://www.gitlink.org.cn/$Owner/$Repo/releases"
} else {
Log-Warn "Release may have failed (tag might exist)"
}
}
# ================================================================
# Phase 5: 发布社区周报 (覆盖更新同一天)
# ================================================================
Log-Title "Phase 5: Publish Weekly Report"
$wikiTitle = "社区周报"
$wikiBody = @"
# - $Owner/$Repo
**$periodStartStr ~ $periodEndStr**
---
## 📊
- PR: **$prCount**
- Issue : **$issCount**
- : $($allContribs.Count)
## 🔀 PR
$prText
## 📝 Issue
$bugSection
$featSection
$docSection
$otherSection
---
*Auto-generated by gitlink-cli | $periodStartStr ~ $periodEndStr | Next report in ~$PeriodHours h*
"@
if ($DryRun) {
Log-Warn "[DRY RUN] Would publish Wiki"
} else {
Log-Step "Publishing to Wiki..."
# 先尝试覆盖更新,不存在则新建
$wikiResult = Invoke-GL wiki,+update,--owner,$Owner,--repo,$Repo,--title,$wikiTitle,--cover,$wikiBody
if ($wikiResult -and (Get-JsonOk ($wikiResult | ConvertFrom-Json))) {
Log-Ok "Weekly report updated on Wiki"
} else {
Log-Info "Page not found, creating new..."
$wikiResult = Invoke-GL wiki,+create,--owner,$Owner,--repo,$Repo,--title,$wikiTitle,--content,$wikiBody
if ($wikiResult -and (Get-JsonOk ($wikiResult | ConvertFrom-Json))) {
Log-Ok "Weekly report created on Wiki"
} else {
Log-Warn "Wiki publish failed"
}
}
}
Log-Title "Complete"
Write-Host " Release: $newVersion" -ForegroundColor Green
Write-Host " PRs merged: $prCount" -ForegroundColor Green
Write-Host " Issues: $issCount" -ForegroundColor Green
Write-Host " Contributors: $($allContribs.Count)" -ForegroundColor Green
Write-Host " Wiki: $wikiTitle" -ForegroundColor Green