gitlink-cli/workflows/01a-webhook-setup.ps1

324 lines
14 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 1a: Webhook Setup — Register on GitLink Platform
# Role: 在 GitLink 平台上注册 webhook连接"平台事件"到"本地接收器"
#
# 这是整个实时链路的最后一块拼图——把 GitLink 平台的 Issue 创建事件
# 和本地的 01a-webhook-listener.ps1 接收器连接起来。
#
# 完整链路:
# GitLink Issue 创建
# → Webhook POST 到 <WebhookUrl>
# → 01a-webhook-listener.ps1 (接收 HTTP 请求)
# → 01a-issue-triage.ps1 (AI 分类 + 打标签 + 分配)
#
# 前置条件:
# 方案A (本地开发): 先启动 ngrok → 再启动 01a-webhook-listener.ps1 → 再运行本脚本
# 方案B (公网服务器): 先启动 01a-webhook-listener.ps1 → 再运行本脚本直接给公网URL
# ----------------------------------------------------------------
#Requires -Version 5.1
param(
[string]$WebhookUrl = "",
[string]$Owner = "",
[string]$Repo = "",
[string]$Secret = "",
[string]$Events = "issue",
[string]$Description = "Community Ops — Issue Auto-Triage (created by gitlink-cli)",
[switch]$DryRun,
[switch]$ListExisting,
[switch]$DeleteExisting,
[switch]$Force,
[switch]$Help
)
$ErrorActionPreference = "Stop"
Import-Module "$PSScriptRoot/lib/common.psm1" -Force -WarningAction SilentlyContinue
if ($Help) {
Write-Host "Usage: powershell 01a-webhook-setup.ps1 -WebhookUrl URL [-Owner OWNER] [-Repo REPO] [-Secret SECRET] [-Events EVENTS] [-DryRun]"
Write-Host ""
Write-Host " 在 GitLink 平台上注册 webhook将 Issue 创建事件连接到本地接收器。"
Write-Host ""
Write-Host " -WebhookUrl URL (必填) Webhook 回调地址GitLink 会向此 URL POST 事件"
Write-Host " - 本地开发: https://xxx.ngrok-free.app/webhook"
Write-Host " - 公网服务器: https://your-server.com:8080/webhook"
Write-Host " -Owner OWNER 仓库所有者在git仓库内可自动检测"
Write-Host " -Repo REPO 仓库名称在git仓库内可自动检测"
Write-Host " -Secret SECRET HMAC 密钥(需与 01a-webhook-listener.ps1 的 -Secret 一致)"
Write-Host " -Events EVENTS 触发事件类型(默认: issue"
Write-Host " -Description DESC Webhook 描述"
Write-Host " -ListExisting 列出当前仓库已有的 webhook"
Write-Host " -DeleteExisting 删除当前仓库所有非 gitlink-cli 创建的 issue 类 webhook需配合 -Force"
Write-Host " -Force 配合 -DeleteExisting 使用"
Write-Host " -DryRun 预览模式"
Write-Host ""
Write-Host " 部署步骤:"
Write-Host " # 终端 1: 启动 ngrok本地开发"
Write-Host " ngrok http 8080"
Write-Host ""
Write-Host " # 终端 2: 启动接收器"
Write-Host " powershell workflows/01a-webhook-listener.ps1 -Port 8080 -Secret 'your-secret'"
Write-Host ""
Write-Host " # 终端 3: 注册 webhookngrok 提供的 URL"
Write-Host " powershell workflows/01a-webhook-setup.ps1 -WebhookUrl 'https://xxx.ngrok-free.app/webhook' -Secret 'your-secret'"
exit 0
}
if (-not $WebhookUrl) { Log-Err "WebhookUrl is required (use -Help for usage)"; exit 1 }
Check-Auth
$r = Resolve-OwnerRepo $Owner $Repo
$Owner = $r.Owner; $Repo = $r.Repo
# ================================================================
# Validation
# ================================================================
Log-Title "Webhook Setup: $Owner/$Repo"
# Validate URL format
if ($WebhookUrl -notmatch '^https?://') {
Log-Err "Webhook URL must start with http:// or https://"
Log-Info "For GitLink platform, HTTPS is required. Use ngrok for local dev: ngrok http 8080"
exit 1
}
if ($WebhookUrl -notmatch '^https://') {
Log-Warn "GitLink requires HTTPS URLs for webhooks. Your URL uses HTTP which may be rejected."
Log-Info "Consider using ngrok to get an HTTPS URL: ngrok http <port>"
}
Write-Host " Owner: $Owner"
Write-Host " Repo: $Repo"
Write-Host " Webhook URL: $WebhookUrl"
Write-Host " Events: $Events"
Write-Host " Secret: $(if ($Secret) { '***configured***' } else { '(not set)' })"
Write-Host " Description: $Description"
Divider
# ================================================================
# List existing webhooks
# ================================================================
if ($ListExisting -or $DeleteExisting) {
Log-Title "Existing Webhooks"
$listResult = Invoke-GL webhook,+list,--owner,$Owner,--repo,$Repo
if (-not $listResult) {
Log-Warn "Could not list webhooks (API may not be available or no webhooks)"
} else {
try {
$listData = $listResult | ConvertFrom-Json
if ($listData.ok -and $listData.data) {
$webhooks = @()
if ($listData.data.webhooks) { $webhooks = @($listData.data.webhooks) }
elseif ($listData.data -is [array]) { $webhooks = $listData.data }
if ($webhooks.Count -eq 0) {
Log-Info "No webhooks configured for this repo"
} else {
Write-Host ""
foreach ($wh in $webhooks) {
$whId = if ($wh.id) { $wh.id } else { "?" }
$whUrl = if ($wh.hook_url) { $wh.hook_url } elseif ($wh.url) { $wh.url } else { "?" }
$whActive = if ($wh.is_active -ne $null) { $wh.is_active } elseif ($wh.active -ne $null) { $wh.active } else { "?" }
$whEvents = if ($wh.events) { ($wh.events -join ',') } else { "?" }
$whDesc = if ($wh.description) { $wh.description } else { "(no description)" }
Write-Host " [#$whId] $whUrl" -ForegroundColor Cyan
Write-Host " Active: $whActive | Events: $whEvents"
Write-Host " $whDesc"
Write-Host ""
}
}
}
} catch {
Log-Warn "Could not parse webhook list: $_"
Log-Info "Raw output: $listResult"
}
}
}
# ================================================================
# Delete existing issue-related webhooks (cleanup before create)
# ================================================================
if ($DeleteExisting) {
if (-not $Force) {
Log-Warn "-DeleteExisting requires -Force flag for safety. Add -Force to confirm deletion."
} else {
Log-Warn "Removing existing webhooks that match issue events..."
$listResult = Invoke-GL webhook,+list,--owner,$Owner,--repo,$Repo
if ($listResult) {
try {
$listData = $listResult | ConvertFrom-Json
$webhooks = @()
if ($listData.data.webhooks) { $webhooks = @($listData.data.webhooks) }
elseif ($listData.data -is [array]) { $webhooks = $listData.data }
foreach ($wh in $webhooks) {
$whId = if ($wh.id) { $wh.id } else { $null }
$whEvents = if ($wh.events) { $wh.events } else { @() }
$whUrl = if ($wh.hook_url) { $wh.hook_url } else { "" }
# Only delete issue-related ones that point to gitlink-cli created URLs
$isIssueWebhook = ($whEvents -contains "issue") -or ($whEvents -is [string] -and $whEvents -match "issue")
if ($isIssueWebhook) {
if ($DryRun) {
Log-Warn "[DRY RUN] Would delete webhook #$whId ($whUrl)"
} else {
Log-Step "Deleting webhook #$whId..."
$delResult = Invoke-GL webhook,+delete,--owner,$Owner,--repo,$Repo,--id,$whId
if ($delResult) {
Log-Ok "Deleted webhook #$whId"
} else {
Log-Warn "Failed to delete webhook #$whId"
}
}
}
}
} catch { }
}
}
if (-not $ListExisting) {
Log-Info "Cleanup complete. Proceeding to create new webhook..."
} else {
# User just wanted to list, exit
exit 0
}
}
if ($ListExisting) { exit 0 }
# ================================================================
# Check for existing webhook with same URL
# ================================================================
Log-Step "Checking for existing webhooks with same URL..."
$listResult = Invoke-GL webhook,+list,--owner,$Owner,--repo,$Repo
$existingId = $null
if ($listResult) {
try {
$listData = $listResult | ConvertFrom-Json
$webhooks = @()
if ($listData.data.webhooks) { $webhooks = @($listData.data.webhooks) }
elseif ($listData.data -is [array]) { $webhooks = $listData.data }
foreach ($wh in $webhooks) {
if ($wh.hook_url -eq $WebhookUrl -or $wh.url -eq $WebhookUrl) {
$existingId = $wh.id
break
}
}
} catch { }
}
if ($existingId) {
Log-Warn "A webhook with URL '$WebhookUrl' already exists (ID: #$existingId)"
Log-Info "To replace it, delete the existing one first with:"
Log-Info " gitlink-cli webhook +delete --owner $Owner --repo $Repo --id $existingId"
Log-Info "Or run this script with -DeleteExisting -Force to clean up"
exit 1
}
Log-Ok "No duplicate webhook found"
# ================================================================
# Register Webhook on GitLink
# ================================================================
Log-Title "Registering Webhook"
# Build command arguments
$createArgs = @(
"webhook", "+create",
"--owner", $Owner,
"--repo", $Repo,
"--url", $WebhookUrl,
"--events", $Events,
"--description", $Description
)
if ($Secret) {
$createArgs += @("--secret", $Secret)
}
Log-Step "Creating webhook on GitLink platform..."
Log-Info "Command: gitlink-cli $($createArgs -join ' ')"
if ($DryRun) {
Log-Warn "[DRY RUN] Would create webhook with above parameters"
exit 0
}
$createResult = Invoke-GLCheck @createArgs
if (-not $createResult) {
Log-Err "Webhook creation failed"
Log-Info "Common issues:"
Log-Info " 1. URL must be HTTPS (GitLink requirement)"
Log-Info " 2. URL must be publicly accessible from GitLink's servers"
Log-Info " 3. You may need admin permissions on the repo"
Log-Info " 4. Max 20 webhooks per repo — use -ListExisting to check"
exit 1
}
$webhookId = ""
if ($createResult.data.id) { $webhookId = $createResult.data.id }
elseif ($createResult.data.webhook.id) { $webhookId = $createResult.data.webhook.id }
Log-Ok "Webhook created! ID: #$webhookId"
# ================================================================
# Test Webhook
# ================================================================
Log-Step "Testing webhook connectivity..."
$testResult = Invoke-GL webhook,+test,--owner,$Owner,--repo,$Repo,--id,$webhookId,--event,issue
if ($testResult) {
try {
$testOk = (($testResult | ConvertFrom-Json).ok -eq $true)
} catch { $testOk = $false }
if ($testOk) {
Log-Ok "Webhook test ping sent successfully"
Log-Info "Check the listener console for the test event"
} else {
Log-Warn "Webhook test may have failed — check that your listener is running and accessible"
Log-Info "Verify: curl -X POST $WebhookUrl -H 'Content-Type: application/json' -d '{}'"
}
} else {
Log-Warn "Could not test webhook — check that your listener is running"
}
# ================================================================
# Complete
# ================================================================
Log-Title "Webhook Setup Complete"
Write-Host ""
$checkmark = [char]0x2714
Write-Host " ${checkmark} GitLink Platform: Webhook registered" -ForegroundColor Green
Write-Host " → When a new Issue is created in $Owner/$Repo" -ForegroundColor Gray
Write-Host " → GitLink POSTs to: $WebhookUrl" -ForegroundColor Gray
Write-Host " → Webhook ID: #$webhookId" -ForegroundColor Gray
Write-Host ""
Write-Host " ${checkmark} Local Listener: 01a-webhook-listener.ps1" -ForegroundColor Green
Write-Host " → Receives HTTP POST from GitLink" -ForegroundColor Gray
Write-Host " → Validates HMAC signature" -ForegroundColor Gray
Write-Host " → Calls 01a-issue-triage.ps1" -ForegroundColor Gray
Write-Host ""
Write-Host " ${checkmark} Triage Script: 01a-issue-triage.ps1" -ForegroundColor Green
Write-Host " → AI analyzes issue content" -ForegroundColor Gray
Write-Host " → Selects matching label from repo's existing labels" -ForegroundColor Gray
Write-Host " → Assigns to issue creator" -ForegroundColor Gray
Write-Host ""
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
Write-Host " 验证方式:" -ForegroundColor Cyan
Write-Host " 1. 在 GitLink 网页端 $Owner/$Repo 创建一个新 Issue" -ForegroundColor White
Write-Host " 2. 观察 01a-webhook-listener.ps1 的控制台输出" -ForegroundColor White
Write-Host " 3. 检查 Issue 是否自动被打上标签并分配了负责人" -ForegroundColor White
Write-Host ""
Write-Host " 手动测试(不走 webhook直接触发分类:" -ForegroundColor Cyan
Write-Host " powershell workflows/01a-issue-triage.ps1 -IssueNumber <N>" -ForegroundColor White
Write-Host "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor Cyan
Write-Host ""
Write-Host " Webhook 管理:" -ForegroundColor Cyan
Write-Host " - 查看: gitlink-cli webhook +list"
Write-Host " - 详情: gitlink-cli webhook +info --id $webhookId"
Write-Host " - 删除: gitlink-cli webhook +delete --id $webhookId"