chore: harden feishu export delivery
This commit is contained in:
parent
d8cb4aa9d2
commit
1af54e015a
|
|
@ -0,0 +1,68 @@
|
|||
# Feishu Bitable Dry-Run Schema
|
||||
|
||||
`gitlink-cli feishu` currently generates Bitable schema and records locally.
|
||||
|
||||
It does not call Feishu Bitable OpenAPI.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bitable-schema --format markdown
|
||||
gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json
|
||||
```
|
||||
|
||||
## Tables
|
||||
|
||||
Default tables:
|
||||
|
||||
```text
|
||||
issues
|
||||
prs
|
||||
contributors
|
||||
reports
|
||||
```
|
||||
|
||||
## Record Semantics
|
||||
|
||||
Records are summary records derived from `workflow +repo-report` JSON.
|
||||
|
||||
They are not one row per GitLink issue or one row per GitLink pull request.
|
||||
|
||||
Current behavior:
|
||||
|
||||
```text
|
||||
reports: one summary row per repo report
|
||||
issues: summary buckets by issue type and priority
|
||||
prs: summary buckets by change type and risk
|
||||
contributors: reserved schema; records are empty unless workflow JSON later includes contributor details
|
||||
```
|
||||
|
||||
## Real Write Boundary
|
||||
|
||||
Not implemented:
|
||||
|
||||
```text
|
||||
Bitable OpenAPI create
|
||||
Bitable OpenAPI batch create
|
||||
Bitable update
|
||||
Bitable upsert
|
||||
Base creation
|
||||
table creation
|
||||
view creation
|
||||
field creation
|
||||
person/open_id mapping
|
||||
```
|
||||
|
||||
Real Bitable writes require a separate design for:
|
||||
|
||||
```text
|
||||
app authentication
|
||||
table IDs
|
||||
record unique keys
|
||||
search-before-update
|
||||
pagination
|
||||
partial failure handling
|
||||
rate limits
|
||||
permission diagnostics
|
||||
```
|
||||
|
||||
|
|
@ -1,27 +1,39 @@
|
|||
# Feishu Integration
|
||||
|
||||
`gitlink-cli feishu` exports local GitLink workflow JSON to Feishu collaboration surfaces.
|
||||
`gitlink-cli feishu` exports local GitLink workflow JSON to Feishu.
|
||||
|
||||
The commands are intentionally one-way:
|
||||
The stable command path is intentionally narrow:
|
||||
|
||||
```text
|
||||
workflow JSON -> local preview
|
||||
workflow JSON -> Feishu bot card
|
||||
workflow JSON -> Feishu DocX / Wiki report
|
||||
workflow JSON -> Bitable-ready dry-run records
|
||||
workflow JSON -> Feishu custom bot card
|
||||
workflow JSON -> weekly report
|
||||
workflow JSON -> Bitable schema / records dry-run
|
||||
```
|
||||
|
||||
## Stable Commands
|
||||
|
||||
```text
|
||||
gitlink-cli feishu +bot-test
|
||||
gitlink-cli feishu +notify
|
||||
gitlink-cli feishu +weekly-report
|
||||
gitlink-cli feishu +bitable-schema
|
||||
gitlink-cli feishu +bitable-records
|
||||
```
|
||||
|
||||
`feishu +doc-export` exists as an experimental command. It uses Feishu self-built app OpenAPI and is not part of the clean first-path workflow.
|
||||
|
||||
## Safety Model
|
||||
|
||||
Default behavior is local preview.
|
||||
- Default behavior is local preview.
|
||||
- Real Feishu bot delivery requires `--send`.
|
||||
- `--send` and `--dry-run` cannot be used together.
|
||||
- Webhook URLs are redacted in command output.
|
||||
- Secrets and tokens are never intentionally printed.
|
||||
- The stable commands do not write to GitLink resources.
|
||||
- Bitable commands are dry-run only and do not call Bitable OpenAPI.
|
||||
|
||||
Network operations require `--send`.
|
||||
|
||||
`--send` and `--dry-run` cannot be used together.
|
||||
|
||||
The implementation does not write to GitLink resources, does not close issues, does not comment on PRs, and does not merge code.
|
||||
|
||||
## Custom Bot
|
||||
## Custom Bot Setup
|
||||
|
||||
Use a Feishu custom group bot for notification cards.
|
||||
|
||||
|
|
@ -32,26 +44,41 @@ $env:FEISHU_WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/..."
|
|||
$env:FEISHU_WEBHOOK_SECRET="optional signing secret"
|
||||
```
|
||||
|
||||
Preview:
|
||||
Preview a test card:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bot-test --format json
|
||||
```
|
||||
|
||||
Send:
|
||||
Send a test card:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bot-test --send --format table
|
||||
```
|
||||
|
||||
Send a workflow report card:
|
||||
## Workflow Report Card
|
||||
|
||||
Generate workflow JSON:
|
||||
|
||||
```bash
|
||||
gitlink-cli workflow +repo-report --owner Gitlink --repo gitlink-cli --format json > report.json
|
||||
```
|
||||
|
||||
On Windows PowerShell, redirected files may be written with UTF-16 encoding. `feishu` workflow JSON readers accept UTF-8 and UTF-16 BOM files so the redirected output above can be consumed directly.
|
||||
|
||||
Preview a card:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +notify --from-workflow-json report.json --format json
|
||||
```
|
||||
|
||||
Send a card:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +notify --from-workflow-json report.json --send --format table
|
||||
```
|
||||
|
||||
Send a card with a DocX or Wiki link:
|
||||
Send a card with an existing Feishu document or Wiki link:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +notify \
|
||||
|
|
@ -61,9 +88,39 @@ gitlink-cli feishu +notify \
|
|||
--format table
|
||||
```
|
||||
|
||||
## DocX / Wiki Export
|
||||
## Weekly Report
|
||||
|
||||
Use a Feishu self-built app for document export.
|
||||
Render markdown:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +weekly-report --from-workflow-json report.json --format markdown
|
||||
```
|
||||
|
||||
Send a weekly summary card:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +weekly-report --from-workflow-json report.json --send --format table
|
||||
```
|
||||
|
||||
## Bitable Dry Run
|
||||
|
||||
Generate recommended table schemas:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bitable-schema --format markdown
|
||||
```
|
||||
|
||||
Generate Bitable-ready records:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json
|
||||
```
|
||||
|
||||
These records are summary records derived from workflow repo-report JSON. They are not a per-issue or per-PR synchronization.
|
||||
|
||||
## Experimental DocX / Wiki Export
|
||||
|
||||
`feishu +doc-export` is experimental because it uses Feishu self-built app credentials and writes to DocX / Wiki through OpenAPI.
|
||||
|
||||
Environment:
|
||||
|
||||
|
|
@ -81,7 +138,7 @@ gitlink-cli feishu +doc-export \
|
|||
--format markdown
|
||||
```
|
||||
|
||||
Append report blocks to a Wiki-backed DocX:
|
||||
Write to DocX / Wiki:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +doc-export \
|
||||
|
|
@ -91,40 +148,10 @@ gitlink-cli feishu +doc-export \
|
|||
--format table
|
||||
```
|
||||
|
||||
Create a new DocX in a folder:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +doc-export \
|
||||
--from-workflow-json report.json \
|
||||
--folder-token "<folder_token>" \
|
||||
--title "GitLink workflow report" \
|
||||
--send \
|
||||
--format table
|
||||
```
|
||||
|
||||
Required Feishu setup:
|
||||
|
||||
```text
|
||||
1. The self-built app must have DocX / Drive application scopes.
|
||||
2. The app permission version must be published and approved.
|
||||
3. The target Wiki / DocX / folder must grant the app write permission.
|
||||
1. The self-built app must have approved DocX / Drive scopes.
|
||||
2. The target Wiki / DocX / folder must grant the app write permission.
|
||||
3. If Feishu returns 1770032: forBidden, credentials are valid but the app cannot write the target document.
|
||||
```
|
||||
|
||||
If Feishu returns `1770032: forBidden`, the token is valid but the app cannot write to the target document. Grant the app access to that Wiki/DocX page or use a folder where the app can create documents.
|
||||
|
||||
## Bitable Dry Run
|
||||
|
||||
Generate recommended table schemas:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bitable-schema --format markdown
|
||||
```
|
||||
|
||||
Generate Bitable-ready records:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json
|
||||
```
|
||||
|
||||
These commands do not call Bitable OpenAPI and do not create, update, or upsert records.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
# Feishu Security Notes
|
||||
|
||||
## Default Behavior
|
||||
|
||||
All Feishu shortcut commands default to local preview.
|
||||
|
||||
Real network writes require `--send`.
|
||||
|
||||
`--send` and `--dry-run` cannot be used together.
|
||||
|
||||
## Secrets
|
||||
|
||||
Supported environment variables:
|
||||
|
||||
```text
|
||||
FEISHU_WEBHOOK_URL
|
||||
FEISHU_WEBHOOK_SECRET
|
||||
FEISHU_APP_ID experimental doc-export only
|
||||
FEISHU_APP_SECRET experimental doc-export only
|
||||
```
|
||||
|
||||
Do not commit real webhook URLs, app secrets, access tokens, Base app tokens, table IDs, or document tokens.
|
||||
|
||||
Command output redacts webhook URLs. Tests use fake webhook IDs.
|
||||
|
||||
## Stable Surface
|
||||
|
||||
The stable surface uses Feishu custom bot webhooks:
|
||||
|
||||
```text
|
||||
feishu +bot-test
|
||||
feishu +notify
|
||||
feishu +weekly-report
|
||||
```
|
||||
|
||||
These commands can send Feishu cards, but they do not read or write Feishu documents, tables, users, or groups.
|
||||
|
||||
## Dry-Run Surface
|
||||
|
||||
The Bitable commands are local only:
|
||||
|
||||
```text
|
||||
feishu +bitable-schema
|
||||
feishu +bitable-records
|
||||
```
|
||||
|
||||
They do not call Feishu OpenAPI and cannot create, update, or upsert Bitable records.
|
||||
|
||||
## Experimental Surface
|
||||
|
||||
`feishu +doc-export` is experimental. It uses:
|
||||
|
||||
```text
|
||||
app_id
|
||||
app_secret
|
||||
tenant_access_token
|
||||
Wiki OpenAPI
|
||||
DocX OpenAPI
|
||||
```
|
||||
|
||||
It should not be treated as part of the stable clean export path. If used, grant the self-built app only the minimum required document permissions.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
```text
|
||||
BotBuilder integration
|
||||
Feishu Robot Assistant workflows
|
||||
automatic Feishu permission changes
|
||||
GitLink remote writes
|
||||
GitLink comments
|
||||
Issue closure
|
||||
merge actions
|
||||
real Bitable writes
|
||||
```
|
||||
|
||||
|
|
@ -1,24 +1,48 @@
|
|||
# Feishu Export Examples
|
||||
|
||||
## 1. Generate Workflow JSON
|
||||
## Stable Workflow
|
||||
|
||||
### 1. Generate Workflow JSON
|
||||
|
||||
```bash
|
||||
gitlink-cli workflow +repo-report --owner Gitlink --repo gitlink-cli --format json > report.json
|
||||
```
|
||||
|
||||
## 2. Preview Notification Card
|
||||
### 2. Preview Notification Card
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +notify --from-workflow-json report.json --format json
|
||||
```
|
||||
|
||||
## 3. Send Notification Card
|
||||
### 3. Send Notification Card
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +notify --from-workflow-json report.json --send --format table
|
||||
```
|
||||
|
||||
## 4. Preview Wiki Export
|
||||
### 4. Render Weekly Report
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +weekly-report --from-workflow-json report.json --format markdown
|
||||
```
|
||||
|
||||
### 5. Generate Bitable Schema
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bitable-schema --format markdown
|
||||
```
|
||||
|
||||
### 6. Generate Bitable Records
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json
|
||||
```
|
||||
|
||||
## Experimental DocX / Wiki Export
|
||||
|
||||
`+doc-export` is available for Feishu self-built app experiments. It is not part of the stable clean export path.
|
||||
|
||||
Preview:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +doc-export \
|
||||
|
|
@ -27,7 +51,7 @@ gitlink-cli feishu +doc-export \
|
|||
--format markdown
|
||||
```
|
||||
|
||||
## 5. Export To Wiki
|
||||
Write:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +doc-export \
|
||||
|
|
@ -37,9 +61,3 @@ gitlink-cli feishu +doc-export \
|
|||
--format table
|
||||
```
|
||||
|
||||
## 6. Generate Bitable Records
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -266,7 +266,8 @@ But it is incomplete for a "Feishu collaboration export" feature because it does
|
|||
Required design adjustment:
|
||||
|
||||
```text
|
||||
Add doc-export with DocX/Wiki support as the first Open Platform custom-app integration.
|
||||
Keep real Bitable writes after doc-export.
|
||||
Keep custom bot as the low-friction smoke test path.
|
||||
Keep custom bot as the low-friction stable smoke test path.
|
||||
Keep Bitable as dry-run in the stable path.
|
||||
Treat doc-export with DocX/Wiki support as experimental because it uses self-built app OpenAPI and document write permissions.
|
||||
Keep real Bitable writes out of scope.
|
||||
```
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ type BitableRecord struct {
|
|||
|
||||
Official Feishu Open Platform docs show that cloud document integration belongs to the self-built app flow, not the custom bot flow.
|
||||
|
||||
Add this after the custom bot MVP:
|
||||
Experimental command:
|
||||
|
||||
```text
|
||||
feishu +doc-export
|
||||
|
|
@ -310,13 +310,19 @@ Implementation notes:
|
|||
- Mock all HTTP tests.
|
||||
- Do not implement document sharing or permission changes in the first doc export pass.
|
||||
|
||||
Recommended product flow:
|
||||
Stable product flow:
|
||||
|
||||
```text
|
||||
workflow +repo-report -> feishu +weekly-report -> feishu +notify --doc-url -> feishu +bitable-records
|
||||
```
|
||||
|
||||
Experimental product flow:
|
||||
|
||||
```text
|
||||
workflow +repo-report -> feishu +doc-export --wiki-url -> feishu +notify --doc-url -> feishu +bitable-records
|
||||
```
|
||||
|
||||
This should land before any real Bitable write because DocX export has clearer value and simpler consistency semantics than Bitable upsert.
|
||||
DocX export should remain clearly marked as experimental until tenant permissions, scopes, and document-write behavior are stable.
|
||||
|
||||
## Tests To Add
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ gitlink-cli feishu +bitable-records
|
|||
- Added project activity card generation from workflow JSON.
|
||||
- Added weekly report rendering from workflow JSON.
|
||||
- Added `--doc-url` support for notification cards.
|
||||
- Added `feishu +doc-export` for Feishu DocX / Wiki export.
|
||||
- Added experimental `feishu +doc-export` for Feishu DocX / Wiki export.
|
||||
- Added self-built app tenant token acquisition.
|
||||
- Added Wiki node resolution.
|
||||
- Added DocX block creation client.
|
||||
|
|
@ -109,6 +109,20 @@ Design now treats Feishu Knowledge Base / Wiki pages as a project showcase and r
|
|||
workflow JSON -> DocX/Wiki report -> bot card with doc URL -> Bitable dry-run records
|
||||
```
|
||||
|
||||
After scope review, DocX / Wiki export is explicitly experimental and not part of the stable clean workflow.
|
||||
|
||||
Stable path:
|
||||
|
||||
```text
|
||||
workflow JSON -> bot card / weekly report / Bitable dry-run records
|
||||
```
|
||||
|
||||
Experimental path:
|
||||
|
||||
```text
|
||||
workflow JSON -> DocX/Wiki export through self-built app OpenAPI
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
Commands run:
|
||||
|
|
@ -147,9 +161,13 @@ document permission modification
|
|||
DocX content write
|
||||
```
|
||||
|
||||
Note: experimental `doc-export` can attempt DocX block writes when explicitly invoked with `--send`, but it remains outside the stable clean export path.
|
||||
|
||||
## Next Engineering Step
|
||||
|
||||
Complete the Feishu document permission setup and rerun:
|
||||
For stable delivery, continue validating custom bot delivery, weekly reports, and Bitable dry-run output.
|
||||
|
||||
For experimental DocX/Wiki export, complete the Feishu document permission setup and rerun:
|
||||
|
||||
```text
|
||||
gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url <wiki_url> --send --format table
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
# Feishu Test Enterprise Smoke Report
|
||||
|
||||
Date: 2026-06-15
|
||||
|
||||
Branch:
|
||||
|
||||
```text
|
||||
feat/feishu-export-clean
|
||||
```
|
||||
|
||||
## Scope
|
||||
|
||||
This smoke run validates the stable Feishu export path in a real Feishu test enterprise.
|
||||
|
||||
Stable path:
|
||||
|
||||
```text
|
||||
bot-test
|
||||
notify
|
||||
weekly-report
|
||||
bitable-schema
|
||||
bitable-records
|
||||
```
|
||||
|
||||
Experimental path:
|
||||
|
||||
```text
|
||||
doc-export
|
||||
```
|
||||
|
||||
Secrets, full webhook URLs, app secrets, and real Wiki tokens are not recorded in this report.
|
||||
|
||||
## Local Verification
|
||||
|
||||
Commands:
|
||||
|
||||
```bash
|
||||
gofmt -w shortcuts/feishu
|
||||
git diff --check
|
||||
go test ./shortcuts/feishu ./shortcuts ./...
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```text
|
||||
passed
|
||||
```
|
||||
|
||||
## Windows JSON Encoding Check
|
||||
|
||||
The smoke run generated workflow JSON through Windows PowerShell redirection.
|
||||
|
||||
Initial result before fix:
|
||||
|
||||
```text
|
||||
parse workflow JSON: invalid character 'ÿ' looking for beginning of value
|
||||
```
|
||||
|
||||
Fix:
|
||||
|
||||
```text
|
||||
workflow JSON reader now accepts UTF-8 BOM, UTF-16LE BOM, and UTF-16BE BOM.
|
||||
```
|
||||
|
||||
Post-fix result:
|
||||
|
||||
```text
|
||||
workflow JSON generated by PowerShell redirection is accepted.
|
||||
```
|
||||
|
||||
## Real Feishu Bot Smoke
|
||||
|
||||
| Step | Result | Notes |
|
||||
| --- | --- | --- |
|
||||
| bot-test preview | pass | local preview |
|
||||
| bot-test send | pass | HTTP 200 / Feishu code 0 |
|
||||
| notify preview | pass | local preview |
|
||||
| notify send | pass | HTTP 200 / Feishu code 0 |
|
||||
| notify send with doc URL | pass | HTTP 200 / Feishu code 0 |
|
||||
| weekly-report markdown | pass | markdown rendered |
|
||||
| weekly-report send | pass | HTTP 200 / Feishu code 0 |
|
||||
|
||||
## Bitable Dry-Run Smoke
|
||||
|
||||
| Step | Result | Notes |
|
||||
| --- | --- | --- |
|
||||
| bitable-schema json | pass | JSON schema generated |
|
||||
| bitable-schema markdown | pass | Markdown schema generated |
|
||||
| bitable-records json | pass | dry-run records generated |
|
||||
| bitable-records table | pass | reports/issues/prs records summarized; contributors reserved |
|
||||
|
||||
## Experimental Doc Export Smoke
|
||||
|
||||
| Step | Result | Notes |
|
||||
| --- | --- | --- |
|
||||
| doc-export preview | pass | target resolved as Wiki append preview |
|
||||
| doc-export send | expected failure | Feishu returned HTTP 403 / code 1770032 / forBidden |
|
||||
|
||||
Interpretation:
|
||||
|
||||
```text
|
||||
The self-built app credentials can get tenant_access_token and resolve the Wiki node, but the app cannot write blocks to the target Wiki-backed DocX page yet.
|
||||
```
|
||||
|
||||
Required Feishu-side action:
|
||||
|
||||
```text
|
||||
Grant the self-built app approved DocX/Drive scopes and write access to the target Wiki/DocX page or use a writable folder token.
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
Stable Feishu export path is working in the test enterprise.
|
||||
|
||||
`doc-export` remains experimental and permission-blocked for real writes.
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ func newWeeklyReportShortcut() *common.Shortcut {
|
|||
func newDocExportShortcut() *common.Shortcut {
|
||||
return &common.Shortcut{
|
||||
Name: "doc-export",
|
||||
Description: "Preview or export a workflow report to Feishu DocX or Wiki",
|
||||
Description: "Experimental: preview or export a workflow report to Feishu DocX or Wiki",
|
||||
Flags: []common.Flag{
|
||||
{Name: "from-workflow-json", Usage: "Read workflow repo report JSON from a file", Required: true},
|
||||
{Name: "title", Usage: "Document title"},
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -120,6 +121,31 @@ func TestReadWorkflowReportSupportsInputFixture(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestReadWorkflowReportSupportsPowerShellUTF16Redirect(t *testing.T) {
|
||||
raw, err := os.ReadFile(filepath.Join("..", "workflow", "testdata", "repo_report.json"))
|
||||
if err != nil {
|
||||
t.Fatalf("read fixture: %v", err)
|
||||
}
|
||||
utf16Data := []byte{0xFF, 0xFE}
|
||||
for _, r := range string(raw) {
|
||||
if r > 0xFFFF {
|
||||
t.Fatalf("fixture contains non-BMP rune %q", r)
|
||||
}
|
||||
utf16Data = append(utf16Data, byte(r), byte(r>>8))
|
||||
}
|
||||
path := filepath.Join(t.TempDir(), "report.json")
|
||||
if err := os.WriteFile(path, utf16Data, 0600); err != nil {
|
||||
t.Fatalf("write UTF-16 fixture: %v", err)
|
||||
}
|
||||
report, err := readWorkflowReport(path, "en")
|
||||
if err != nil {
|
||||
t.Fatalf("readWorkflowReport returned error: %v", err)
|
||||
}
|
||||
if report.Repository != "Gitlink/gitlink-cli" {
|
||||
t.Fatalf("Repository = %q", report.Repository)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitableSchemaAndRecords(t *testing.T) {
|
||||
report, err := readWorkflowReport(filepath.Join("..", "workflow", "testdata", "repo_report.json"), "en")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf16"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/workflow"
|
||||
)
|
||||
|
|
@ -14,6 +15,10 @@ func readWorkflowReport(path string, lang string) (workflow.RepoReportResult, er
|
|||
if err != nil {
|
||||
return workflow.RepoReportResult{}, fmt.Errorf("read workflow JSON: %w", err)
|
||||
}
|
||||
data, err = normalizeJSONBytes(data)
|
||||
if err != nil {
|
||||
return workflow.RepoReportResult{}, err
|
||||
}
|
||||
data, err = unwrapWorkflowJSON(data)
|
||||
if err != nil {
|
||||
return workflow.RepoReportResult{}, err
|
||||
|
|
@ -32,6 +37,34 @@ func readWorkflowReport(path string, lang string) (workflow.RepoReportResult, er
|
|||
return workflow.RepoReportResult{}, fmt.Errorf("parse workflow JSON: expected workflow RepoReportResult or RepoReportInput")
|
||||
}
|
||||
|
||||
func normalizeJSONBytes(data []byte) ([]byte, error) {
|
||||
if len(data) >= 3 && data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF {
|
||||
return data[3:], nil
|
||||
}
|
||||
if len(data) >= 2 && data[0] == 0xFF && data[1] == 0xFE {
|
||||
return decodeUTF16(data[2:], true)
|
||||
}
|
||||
if len(data) >= 2 && data[0] == 0xFE && data[1] == 0xFF {
|
||||
return decodeUTF16(data[2:], false)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func decodeUTF16(data []byte, littleEndian bool) ([]byte, error) {
|
||||
if len(data)%2 != 0 {
|
||||
return nil, fmt.Errorf("parse workflow JSON: invalid UTF-16 byte length")
|
||||
}
|
||||
words := make([]uint16, 0, len(data)/2)
|
||||
for i := 0; i < len(data); i += 2 {
|
||||
if littleEndian {
|
||||
words = append(words, uint16(data[i])|uint16(data[i+1])<<8)
|
||||
} else {
|
||||
words = append(words, uint16(data[i])<<8|uint16(data[i+1]))
|
||||
}
|
||||
}
|
||||
return []byte(string(utf16.Decode(words))), nil
|
||||
}
|
||||
|
||||
func unwrapWorkflowJSON(data []byte) ([]byte, error) {
|
||||
var raw map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
name: gitlink-feishu
|
||||
version: 1.0.0
|
||||
description: "Export GitLink workflow JSON to Feishu bot cards, DocX/Wiki reports, and Bitable-ready dry-run records."
|
||||
description: "Export GitLink workflow JSON to Feishu custom bot cards, weekly reports, and Bitable-ready dry-run records."
|
||||
metadata:
|
||||
requires:
|
||||
bins: ["gitlink-cli"]
|
||||
|
|
@ -10,47 +10,58 @@ metadata:
|
|||
|
||||
# gitlink-feishu
|
||||
|
||||
Use this skill when a user needs to send or export GitLink workflow analysis to Feishu.
|
||||
Use this skill when a user needs to export GitLink workflow analysis into Feishu.
|
||||
|
||||
## Rules
|
||||
## Purpose
|
||||
|
||||
- Prefer local preview first.
|
||||
- Use `--send` only when the user explicitly wants a Feishu network write.
|
||||
- Never use BotBuilder or Robot Assistant workflows.
|
||||
- Do not write to GitLink resources.
|
||||
- Do not print webhook URLs, app secrets, or access tokens.
|
||||
- Use `+bitable-records` for dry-run output only; do not claim that Bitable has been written.
|
||||
Stable path:
|
||||
|
||||
## Workflow
|
||||
```text
|
||||
workflow JSON -> Feishu bot card / weekly report / Bitable dry-run records
|
||||
```
|
||||
|
||||
Generate workflow JSON:
|
||||
Experimental path:
|
||||
|
||||
```text
|
||||
workflow JSON -> Feishu DocX / Wiki export
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
Workflow JSON should usually come from:
|
||||
|
||||
```bash
|
||||
gitlink-cli workflow +repo-report --owner <owner> --repo <repo> --format json > report.json
|
||||
```
|
||||
|
||||
Preview a Feishu card:
|
||||
## Safety Rules
|
||||
|
||||
- Preview first.
|
||||
- Use `--send` only when the user explicitly wants a Feishu network write.
|
||||
- Never use BotBuilder or Robot Assistant workflows.
|
||||
- Do not write to GitLink resources.
|
||||
- Do not print webhook URLs, app secrets, access tokens, or table tokens.
|
||||
- Treat `+bitable-schema` and `+bitable-records` as local dry-run commands only.
|
||||
- Treat `+doc-export` as experimental because it uses self-built app OpenAPI and document write permissions.
|
||||
|
||||
## Preview Flow
|
||||
|
||||
Preview a card:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +notify --from-workflow-json report.json --format json
|
||||
```
|
||||
|
||||
Send a Feishu card:
|
||||
Render a weekly report:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +notify --from-workflow-json report.json --send --format table
|
||||
gitlink-cli feishu +weekly-report --from-workflow-json report.json --format markdown
|
||||
```
|
||||
|
||||
Preview a document export:
|
||||
Generate Bitable schemas:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url "<wiki_url>" --format markdown
|
||||
```
|
||||
|
||||
Export to DocX or Wiki:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url "<wiki_url>" --send --format table
|
||||
gitlink-cli feishu +bitable-schema --format markdown
|
||||
```
|
||||
|
||||
Generate Bitable-ready records:
|
||||
|
|
@ -59,7 +70,7 @@ Generate Bitable-ready records:
|
|||
gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json
|
||||
```
|
||||
|
||||
## Feishu Setup
|
||||
## Send Flow
|
||||
|
||||
Custom bot commands need:
|
||||
|
||||
|
|
@ -68,12 +79,46 @@ FEISHU_WEBHOOK_URL
|
|||
FEISHU_WEBHOOK_SECRET optional
|
||||
```
|
||||
|
||||
DocX/Wiki export needs:
|
||||
Send a card:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +notify --from-workflow-json report.json --send --format table
|
||||
```
|
||||
|
||||
Send a weekly report card:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +weekly-report --from-workflow-json report.json --send --format table
|
||||
```
|
||||
|
||||
## Experimental Doc Export
|
||||
|
||||
DocX / Wiki export needs:
|
||||
|
||||
```text
|
||||
FEISHU_APP_ID
|
||||
FEISHU_APP_SECRET
|
||||
```
|
||||
|
||||
The self-built app must also have permission to write the target DocX/Wiki page or folder.
|
||||
Preview only:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url "<wiki_url>" --format markdown
|
||||
```
|
||||
|
||||
Write to Feishu:
|
||||
|
||||
```bash
|
||||
gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url "<wiki_url>" --send --format table
|
||||
```
|
||||
|
||||
If Feishu returns `1770032: forBidden`, the app token is valid but the app cannot write to the target DocX/Wiki page or folder.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- No GitLink remote writes.
|
||||
- No GitLink comments, issue closure, merge, or webhook creation.
|
||||
- No Bitable real writes in the stable path.
|
||||
- No BotBuilder integration.
|
||||
- No automatic Feishu permission changes.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue