test(feishu): add local setup and smoke scripts

This commit is contained in:
whzy 2026-06-26 16:28:57 +08:00
parent 8bcc8607f5
commit 73da46c143
13 changed files with 906 additions and 116 deletions

6
.gitignore vendored
View File

@ -1,3 +1,9 @@
gitlink-cli.exe gitlink-cli.exe
/gitlink-cli /gitlink-cli
.local/*
!.local/
!.local/feishu-gitlink.env.example.ps1
*.local.ps1
*.secret.*
reports/feishu-real-smoke-terminal.log

View File

@ -0,0 +1,30 @@
# Stable Feishu webhook
$env:FEISHU_WEBHOOK_URL=""
$env:FEISHU_WEBHOOK_SECRET=""
# Feishu Open Platform
$env:FEISHU_APP_ID=""
$env:FEISHU_APP_SECRET=""
# Feishu DocX / Wiki
$env:FEISHU_WIKI_URL=""
$env:FEISHU_WIKI_NODE_TOKEN=""
$env:FEISHU_FOLDER_TOKEN=""
# Feishu Base / Bitable
$env:FEISHU_BASE_APP_TOKEN=""
$env:FEISHU_REPORT_TABLE_ID=""
$env:FEISHU_ISSUE_TABLE_ID=""
$env:FEISHU_PR_TABLE_ID=""
$env:FEISHU_CONTRIBUTOR_TABLE_ID=""
$env:FEISHU_TASK_TABLE_ID=""
# Feishu Task
$env:FEISHU_TASK_PROJECT_ID=""
$env:FEISHU_TASK_SECTION_ID=""
# GitLink real test input
$env:GITLINK_OWNER=""
$env:GITLINK_REPO=""
$env:GITLINK_TEST_PR_IDS=""
$env:GITLINK_TOKEN=""

View File

@ -686,6 +686,16 @@ Details:
- [Feishu environment variables](./docs/FEISHU_ENVIRONMENT.md) - [Feishu environment variables](./docs/FEISHU_ENVIRONMENT.md)
- [Feishu permission matrix](./reports/FEISHU_PERMISSION_MATRIX.md) - [Feishu permission matrix](./reports/FEISHU_PERMISSION_MATRIX.md)
Local setup and smoke testing:
```powershell
.\scripts\feishu-gitlink-setup.ps1
.\scripts\feishu-gitlink-env-check.ps1 -Layer stable
.\scripts\feishu-gitlink-smoke.ps1 -Mode preview
```
The setup script stores real values only in `.local/feishu-gitlink.env.ps1`, which is ignored.
### Dataset ### Dataset
`dataset` manages and queries GitLink research datasets (title, description, `dataset` manages and queries GitLink research datasets (title, description,

View File

@ -586,6 +586,16 @@ gitlink-cli feishu +task-create --from-workflow-json report.json --send --format
- [飞书能力分层](./docs/FEISHU_CAPABILITY_LAYERS.md) - [飞书能力分层](./docs/FEISHU_CAPABILITY_LAYERS.md)
- [飞书环境变量](./docs/FEISHU_ENVIRONMENT.md) - [飞书环境变量](./docs/FEISHU_ENVIRONMENT.md)
- [飞书权限矩阵](./reports/FEISHU_PERMISSION_MATRIX.md) - [飞书权限矩阵](./reports/FEISHU_PERMISSION_MATRIX.md)
本地配置和 smoke 测试:
```powershell
.\scripts\feishu-gitlink-setup.ps1
.\scripts\feishu-gitlink-env-check.ps1 -Layer stable
.\scripts\feishu-gitlink-smoke.ps1 -Mode preview
```
真实值只会写入被忽略的 `.local/feishu-gitlink.env.ps1`,不要提交。
### Raw API ### Raw API
Shortcuts 未覆盖的接口可通过 Raw API 直接调用: Shortcuts 未覆盖的接口可通过 Raw API 直接调用:

View File

@ -4,6 +4,26 @@ Date: 2026-06-26
Do not commit real values. Use a local shell profile, CI secret store, or test terminal session. Do not commit real values. Use a local shell profile, CI secret store, or test terminal session.
Recommended local workflow:
```powershell
.\scripts\feishu-gitlink-setup.ps1
.\scripts\feishu-gitlink-env-check.ps1 -Layer stable
.\scripts\feishu-gitlink-smoke.ps1 -Mode preview
```
`feishu-gitlink-setup.ps1` opens the relevant Feishu / GitLink pages, lets the user paste values locally, and writes only to:
```text
.local/feishu-gitlink.env.ps1
```
The real local env file is ignored. The tracked example is:
```text
.local/feishu-gitlink.env.example.ps1
```
## Stable Custom Bot Variables ## Stable Custom Bot Variables
| Name | Purpose | Required | Used by | Sensitive | How to obtain | | Name | Purpose | Required | Used by | Sensitive | How to obtain |
@ -112,6 +132,7 @@ $env:GITLINK_TOKEN="REDACTED"
```text ```text
Never paste real secrets into committed docs. Never paste real secrets into committed docs.
Never paste real secrets into ChatGPT.
Never print raw webhook URLs or app secrets in smoke reports. Never print raw webhook URLs or app secrets in smoke reports.
Do not commit tenant_access_token or user_access_token. Do not commit tenant_access_token or user_access_token.
Do not enable --send in shared scripts unless the target test enterprise is intentional. Do not enable --send in shared scripts unless the target test enterprise is intentional.

View File

@ -6,6 +6,12 @@ This file lists the manual screenshots to capture after local and real smoke tes
Do not fabricate screenshots. If a capability is not available in the test enterprise, keep the placeholder and record the failure in `reports/FEISHU_SMOKE_20260626.md`. Do not fabricate screenshots. If a capability is not available in the test enterprise, keep the placeholder and record the failure in `reports/FEISHU_SMOKE_20260626.md`.
Use the helper to check current screenshot status:
```powershell
.\scripts\feishu-gitlink-screenshot-check.ps1
```
| Screenshot | Expected path | Capture note | | Screenshot | Expected path | Capture note |
| --- | --- | --- | | --- | --- | --- |
| Feishu bot card in test group | `docs/images/feishu-bot-card.png` | Capture after `+bot-test --send` or `+notify --send` | | Feishu bot card in test group | `docs/images/feishu-bot-card.png` | Capture after `+bot-test --send` or `+notify --send` |

View File

@ -53,6 +53,15 @@ Experimental commands use Feishu self-built app OpenAPI and are not part of the
Use a Feishu custom group bot for notification cards. Use a Feishu custom group bot for notification cards.
Recommended local setup:
```powershell
.\scripts\feishu-gitlink-setup.ps1
.\scripts\feishu-gitlink-env-check.ps1 -Layer stable
```
The setup wizard opens Feishu / GitLink pages and stores values only in `.local/feishu-gitlink.env.ps1`.
Environment: Environment:
```powershell ```powershell
@ -288,3 +297,12 @@ docs/FEISHU_ENVIRONMENT.md
reports/FEISHU_PERMISSION_MATRIX.md reports/FEISHU_PERMISSION_MATRIX.md
reports/FEISHU_LOCAL_TESTING_GUIDE.md reports/FEISHU_LOCAL_TESTING_GUIDE.md
``` ```
Scripted smoke test:
```powershell
.\scripts\feishu-gitlink-smoke.ps1 -Mode preview
.\scripts\feishu-gitlink-smoke.ps1 -Mode stable
.\scripts\feishu-gitlink-smoke.ps1 -Mode open-platform
.\scripts\feishu-gitlink-smoke.ps1 -Mode all
```

View File

@ -4,7 +4,48 @@ Date: 2026-06-26
This guide verifies the layered Feishu integration without committing secrets. This guide verifies the layered Feishu integration without committing secrets.
## 1. Configure GitLink Test Repository ## 1. Run Local Setup Wizard
```powershell
.\scripts\feishu-gitlink-setup.ps1
```
The setup wizard opens these pages as needed:
```text
Feishu custom bot documentation
Feishu developer console
Feishu Docs / Wiki
Feishu Base / Bitable
Feishu Tasks
GitLink
```
The user logs in and authorizes in the browser. Values are pasted into the local PowerShell prompt, not into ChatGPT.
The wizard writes only to:
```text
.local/feishu-gitlink.env.ps1
```
This file is ignored and must not be committed. A tracked empty example is available at:
```text
.local/feishu-gitlink.env.example.ps1
```
## 2. Check Local Environment
```powershell
.\scripts\feishu-gitlink-env-check.ps1 -Layer stable
.\scripts\feishu-gitlink-env-check.ps1 -Layer open-platform
.\scripts\feishu-gitlink-env-check.ps1 -Layer all
```
The checker prints only redacted values.
## 3. Configure GitLink Test Repository Manually If Needed
```powershell ```powershell
$env:GITLINK_OWNER="OWNER" $env:GITLINK_OWNER="OWNER"
@ -17,7 +58,43 @@ If the current workflow command cannot filter specific PR IDs, keep the PR IDs i
$env:GITLINK_TEST_PR_IDS="1,2,3" $env:GITLINK_TEST_PR_IDS="1,2,3"
``` ```
## 2. Generate Workflow Report JSON ## 4. Run Scripted Smoke Tests
Preview only:
```powershell
.\scripts\feishu-gitlink-smoke.ps1 -Mode preview
```
Stable custom bot sends:
```powershell
.\scripts\feishu-gitlink-smoke.ps1 -Mode stable
```
Experimental Open Platform sends:
```powershell
.\scripts\feishu-gitlink-smoke.ps1 -Mode open-platform
```
All available tests:
```powershell
.\scripts\feishu-gitlink-smoke.ps1 -Mode all
```
The smoke runner writes:
```text
.local/report.json
reports/FEISHU_SMOKE_YYYYMMDD.md
reports/feishu-real-smoke-terminal.log
```
The terminal log is ignored and must not be committed after real runs.
## 5. Generate Workflow Report JSON Manually
```bash ```bash
gitlink-cli workflow +repo-report \ gitlink-cli workflow +repo-report \
@ -28,13 +105,13 @@ gitlink-cli workflow +repo-report \
Windows PowerShell redirection may produce UTF-16 with BOM. The Feishu workflow JSON reader supports UTF-8 and UTF-16 BOM inputs. Windows PowerShell redirection may produce UTF-16 with BOM. The Feishu workflow JSON reader supports UTF-8 and UTF-16 BOM inputs.
## 3. Preview Feishu Notify Card ## 6. Preview Feishu Notify Card
```bash ```bash
gitlink-cli feishu +notify --from-workflow-json report.json --format json gitlink-cli feishu +notify --from-workflow-json report.json --format json
``` ```
## 4. Send Feishu Notify Card ## 7. Send Feishu Notify Card
```bash ```bash
gitlink-cli feishu +notify --from-workflow-json report.json --send --format table gitlink-cli feishu +notify --from-workflow-json report.json --send --format table
@ -47,50 +124,50 @@ FEISHU_WEBHOOK_URL
FEISHU_WEBHOOK_SECRET optional FEISHU_WEBHOOK_SECRET optional
``` ```
## 5. Render Weekly Report ## 8. Render Weekly Report
```bash ```bash
gitlink-cli feishu +weekly-report --from-workflow-json report.json --format markdown gitlink-cli feishu +weekly-report --from-workflow-json report.json --format markdown
``` ```
## 6. Send Weekly Report ## 9. Send Weekly Report
```bash ```bash
gitlink-cli feishu +weekly-report --from-workflow-json report.json --send --format table gitlink-cli feishu +weekly-report --from-workflow-json report.json --send --format table
``` ```
## 7. Generate Owner Digest ## 10. Generate Owner Digest
```bash ```bash
gitlink-cli feishu +owner-digest --from-workflow-json report.json --format markdown gitlink-cli feishu +owner-digest --from-workflow-json report.json --format markdown
``` ```
## 8. Send Owner Digest ## 11. Send Owner Digest
```bash ```bash
gitlink-cli feishu +owner-digest --from-workflow-json report.json --send --format table gitlink-cli feishu +owner-digest --from-workflow-json report.json --send --format table
``` ```
## 9. Generate Contributor Digest ## 12. Generate Contributor Digest
```bash ```bash
gitlink-cli feishu +contributor-digest --from-workflow-json report.json --format markdown gitlink-cli feishu +contributor-digest --from-workflow-json report.json --format markdown
``` ```
## 10. Send Contributor Digest ## 13. Send Contributor Digest
```bash ```bash
gitlink-cli feishu +contributor-digest --from-workflow-json report.json --send --format table gitlink-cli feishu +contributor-digest --from-workflow-json report.json --send --format table
``` ```
## 11. Generate Bitable-Ready Records ## 14. Generate Bitable-Ready Records
```bash ```bash
gitlink-cli feishu +bitable-schema --tables reports,issues,prs,contributors,tasks --format markdown gitlink-cli feishu +bitable-schema --tables reports,issues,prs,contributors,tasks --format markdown
gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json
``` ```
## 12. Preview Bitable Sync ## 15. Preview Bitable Sync
```bash ```bash
gitlink-cli feishu +bitable-sync \ gitlink-cli feishu +bitable-sync \
@ -99,7 +176,7 @@ gitlink-cli feishu +bitable-sync \
--format table --format table
``` ```
## 13. Execute Bitable Sync ## 16. Execute Bitable Sync
```bash ```bash
gitlink-cli feishu +bitable-sync \ gitlink-cli feishu +bitable-sync \
@ -122,7 +199,7 @@ FEISHU_CONTRIBUTOR_TABLE_ID optional
FEISHU_TASK_TABLE_ID optional FEISHU_TASK_TABLE_ID optional
``` ```
## 14. Preview DocX / Wiki Export ## 17. Preview DocX / Wiki Export
```bash ```bash
gitlink-cli feishu +doc-export \ gitlink-cli feishu +doc-export \
@ -131,7 +208,7 @@ gitlink-cli feishu +doc-export \
--format markdown --format markdown
``` ```
## 15. Execute DocX / Wiki Export ## 18. Execute DocX / Wiki Export
```bash ```bash
gitlink-cli feishu +doc-export \ gitlink-cli feishu +doc-export \
@ -141,13 +218,13 @@ gitlink-cli feishu +doc-export \
--format table --format table
``` ```
## 16. Preview Feishu Tasks ## 19. Preview Feishu Tasks
```bash ```bash
gitlink-cli feishu +task-preview --from-workflow-json report.json --format markdown gitlink-cli feishu +task-preview --from-workflow-json report.json --format markdown
``` ```
## 17. Create Feishu Tasks ## 20. Create Feishu Tasks
```bash ```bash
gitlink-cli feishu +task-create --from-workflow-json report.json --send --format table gitlink-cli feishu +task-create --from-workflow-json report.json --send --format table
@ -162,7 +239,15 @@ FEISHU_TASK_PROJECT_ID optional
FEISHU_TASK_SECTION_ID optional FEISHU_TASK_SECTION_ID optional
``` ```
## 18. Run Go Tests ## 21. Run Screenshot Check
```powershell
.\scripts\feishu-gitlink-screenshot-check.ps1
```
The script lists missing screenshots. It does not fabricate images.
## 22. Run Go Tests
```bash ```bash
gofmt -w shortcuts/feishu gofmt -w shortcuts/feishu
@ -172,7 +257,7 @@ go test ./shortcuts
go test ./... go test ./...
``` ```
## 19. Capture Evidence ## 23. Capture Evidence
Capture terminal logs and screenshots listed in `docs/PR_VISUAL_GUIDE.md`. Capture terminal logs and screenshots listed in `docs/PR_VISUAL_GUIDE.md`.

View File

@ -1,6 +1,6 @@
# Feishu Smoke Report # Feishu Smoke Report
Date: 2026-06-26 Date: 2026-06-26 16:29:18 +08:00
## Branch ## Branch
@ -11,23 +11,17 @@ feat/feishu-export-clean
## Commit ## Commit
```text ```text
working tree smoke before final implementation commit; base HEAD before this implementation: bcdab0b 9255518304e1a6b0fba9f9e5eee9bdf4f62d8e04
``` ```
## Test Environment ## Mode
```text ```text
Local OS: Windows / PowerShell preview
Repository: gitlink-cli-feishu-clean
Feishu test enterprise: available only when local environment variables are configured
Real GitLink repo data: public Gitlink/gitlink-cli workflow report generated through gitlink-cli
Previous 3 GitLink PR IDs: not available in current shell; GITLINK_TEST_PR_IDS was not set
``` ```
## Redacted Environment Presence ## Redacted Environment Presence
This section must record presence only, not raw values:
| Variable | Present? | | Variable | Present? |
| --- | --- | | --- | --- |
| `FEISHU_WEBHOOK_URL` | missing | | `FEISHU_WEBHOOK_URL` | missing |
@ -35,104 +29,56 @@ This section must record presence only, not raw values:
| `FEISHU_APP_ID` | missing | | `FEISHU_APP_ID` | missing |
| `FEISHU_APP_SECRET` | missing | | `FEISHU_APP_SECRET` | missing |
| `FEISHU_WIKI_URL` | missing | | `FEISHU_WIKI_URL` | missing |
| `FEISHU_WIKI_NODE_TOKEN` | missing |
| `FEISHU_FOLDER_TOKEN` | missing |
| `FEISHU_BASE_APP_TOKEN` | missing | | `FEISHU_BASE_APP_TOKEN` | missing |
| `FEISHU_REPORT_TABLE_ID` | missing | | `FEISHU_REPORT_TABLE_ID` | missing |
| `FEISHU_ISSUE_TABLE_ID` | missing | | `FEISHU_ISSUE_TABLE_ID` | missing |
| `FEISHU_PR_TABLE_ID` | missing | | `FEISHU_PR_TABLE_ID` | missing |
| `FEISHU_CONTRIBUTOR_TABLE_ID` | missing |
| `FEISHU_TASK_TABLE_ID` | missing |
| `FEISHU_TASK_PROJECT_ID` | missing | | `FEISHU_TASK_PROJECT_ID` | missing |
| `FEISHU_TASK_SECTION_ID` | missing |
| `GITLINK_OWNER` | missing | | `GITLINK_OWNER` | missing |
| `GITLINK_REPO` | missing | | `GITLINK_REPO` | missing |
| `GITLINK_TEST_PR_IDS` | missing | | `GITLINK_TEST_PR_IDS` | missing |
| `GITLINK_TOKEN` | missing |
## Commands Run So Far ## Results
```bash | Command | Result | Details |
go run . feishu --help
go run . feishu +owner-digest --help
go run . feishu +bitable-sync --help
go run . feishu +task-create --help
go run . feishu +owner-digest --from-workflow-json shortcuts/workflow/testdata/repo_report.json --format table
go run . feishu +contributor-digest --from-workflow-json shortcuts/workflow/testdata/repo_report.json --format table
go run . feishu +bitable-records --from-workflow-json shortcuts/workflow/testdata/repo_report.json --tables reports,issues,prs,contributors,tasks --format table
go run . feishu +bitable-sync --from-workflow-json shortcuts/workflow/testdata/repo_report.json --tables reports,tasks --format table
go run . feishu +task-preview --from-workflow-json shortcuts/workflow/testdata/repo_report.json --format table
$report = Join-Path $env:TEMP 'gitlink-feishu-report-20260626.json'
go run . workflow +repo-report --owner Gitlink --repo gitlink-cli --format json | Set-Content -Encoding utf8 $report
go run . feishu +notify --from-workflow-json $report --format table
go run . feishu +owner-digest --from-workflow-json $report --format table
go run . feishu +contributor-digest --from-workflow-json $report --format table
go run . feishu +bitable-records --from-workflow-json $report --tables reports,issues,prs,contributors,tasks --format table
go run . feishu +task-preview --from-workflow-json $report --format table
go run . feishu +bitable-sync --from-workflow-json $report --tables reports,issues,prs,tasks --format table
go run . feishu +doc-export --from-workflow-json $report --format table
gofmt -w shortcuts/feishu
go test ./shortcuts/feishu
go test ./shortcuts/workflow
go test ./shortcuts
go test ./...
```
## Outputs Summary
| Step | Result | Notes |
| --- | --- | --- | | --- | --- | --- |
| `feishu --help` | pass | new owner/contributor digest, bitable sync, task preview/create commands visible | | feishu help | pass | exit=0 |
| owner digest preview | pass | role summary generated | | feishu +owner-digest help | pass | exit=0 |
| contributor digest preview | pass | role summary generated | | feishu +contributor-digest help | pass | exit=0 |
| bitable records preview | pass | reports/issues/prs/contributors/tasks generated | | feishu +bitable-sync help | pass | exit=0 |
| bitable sync preview | pass | preview only, no OpenAPI call | | feishu +task-preview help | pass | exit=0 |
| task preview | pass | task candidates generated | | feishu +task-create help | pass | exit=0 |
| Feishu unit/mock tests | pass | `go test ./shortcuts/feishu` | | workflow +repo-report | pass | report=.local/report.json; owner=Gitlink; repo=gitlink-cli |
| workflow tests | pass | `go test ./shortcuts/workflow` | | notify preview | pass | exit=0 |
| shortcuts tests | pass | `go test ./shortcuts` | | weekly report preview | pass | exit=0 |
| full repository tests | pass | `go test ./...` | | owner digest preview | pass | exit=0 |
| public GitLink repo report | pass | `Gitlink/gitlink-cli` report generated in temp directory | | contributor digest preview | pass | exit=0 |
| public GitLink notify preview | pass | preview only, no webhook call | | bitable records preview | pass | exit=0 |
| public GitLink owner digest | pass | risk/score summary generated | | task preview | pass | exit=0 |
| public GitLink contributor digest | pass | role-oriented summary generated |
| public GitLink Bitable records | pass | reports/issues/prs/contributors/tasks generated |
| public GitLink Bitable sync preview | pass | preview only, table IDs missing by design |
| public GitLink DocX/Wiki preview | pass | preview only, no Open Platform call |
## Real Feishu Webhook Result ## Notes
```text - No .local/feishu-gitlink.env.ps1 file found. Preview smoke can run with public fallback data; real sends are skipped.
not executed: FEISHU_WEBHOOK_URL was not present in the current shell. - GITLINK_OWNER/GITLINK_REPO were missing. Preview smoke used public Gitlink/gitlink-cli as a fallback.
## Terminal Log
Local redacted terminal log: `reports/feishu-real-smoke-terminal.log`
This log file is ignored and should not be committed after real runs.
## Screenshot Checklist
Run:
```powershell
.\scripts\feishu-gitlink-screenshot-check.ps1
``` ```
## DocX / Wiki Result Do not fabricate screenshots. Capture missing images manually after real Feishu runs.
```text
not executed: FEISHU_APP_ID, FEISHU_APP_SECRET, and document target variables were not present in the current shell.
Preview passed with public GitLink report.
```
## Bitable Sync Result
```text
not executed: FEISHU_APP_ID, FEISHU_APP_SECRET, FEISHU_BASE_APP_TOKEN, and table IDs were not present in the current shell.
Preview passed with public GitLink report.
```
## Task Creation Result
```text
not executed: FEISHU_APP_ID and FEISHU_APP_SECRET were not present in the current shell.
Task preview passed with public GitLink report.
```
## Failure Diagnostics
```text
None from local preview, public GitLink read smoke, and unit/mock tests.
Real Open Platform failures must be recorded with endpoint category, HTTP status or Feishu code when available, redacted target type, likely reason, and required permission.
```
## Screenshots Or Terminal Logs
Expected screenshot paths are listed in `docs/PR_VISUAL_GUIDE.md`.
Do not fabricate screenshots.

View File

@ -0,0 +1,88 @@
param(
[ValidateSet("stable", "open-platform", "all")]
[string]$Layer = "stable"
)
$ErrorActionPreference = "Stop"
$RepoRoot = Split-Path -Parent $PSScriptRoot
$LocalEnv = Join-Path $RepoRoot ".local/feishu-gitlink.env.ps1"
function Redact-Value {
param([string]$Value)
if ([string]::IsNullOrWhiteSpace($Value)) { return "" }
if ($Value.Length -le 8) { return "***" }
return "$($Value.Substring(0, 4))...$($Value.Substring($Value.Length - 4))"
}
function Show-Var {
param(
[string]$Name,
[bool]$Sensitive = $true
)
$value = [Environment]::GetEnvironmentVariable($Name)
if ([string]::IsNullOrWhiteSpace($value)) {
Write-Host ("{0}: missing" -f $Name)
return $false
}
if ($Sensitive) {
Write-Host ("{0}: set ({1})" -f $Name, (Redact-Value $value))
} else {
Write-Host ("{0}: set ({1})" -f $Name, $value)
}
return $true
}
function Test-Group {
param(
[string]$Title,
[string[]]$Names,
[string[]]$Optional = @(),
[string[]]$NonSensitive = @()
)
Write-Host ""
Write-Host "[$Title]"
$missingRequired = @()
foreach ($name in $Names) {
$isOptional = $Optional -contains $name
$isSensitive = -not ($NonSensitive -contains $name)
$present = Show-Var -Name $name -Sensitive:$isSensitive
if (-not $present -and -not $isOptional) {
$missingRequired += $name
}
}
return $missingRequired
}
if (Test-Path $LocalEnv) {
. $LocalEnv
Write-Host "Loaded local env: .local/feishu-gitlink.env.ps1"
} else {
Write-Host "No local env file found. Run scripts/feishu-gitlink-setup.ps1 or copy .local/feishu-gitlink.env.example.ps1."
}
$allMissing = @()
if ($Layer -eq "stable" -or $Layer -eq "all") {
$allMissing += Test-Group -Title "Stable webhook" -Names @("FEISHU_WEBHOOK_URL", "FEISHU_WEBHOOK_SECRET") -Optional @("FEISHU_WEBHOOK_SECRET")
}
if ($Layer -eq "open-platform" -or $Layer -eq "all") {
$allMissing += Test-Group -Title "Open Platform app" -Names @("FEISHU_APP_ID", "FEISHU_APP_SECRET")
$allMissing += Test-Group -Title "DocX / Wiki" -Names @("FEISHU_WIKI_URL", "FEISHU_WIKI_NODE_TOKEN", "FEISHU_FOLDER_TOKEN") -Optional @("FEISHU_WIKI_URL", "FEISHU_WIKI_NODE_TOKEN", "FEISHU_FOLDER_TOKEN")
$allMissing += Test-Group -Title "Base / Bitable" -Names @("FEISHU_BASE_APP_TOKEN", "FEISHU_REPORT_TABLE_ID", "FEISHU_ISSUE_TABLE_ID", "FEISHU_PR_TABLE_ID", "FEISHU_CONTRIBUTOR_TABLE_ID", "FEISHU_TASK_TABLE_ID") -Optional @("FEISHU_CONTRIBUTOR_TABLE_ID", "FEISHU_TASK_TABLE_ID")
$allMissing += Test-Group -Title "Feishu Task" -Names @("FEISHU_TASK_PROJECT_ID", "FEISHU_TASK_SECTION_ID") -Optional @("FEISHU_TASK_PROJECT_ID", "FEISHU_TASK_SECTION_ID")
}
if ($Layer -eq "all") {
$allMissing += Test-Group -Title "GitLink test input" -Names @("GITLINK_OWNER", "GITLINK_REPO", "GITLINK_TEST_PR_IDS", "GITLINK_TOKEN") -Optional @("GITLINK_TEST_PR_IDS", "GITLINK_TOKEN") -NonSensitive @("GITLINK_OWNER", "GITLINK_REPO", "GITLINK_TEST_PR_IDS")
}
if ($allMissing.Count -gt 0) {
Write-Host ""
Write-Host "Missing required values for layer '$Layer': $($allMissing -join ', ')"
exit 1
}
Write-Host ""
Write-Host "Layer '$Layer' is ready."
exit 0

View File

@ -0,0 +1,35 @@
$ErrorActionPreference = "Stop"
$RepoRoot = Split-Path -Parent $PSScriptRoot
$Expected = @(
"docs/images/feishu-bot-card.png",
"docs/images/feishu-weekly-report.png",
"docs/images/feishu-owner-digest.png",
"docs/images/feishu-contributor-digest.png",
"docs/images/feishu-bitable-preview.png",
"docs/images/feishu-bitable-sync.png",
"docs/images/feishu-docx-wiki.png",
"docs/images/feishu-task-create.png",
"docs/images/feishu-smoke-terminal.png",
"docs/images/feishu-env-redacted.png"
)
$missing = @()
foreach ($relative in $Expected) {
$path = Join-Path $RepoRoot $relative
if (Test-Path $path) {
Write-Host "Found screenshot: $relative"
} else {
Write-Host "Missing screenshot: $relative"
Write-Host "Open Feishu or terminal and capture this screenshot manually."
$missing += $relative
}
}
if ($missing.Count -gt 0) {
Write-Host ""
Write-Host "Missing screenshots: $($missing.Count)"
exit 1
}
Write-Host "All expected screenshots are present."
exit 0

View File

@ -0,0 +1,199 @@
$ErrorActionPreference = "Stop"
$RepoRoot = Split-Path -Parent $PSScriptRoot
$LocalDir = Join-Path $RepoRoot ".local"
$LocalEnv = Join-Path $LocalDir "feishu-gitlink.env.ps1"
function Redact {
param([string]$Value)
if ([string]::IsNullOrWhiteSpace($Value)) { return "missing" }
if ($Value.Length -le 8) { return "***" }
return "$($Value.Substring(0, 4))...$($Value.Substring($Value.Length - 4))"
}
function Escape-PSString {
param([string]$Value)
if ($null -eq $Value) { return "" }
return $Value.Replace('`', '``').Replace('"', '`"')
}
function SecureString-ToPlainText {
param([System.Security.SecureString]$Secure)
if ($null -eq $Secure) { return "" }
$ptr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Secure)
try {
return [Runtime.InteropServices.Marshal]::PtrToStringBSTR($ptr)
} finally {
if ($ptr -ne [IntPtr]::Zero) {
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ptr)
}
}
}
function Read-OptionalValue {
param(
[string]$Name,
[string]$CurrentValue,
[string]$Hint
)
$currentLabel = if ([string]::IsNullOrWhiteSpace($CurrentValue)) { "empty" } else { Redact $CurrentValue }
Write-Host ""
Write-Host "$Name ($currentLabel)"
if ($Hint) { Write-Host $Hint }
$value = Read-Host "Enter value, or press Enter to keep current"
if ([string]::IsNullOrWhiteSpace($value)) { return $CurrentValue }
return $value.Trim()
}
function Read-SecretValue {
param(
[string]$Name,
[string]$CurrentValue,
[string]$Hint
)
$currentLabel = if ([string]::IsNullOrWhiteSpace($CurrentValue)) { "empty" } else { "set" }
Write-Host ""
Write-Host "$Name ($currentLabel)"
if ($Hint) { Write-Host $Hint }
$secure = Read-Host "Enter secret, or press Enter to keep current" -AsSecureString
$plain = SecureString-ToPlainText $secure
if ([string]::IsNullOrWhiteSpace($plain)) { return $CurrentValue }
return $plain.Trim()
}
function Open-Url {
param(
[string]$Url,
[string]$Reason
)
Write-Host ""
Write-Host "Opening: $Reason"
Write-Host $Url
Start-Process $Url
}
function Pause-User {
param([string]$Message)
[void](Read-Host $Message)
}
function Env {
param([string]$Name)
return [Environment]::GetEnvironmentVariable($Name)
}
function Missing {
param([string[]]$Names)
foreach ($name in $Names) {
if ([string]::IsNullOrWhiteSpace((Env $name))) { return $true }
}
return $false
}
New-Item -ItemType Directory -Force -Path $LocalDir | Out-Null
if (Test-Path $LocalEnv) {
. $LocalEnv
Write-Host "Loaded existing local env: .local/feishu-gitlink.env.ps1"
}
Write-Host "This setup writes values only to .local/feishu-gitlink.env.ps1."
Write-Host "Do not paste secrets into chat or tracked docs."
if (Missing @("FEISHU_WEBHOOK_URL")) {
Open-Url "https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot" "Feishu custom bot guide"
Pause-User "Add a custom bot to your Feishu test group and copy the webhook URL. Press Enter when ready."
$env:FEISHU_WEBHOOK_URL = Read-OptionalValue "FEISHU_WEBHOOK_URL" (Env "FEISHU_WEBHOOK_URL") "Used by +bot-test, +notify, +weekly-report, +owner-digest, and +contributor-digest."
$env:FEISHU_WEBHOOK_SECRET = Read-SecretValue "FEISHU_WEBHOOK_SECRET" (Env "FEISHU_WEBHOOK_SECRET") "Optional signing secret from the custom bot security settings."
}
if (Missing @("FEISHU_APP_ID", "FEISHU_APP_SECRET")) {
Open-Url "https://open.feishu.cn/app" "Feishu developer console"
Pause-User "Create/open a self-built app, enable required scopes, and copy app_id/app_secret. Press Enter when ready."
$env:FEISHU_APP_ID = Read-OptionalValue "FEISHU_APP_ID" (Env "FEISHU_APP_ID") "Used by experimental +doc-export, +bitable-sync, and +task-create."
$env:FEISHU_APP_SECRET = Read-SecretValue "FEISHU_APP_SECRET" (Env "FEISHU_APP_SECRET") "Self-built app secret."
}
if (Missing @("FEISHU_WIKI_URL", "FEISHU_WIKI_NODE_TOKEN", "FEISHU_FOLDER_TOKEN")) {
Open-Url "https://www.feishu.cn/" "Feishu Docs / Wiki"
Pause-User "Open your target Wiki/Doc page or folder and copy the URL/token. Press Enter when ready."
$env:FEISHU_WIKI_URL = Read-OptionalValue "FEISHU_WIKI_URL" (Env "FEISHU_WIKI_URL") "Existing Wiki or Doc URL for +doc-export."
$env:FEISHU_WIKI_NODE_TOKEN = Read-OptionalValue "FEISHU_WIKI_NODE_TOKEN" (Env "FEISHU_WIKI_NODE_TOKEN") "Optional. Usually parsed from FEISHU_WIKI_URL."
$env:FEISHU_FOLDER_TOKEN = Read-OptionalValue "FEISHU_FOLDER_TOKEN" (Env "FEISHU_FOLDER_TOKEN") "Optional. Used when creating a new DocX in a folder."
}
if (Missing @("FEISHU_BASE_APP_TOKEN", "FEISHU_REPORT_TABLE_ID", "FEISHU_ISSUE_TABLE_ID", "FEISHU_PR_TABLE_ID")) {
Open-Url "https://www.feishu.cn/" "Feishu Base / Bitable"
Pause-User "Open/create the Base for reports, issues, prs, contributors, and tasks. Press Enter when table IDs are ready."
Write-Host "Expected tables: reports, issues, prs, contributors, tasks."
Write-Host "Each selected table should contain at least unique_key and repository."
$env:FEISHU_BASE_APP_TOKEN = Read-OptionalValue "FEISHU_BASE_APP_TOKEN" (Env "FEISHU_BASE_APP_TOKEN") "Base app token."
$env:FEISHU_REPORT_TABLE_ID = Read-OptionalValue "FEISHU_REPORT_TABLE_ID" (Env "FEISHU_REPORT_TABLE_ID") "Reports table ID."
$env:FEISHU_ISSUE_TABLE_ID = Read-OptionalValue "FEISHU_ISSUE_TABLE_ID" (Env "FEISHU_ISSUE_TABLE_ID") "Issues table ID."
$env:FEISHU_PR_TABLE_ID = Read-OptionalValue "FEISHU_PR_TABLE_ID" (Env "FEISHU_PR_TABLE_ID") "Pull request table ID."
$env:FEISHU_CONTRIBUTOR_TABLE_ID = Read-OptionalValue "FEISHU_CONTRIBUTOR_TABLE_ID" (Env "FEISHU_CONTRIBUTOR_TABLE_ID") "Optional contributor table ID."
$env:FEISHU_TASK_TABLE_ID = Read-OptionalValue "FEISHU_TASK_TABLE_ID" (Env "FEISHU_TASK_TABLE_ID") "Optional task candidate table ID."
}
if (Missing @("FEISHU_TASK_PROJECT_ID", "FEISHU_TASK_SECTION_ID")) {
Open-Url "https://www.feishu.cn/" "Feishu Tasks"
Pause-User "Open the Feishu Task project/section if needed. Press Enter when IDs are ready."
$env:FEISHU_TASK_PROJECT_ID = Read-OptionalValue "FEISHU_TASK_PROJECT_ID" (Env "FEISHU_TASK_PROJECT_ID") "Optional. Some Task API paths may not require it."
$env:FEISHU_TASK_SECTION_ID = Read-OptionalValue "FEISHU_TASK_SECTION_ID" (Env "FEISHU_TASK_SECTION_ID") "Optional."
}
if (Missing @("GITLINK_OWNER", "GITLINK_REPO")) {
Open-Url "https://www.gitlink.org.cn/" "GitLink"
Pause-User "Open the target GitLink repository and the previous 3 PRs. Press Enter when ready."
$env:GITLINK_OWNER = Read-OptionalValue "GITLINK_OWNER" (Env "GITLINK_OWNER") "Repository owner, for example Gitlink."
$env:GITLINK_REPO = Read-OptionalValue "GITLINK_REPO" (Env "GITLINK_REPO") "Repository name, for example gitlink-cli."
$env:GITLINK_TEST_PR_IDS = Read-OptionalValue "GITLINK_TEST_PR_IDS" (Env "GITLINK_TEST_PR_IDS") "Comma-separated PR IDs for smoke report references."
$env:GITLINK_TOKEN = Read-SecretValue "GITLINK_TOKEN" (Env "GITLINK_TOKEN") "Optional if gitlink-cli is already logged in."
}
if (-not [string]::IsNullOrWhiteSpace($env:GITLINK_OWNER) -and -not [string]::IsNullOrWhiteSpace($env:GITLINK_REPO)) {
Open-Url "https://www.gitlink.org.cn/$env:GITLINK_OWNER/$env:GITLINK_REPO" "Target GitLink repository"
if (-not [string]::IsNullOrWhiteSpace($env:GITLINK_TEST_PR_IDS)) {
Write-Host "GITLINK_TEST_PR_IDS set: $env:GITLINK_TEST_PR_IDS"
Write-Host "Verify the PR page URL pattern manually if needed."
}
}
$vars = @(
"FEISHU_WEBHOOK_URL",
"FEISHU_WEBHOOK_SECRET",
"FEISHU_APP_ID",
"FEISHU_APP_SECRET",
"FEISHU_WIKI_URL",
"FEISHU_WIKI_NODE_TOKEN",
"FEISHU_FOLDER_TOKEN",
"FEISHU_BASE_APP_TOKEN",
"FEISHU_REPORT_TABLE_ID",
"FEISHU_ISSUE_TABLE_ID",
"FEISHU_PR_TABLE_ID",
"FEISHU_CONTRIBUTOR_TABLE_ID",
"FEISHU_TASK_TABLE_ID",
"FEISHU_TASK_PROJECT_ID",
"FEISHU_TASK_SECTION_ID",
"GITLINK_OWNER",
"GITLINK_REPO",
"GITLINK_TEST_PR_IDS",
"GITLINK_TOKEN"
)
$lines = @(
"# Local Feishu/GitLink smoke-test environment.",
"# Generated by scripts/feishu-gitlink-setup.ps1.",
"# Do not commit this file."
)
foreach ($name in $vars) {
$value = [Environment]::GetEnvironmentVariable($name)
$lines += ('$' + ('env:{0}="{1}"' -f $name, (Escape-PSString $value)))
}
$lines | Set-Content -LiteralPath $LocalEnv -Encoding utf8
Write-Host ""
Write-Host "Saved local env: .local/feishu-gitlink.env.ps1"
Write-Host "Redacted summary:"
foreach ($name in $vars) {
$value = [Environment]::GetEnvironmentVariable($name)
Write-Host ("{0}: {1}" -f $name, (Redact $value))
}

View File

@ -0,0 +1,336 @@
param(
[ValidateSet("preview", "stable", "open-platform", "all")]
[string]$Mode = "preview"
)
$ErrorActionPreference = "Stop"
$RepoRoot = Split-Path -Parent $PSScriptRoot
$LocalDir = Join-Path $RepoRoot ".local"
$LocalEnv = Join-Path $LocalDir "feishu-gitlink.env.ps1"
$ReportJSON = Join-Path $LocalDir "report.json"
$TerminalLog = Join-Path $RepoRoot "reports/feishu-real-smoke-terminal.log"
$DateStamp = Get-Date -Format "yyyyMMdd"
$SmokeReport = Join-Path $RepoRoot "reports/FEISHU_SMOKE_$DateStamp.md"
$Results = New-Object System.Collections.Generic.List[object]
$Notes = New-Object System.Collections.Generic.List[string]
function Env {
param([string]$Name)
return [Environment]::GetEnvironmentVariable($Name)
}
function Has-Env {
param([string[]]$Names)
foreach ($name in $Names) {
if ([string]::IsNullOrWhiteSpace((Env $name))) { return $false }
}
return $true
}
function Redact-Value {
param([string]$Value)
if ([string]::IsNullOrWhiteSpace($Value)) { return "" }
if ($Value.Length -le 8) { return "***" }
return "$($Value.Substring(0, 4))...$($Value.Substring($Value.Length - 4))"
}
function Redact-Text {
param([string]$Text)
if ($null -eq $Text) { return "" }
$redacted = $Text
$names = @(
"FEISHU_WEBHOOK_URL",
"FEISHU_WEBHOOK_SECRET",
"FEISHU_APP_ID",
"FEISHU_APP_SECRET",
"FEISHU_WIKI_URL",
"FEISHU_WIKI_NODE_TOKEN",
"FEISHU_FOLDER_TOKEN",
"FEISHU_BASE_APP_TOKEN",
"FEISHU_REPORT_TABLE_ID",
"FEISHU_ISSUE_TABLE_ID",
"FEISHU_PR_TABLE_ID",
"FEISHU_CONTRIBUTOR_TABLE_ID",
"FEISHU_TASK_TABLE_ID",
"FEISHU_TASK_PROJECT_ID",
"FEISHU_TASK_SECTION_ID",
"GITLINK_TOKEN"
)
foreach ($name in $names) {
$value = Env $name
if (-not [string]::IsNullOrWhiteSpace($value)) {
$redacted = [regex]::Replace($redacted, [regex]::Escape($value), (Redact-Value $value))
}
}
$redacted = [regex]::Replace($redacted, 'tenant_access_token"\s*:\s*"[^"]+', 'tenant_access_token":"REDACTED')
return $redacted
}
function Add-Result {
param(
[string]$Name,
[string]$Status,
[string]$Details
)
$Results.Add([pscustomobject]@{
Name = $Name
Status = $Status
Details = (Redact-Text $Details)
}) | Out-Null
}
function Write-Log {
param([string]$Text)
Add-Content -LiteralPath $TerminalLog -Value (Redact-Text $Text)
}
function Invoke-Cmd {
param(
[string]$Name,
[string[]]$CommandArgs,
[bool]$Required = $false
)
$display = $CommandArgs -join " "
Write-Host "RUN: $Name"
Write-Log ""
Write-Log "## $Name"
Write-Log "COMMAND: $display"
$exe = $CommandArgs[0]
$rest = @()
if ($CommandArgs.Count -gt 1) {
$rest = $CommandArgs[1..($CommandArgs.Count - 1)]
}
$output = & $exe @rest 2>&1 | Out-String
$exit = $LASTEXITCODE
Write-Log $output
if ($exit -eq 0) {
Add-Result $Name "pass" "exit=0"
} else {
Add-Result $Name "fail" ("exit={0}; {1}" -f $exit, (($output -split "`r?`n" | Select-Object -First 4) -join " "))
if ($Required) {
throw "$Name failed with exit $exit"
}
}
}
function Invoke-ReportGeneration {
$owner = Env "GITLINK_OWNER"
$repo = Env "GITLINK_REPO"
if ([string]::IsNullOrWhiteSpace($owner) -or [string]::IsNullOrWhiteSpace($repo)) {
$owner = "Gitlink"
$repo = "gitlink-cli"
$Notes.Add("GITLINK_OWNER/GITLINK_REPO were missing. Preview smoke used public Gitlink/gitlink-cli as a fallback.") | Out-Null
}
if (-not [string]::IsNullOrWhiteSpace((Env "GITLINK_TEST_PR_IDS"))) {
$Notes.Add("GITLINK_TEST_PR_IDS was provided, but workflow +repo-report currently does not support explicit PR ID filtering. The smoke test used the real repository report instead.") | Out-Null
}
Write-Host "Generating workflow report for $owner/$repo"
Write-Log ""
Write-Log "## Generate workflow report"
$output = & go run . workflow +repo-report --owner $owner --repo $repo --format json 2>&1 | Out-String
$exit = $LASTEXITCODE
if ($exit -ne 0) {
Write-Log $output
Add-Result "workflow +repo-report" "fail" ("exit={0}; {1}" -f $exit, (($output -split "`r?`n" | Select-Object -First 4) -join " "))
throw "workflow +repo-report failed"
}
$output | Set-Content -LiteralPath $ReportJSON -Encoding utf8
Write-Log "Report written to .local/report.json"
Add-Result "workflow +repo-report" "pass" "report=.local/report.json; owner=$owner; repo=$repo"
}
function Add-Skip {
param([string]$Name, [string]$Reason)
Write-Host "SKIP: $Name - $Reason"
Write-Log ""
Write-Log "## $Name"
Write-Log "SKIP: $Reason"
Add-Result $Name "skip" $Reason
}
function Env-Status {
param([string]$Name)
if ([string]::IsNullOrWhiteSpace((Env $Name))) { return "missing" }
return "present"
}
function Escape-Table {
param([string]$Value)
if ($null -eq $Value) { return "" }
return ($Value -replace '\|', '\|' -replace "`r?`n", " ")
}
function Write-SmokeReport {
$branch = (git branch --show-current | Out-String).Trim()
$commit = (git rev-parse HEAD | Out-String).Trim()
$envNames = @(
"FEISHU_WEBHOOK_URL",
"FEISHU_WEBHOOK_SECRET",
"FEISHU_APP_ID",
"FEISHU_APP_SECRET",
"FEISHU_WIKI_URL",
"FEISHU_WIKI_NODE_TOKEN",
"FEISHU_FOLDER_TOKEN",
"FEISHU_BASE_APP_TOKEN",
"FEISHU_REPORT_TABLE_ID",
"FEISHU_ISSUE_TABLE_ID",
"FEISHU_PR_TABLE_ID",
"FEISHU_CONTRIBUTOR_TABLE_ID",
"FEISHU_TASK_TABLE_ID",
"FEISHU_TASK_PROJECT_ID",
"FEISHU_TASK_SECTION_ID",
"GITLINK_OWNER",
"GITLINK_REPO",
"GITLINK_TEST_PR_IDS",
"GITLINK_TOKEN"
)
$lines = @(
"# Feishu Smoke Report",
"",
"Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz')",
"",
"## Branch",
"",
'```text',
$branch,
'```',
"",
"## Commit",
"",
'```text',
$commit,
'```',
"",
"## Mode",
"",
'```text',
$Mode,
'```',
"",
"## Redacted Environment Presence",
"",
"| Variable | Present? |",
"| --- | --- |"
)
foreach ($name in $envNames) {
$lines += ('| `{0}` | {1} |' -f $name, (Env-Status $name))
}
$lines += @(
"",
"## Results",
"",
"| Command | Result | Details |",
"| --- | --- | --- |"
)
foreach ($result in $Results) {
$lines += "| $(Escape-Table $result.Name) | $(Escape-Table $result.Status) | $(Escape-Table $result.Details) |"
}
$lines += @(
"",
"## Notes",
""
)
if ($Notes.Count -eq 0) {
$lines += "- None."
} else {
foreach ($note in $Notes) {
$lines += "- $(Redact-Text $note)"
}
}
$lines += @(
"",
"## Terminal Log",
"",
'Local redacted terminal log: `reports/feishu-real-smoke-terminal.log`',
"",
"This log file is ignored and should not be committed after real runs.",
"",
"## Screenshot Checklist",
"",
"Run:",
"",
'```powershell',
".\scripts\feishu-gitlink-screenshot-check.ps1",
'```',
"",
"Do not fabricate screenshots. Capture missing images manually after real Feishu runs."
)
$lines | Set-Content -LiteralPath $SmokeReport -Encoding utf8
Write-Host "Smoke report written: $SmokeReport"
}
Push-Location $RepoRoot
try {
New-Item -ItemType Directory -Force -Path $LocalDir | Out-Null
New-Item -ItemType Directory -Force -Path (Join-Path $RepoRoot "reports") | Out-Null
if (Test-Path $LocalEnv) {
. $LocalEnv
Write-Host "Loaded local env: .local/feishu-gitlink.env.ps1"
} else {
$Notes.Add("No .local/feishu-gitlink.env.ps1 file found. Preview smoke can run with public fallback data; real sends are skipped.") | Out-Null
}
"# Feishu/GitLink smoke terminal log $(Get-Date -Format o)" | Set-Content -LiteralPath $TerminalLog -Encoding utf8
$helpCommands = @(
"+owner-digest",
"+contributor-digest",
"+bitable-sync",
"+task-preview",
"+task-create"
)
Invoke-Cmd "feishu help" @("go", "run", ".", "feishu", "--help") $true
foreach ($command in $helpCommands) {
Invoke-Cmd "feishu $command help" @("go", "run", ".", "feishu", $command, "--help") $true
}
Invoke-ReportGeneration
$runPreview = $Mode -in @("preview", "stable", "open-platform", "all")
$runStable = $Mode -in @("stable", "all")
$runOpenPlatform = $Mode -in @("open-platform", "all")
if ($runPreview) {
Invoke-Cmd "notify preview" @("go", "run", ".", "feishu", "+notify", "--from-workflow-json", $ReportJSON, "--format", "table") $true
Invoke-Cmd "weekly report preview" @("go", "run", ".", "feishu", "+weekly-report", "--from-workflow-json", $ReportJSON, "--format", "markdown") $true
Invoke-Cmd "owner digest preview" @("go", "run", ".", "feishu", "+owner-digest", "--from-workflow-json", $ReportJSON, "--format", "table") $true
Invoke-Cmd "contributor digest preview" @("go", "run", ".", "feishu", "+contributor-digest", "--from-workflow-json", $ReportJSON, "--format", "table") $true
Invoke-Cmd "bitable records preview" @("go", "run", ".", "feishu", "+bitable-records", "--from-workflow-json", $ReportJSON, "--tables", "reports,issues,prs,contributors,tasks", "--format", "table") $true
Invoke-Cmd "task preview" @("go", "run", ".", "feishu", "+task-preview", "--from-workflow-json", $ReportJSON, "--format", "table") $true
}
if ($runStable) {
if (Has-Env @("FEISHU_WEBHOOK_URL")) {
Invoke-Cmd "bot-test send" @("go", "run", ".", "feishu", "+bot-test", "--send", "--format", "table") $false
Invoke-Cmd "notify send" @("go", "run", ".", "feishu", "+notify", "--from-workflow-json", $ReportJSON, "--send", "--format", "table") $false
Invoke-Cmd "weekly report send" @("go", "run", ".", "feishu", "+weekly-report", "--from-workflow-json", $ReportJSON, "--send", "--format", "table") $false
Invoke-Cmd "owner digest send" @("go", "run", ".", "feishu", "+owner-digest", "--from-workflow-json", $ReportJSON, "--send", "--format", "table") $false
Invoke-Cmd "contributor digest send" @("go", "run", ".", "feishu", "+contributor-digest", "--from-workflow-json", $ReportJSON, "--send", "--format", "table") $false
} else {
Add-Skip "stable webhook send" "FEISHU_WEBHOOK_URL missing"
}
}
if ($runOpenPlatform) {
if (Has-Env @("FEISHU_APP_ID", "FEISHU_APP_SECRET") -and (Has-Env @("FEISHU_WIKI_URL") -or Has-Env @("FEISHU_WIKI_NODE_TOKEN") -or Has-Env @("FEISHU_FOLDER_TOKEN"))) {
Invoke-Cmd "doc-export send" @("go", "run", ".", "feishu", "+doc-export", "--from-workflow-json", $ReportJSON, "--send", "--format", "table") $false
} else {
Add-Skip "doc-export send" "missing FEISHU_APP_ID/FEISHU_APP_SECRET or DocX/Wiki target"
}
if (Has-Env @("FEISHU_APP_ID", "FEISHU_APP_SECRET", "FEISHU_BASE_APP_TOKEN", "FEISHU_REPORT_TABLE_ID", "FEISHU_ISSUE_TABLE_ID", "FEISHU_PR_TABLE_ID")) {
Invoke-Cmd "bitable-sync send" @("go", "run", ".", "feishu", "+bitable-sync", "--from-workflow-json", $ReportJSON, "--tables", "reports,issues,prs,contributors,tasks", "--send", "--format", "table") $false
} else {
Add-Skip "bitable-sync send" "missing app/base/table variables"
}
if (Has-Env @("FEISHU_APP_ID", "FEISHU_APP_SECRET")) {
Invoke-Cmd "task-create send" @("go", "run", ".", "feishu", "+task-create", "--from-workflow-json", $ReportJSON, "--send", "--format", "table") $false
} else {
Add-Skip "task-create send" "missing FEISHU_APP_ID/FEISHU_APP_SECRET"
}
}
Write-SmokeReport
} finally {
Pop-Location
}