Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
187 commits
Select commit Hold shift + click to select a range
c25038a
feat: extend feishu track sync
TalexDreamSoul Apr 7, 2026
9f83ba8
feat: refine workspace dashboard
TalexDreamSoul Apr 7, 2026
0a88787
feat: wire casdoor runtime integrations
TalexDreamSoul Apr 7, 2026
941f712
feat: wire project panel shortcuts
TalexDreamSoul Apr 7, 2026
2e62808
feat(team-dashboard): refine project cards and dialogs
TalexDreamSoul Apr 7, 2026
0f63490
feat(user-settings): enhance workspace management flows
TalexDreamSoul Apr 7, 2026
dddb38a
refactor(workspace-members): rename active flag to enabled
TalexDreamSoul Apr 7, 2026
6cea006
chore(lockfile): align sentry nuxt catalog reference
TalexDreamSoul Apr 7, 2026
dd7a1fa
Merge remote-tracking branch 'origin/main' into dev
TalexDreamSoul Apr 7, 2026
9ee9c5b
test(feishu-sync): harden lint-safe assertions
TalexDreamSoul Apr 7, 2026
689c233
chore(lint): fix workflow and feishu sync formatting
TalexDreamSoul Apr 7, 2026
1874fe9
fix(jenkins): use external docker network for deploy
TalexDreamSoul Apr 7, 2026
86df670
docs(jenkins): document external docker network config
TalexDreamSoul Apr 7, 2026
e58b62d
fix(db): add billing_plans is_enabled migration
TalexDreamSoul Apr 7, 2026
7c8b9c7
fix(contest): switch billing_plans queries to is_enabled
TalexDreamSoul Apr 7, 2026
b154c13
fix(build): avoid unocss webfont fetch in ci
TalexDreamSoul Apr 8, 2026
e00adc4
feat(data): add user avatars and member previews
TalexDreamSoul Apr 8, 2026
b5bfb71
feat(team): redesign project card footer
TalexDreamSoul Apr 8, 2026
8e1a550
test(team): cover avatar and footer summaries
TalexDreamSoul Apr 8, 2026
168f85a
fix(team): trim seat summary copy
TalexDreamSoul Apr 8, 2026
eb14238
refactor(project): extract basic settings editor
TalexDreamSoul Apr 8, 2026
df34352
feat(team): enable project settings editing
TalexDreamSoul Apr 8, 2026
d63accf
test(team): cover shared settings editor
TalexDreamSoul Apr 8, 2026
c11f958
feat(auth): support manual avatar management
TalexDreamSoul Apr 8, 2026
e530f9d
feat(notification): add notification center
TalexDreamSoul Apr 8, 2026
0c06d90
feat(loopy): add floating workspace assistant
TalexDreamSoul Apr 8, 2026
6048399
feat(team): polish workspace settings and rename flow
TalexDreamSoul Apr 8, 2026
e71ff48
fix(user-settings): keep settings tabs readable
TalexDreamSoul Apr 8, 2026
a4066dd
fix(lint): resolve workspace validation issues
TalexDreamSoul Apr 8, 2026
4630741
feat(settings): refine workspace overview layout
TalexDreamSoul Apr 8, 2026
a849754
test(settings): cover workspace overview rows
TalexDreamSoul Apr 8, 2026
5fcb2a3
fix(team-ui): repair shared imports and strict guards
TalexDreamSoul Apr 8, 2026
4c2836f
ci(actions): gate image publish on successful ci
TalexDreamSoul Apr 8, 2026
3ac1015
ci(actions): wait for same-sha ci before publish
TalexDreamSoul Apr 8, 2026
c6687e0
ci(jenkins): extract deploy trigger and notify
TalexDreamSoul Apr 8, 2026
b7efad6
ci(jenkins): notify deploy start from jenkins
TalexDreamSoul Apr 8, 2026
0f341ea
feat(settings): simplify profile panel
TalexDreamSoul Apr 8, 2026
26a8e06
test(settings): align profile panel assertions
TalexDreamSoul Apr 8, 2026
ff24a54
refactor(admin): retire legacy contest import sync flows
TalexDreamSoul Apr 8, 2026
bbcda23
refactor(contest): remove obsolete import sync schema code
TalexDreamSoul Apr 8, 2026
ee13ba9
fix(invite-flow): 支持通用邀请链接多人复用
TalexDreamSoul Apr 8, 2026
f712da4
test(invite-ui): 明确通用邀请与定向邀请文案
TalexDreamSoul Apr 8, 2026
68ddd22
chore(invite-ui): 补齐通用邀请文案遗漏
TalexDreamSoul Apr 8, 2026
ec14e8a
feat(project-upload): add session-based chunk upload backend
TalexDreamSoul Apr 8, 2026
72d46aa
feat(workspace): add project upload manager and upload tray ui
TalexDreamSoul Apr 8, 2026
521c717
refactor(workspace): sync dashboard and dialog updates
TalexDreamSoul Apr 8, 2026
a45f482
test(workspace): update smoke and workspace flows
TalexDreamSoul Apr 8, 2026
59ee9fe
feat: add resource knowledge governance
TalexDreamSoul Apr 8, 2026
f7260a0
feat(workspace): enhance collab editor and upload activity
TalexDreamSoul Apr 8, 2026
b38263e
chore(assets): refresh public app icons
TalexDreamSoul Apr 8, 2026
0254d1c
fix(ci): resolve lint regressions
TalexDreamSoul Apr 8, 2026
000c4ef
fix(build): restore app alias resolution
TalexDreamSoul Apr 8, 2026
8b6c6c4
feat(upload): allow project members to view upload activity
TalexDreamSoul Apr 9, 2026
cf27bd1
feat(resource): expose uploader metadata for project uploads
TalexDreamSoul Apr 9, 2026
be62e64
feat(workspace): show uploader names in resource details
TalexDreamSoul Apr 9, 2026
6382c8f
feat: add admin operations dashboard
TalexDreamSoul Apr 9, 2026
26e4393
feat(analytics): add comprehensive analytics dashboard
cxx224 Apr 9, 2026
9494d16
fix(resource): address review feedback
TalexDreamSoul Apr 9, 2026
a6952e1
chore(pr-3): merge dev into branch
TalexDreamSoul Apr 9, 2026
65086eb
feat(resource): add governance and operations dashboard
EntombedShip31 Apr 9, 2026
192cb7d
feat(dashboard): polish home workspace UI
ylp468 Apr 9, 2026
4599fff
Merge remote-tracking branch 'origin/dev' into ydy/dev
TalexDreamSoul Apr 9, 2026
e332419
feat: add billing usage tracking v1 (#5)
MidnightMr Apr 9, 2026
b2c2520
chore(merge): sync origin dev into pr6
TalexDreamSoul Apr 9, 2026
ee00b5d
Merge pull request #6 from EntombedShip31/ydy/dev
TalexDreamSoul Apr 9, 2026
8141016
fix(analytics-topic-board): address review feedback and sync latest d…
cxx224 Apr 9, 2026
fa9d1bc
feat(workspace): update defense runtime and notification ui
TalexDreamSoul Apr 9, 2026
7cfc02b
feat(workspace): add meeting and collaboration workflows
TalexDreamSoul Apr 9, 2026
7f655c7
Merge remote-tracking branch 'origin/dev' into dev
TalexDreamSoul Apr 9, 2026
a3d0bab
feat(meeting): support scheduling and join flow
TalexDreamSoul Apr 9, 2026
c4fb112
fix(meeting): expose join flow and pageview fetch
TalexDreamSoul Apr 9, 2026
b076ad7
feat(workspace): refine panel density and display controls
TalexDreamSoul Apr 9, 2026
676d09b
test(workspace): align workspace display ui assertions
TalexDreamSoul Apr 9, 2026
d77351d
feat(workspace): refresh meeting panels and flows
TalexDreamSoul Apr 9, 2026
4a9c597
feat(editor): extend rich text command support
TalexDreamSoul Apr 9, 2026
69045a6
fix(app): stabilize page fetch typing and embeds
TalexDreamSoul Apr 9, 2026
fe2720d
fix(editor): align image node view typing
TalexDreamSoul Apr 9, 2026
36d92f3
style(repo): normalize lint autofixes
TalexDreamSoul Apr 9, 2026
af95d55
refactor(dashboard): restore classic navigation shell
TalexDreamSoul Apr 9, 2026
7d3dc76
fix(team): keep dashboard on workspace overview
TalexDreamSoul Apr 9, 2026
36c0f18
fix(ci): resolve unsafe fetch typing
TalexDreamSoul Apr 9, 2026
20d0137
fix(team): keep dashboard on workspace overview
TalexDreamSoul Apr 9, 2026
ee36e80
feat(meeting): add guest share backend
TalexDreamSoul Apr 9, 2026
df463fc
feat(meeting): add web meeting client
TalexDreamSoul Apr 9, 2026
ba11955
test(meeting): cover guest share integration
TalexDreamSoul Apr 9, 2026
a35427d
feat(logo): extract reusable icon logo component
TalexDreamSoul Apr 9, 2026
a8ba848
feat(app): sync favicon with active color mode
TalexDreamSoul Apr 9, 2026
9ec01d7
refactor(login): extract reusable login modules
TalexDreamSoul Apr 9, 2026
8f42b55
refactor(login): center the login card layout
TalexDreamSoul Apr 9, 2026
772f91a
refactor(types): align workspace view models
TalexDreamSoul Apr 9, 2026
09b1303
feat(editor): enhance collab rich text workflows
TalexDreamSoul Apr 9, 2026
fccce0a
refactor(workspace): polish sidebar interaction states
TalexDreamSoul Apr 9, 2026
cd20d3e
feat(meeting): sync screen share participant updates
TalexDreamSoul Apr 10, 2026
da1f66c
feat(workspace): wire metak command palette
TalexDreamSoul Apr 10, 2026
050ffac
fix(ci): resolve lint and catalog blockers
TalexDreamSoul Apr 10, 2026
f92d3c0
feat(resource): refine library search and embedded upload titles
TalexDreamSoul Apr 10, 2026
78257c3
refactor(workspace): improve resource tree expansion
TalexDreamSoul Apr 10, 2026
3c4be46
feat(meeting): expand screen sharing experience
TalexDreamSoul Apr 10, 2026
b860daf
fix(ci): sync pnpm lockfile for catalog deps
TalexDreamSoul Apr 10, 2026
1b11164
refactor: unify page system and split workspace panels
TalexDreamSoul Apr 10, 2026
558b646
Merge branch 'codex/page-system-refactor' into dev
TalexDreamSoul Apr 10, 2026
0ae6690
feat(workspace): add document assist and comment workflows
TalexDreamSoul Apr 10, 2026
805a9db
refactor(workspace): move account and ai controls into rails
TalexDreamSoul Apr 11, 2026
1919f6d
feat(auth): add oauth oidc integration support
TalexDreamSoul Apr 11, 2026
4f61c44
fix(admin-operations): aggregate preview queue metrics
TalexDreamSoul Apr 11, 2026
f3b4eb8
test(admin-operations): guard preview queue aggregation
TalexDreamSoul Apr 11, 2026
bcb9554
feat(release): add draft review workflow
TalexDreamSoul Apr 11, 2026
b07fd59
feat(admin): add release workspace pages
TalexDreamSoul Apr 11, 2026
8de6deb
feat(sync): refresh bitable mappings and tests
TalexDreamSoul Apr 11, 2026
73bddc1
fix(settings): retune user settings typography and density
TalexDreamSoul Apr 11, 2026
b657fae
test(ui): guard login shell and user-settings baseline
TalexDreamSoul Apr 11, 2026
3277fee
feat(workspace): support metak pinyin search
TalexDreamSoul Apr 11, 2026
879a700
style(workspace): refine metak panel density
TalexDreamSoul Apr 11, 2026
d9e5bd1
feat(workspace): add final review workbench mode
TalexDreamSoul Apr 11, 2026
2047bbd
fix(login): restore glass auth layout
TalexDreamSoul Apr 11, 2026
f196d15
feat(resource-tree): persist project resource tree and subtree lifecycle
TalexDreamSoul Apr 11, 2026
baf8ae0
fix(workspace-sidebar): compact tree layout and stabilize interactions
TalexDreamSoul Apr 11, 2026
ed450e8
fix(workspace-shell): repair invite flow and panel regressions
TalexDreamSoul Apr 11, 2026
15f04fb
fix(workspace-sidebar): make tree rows fill full width
TalexDreamSoul Apr 11, 2026
ddaf008
fix(workspace): restore display preference sliders
TalexDreamSoul Apr 11, 2026
eeb96cc
feat(workspace): add markdown comment filters
TalexDreamSoul Apr 11, 2026
3d2cad4
fix(runtime): stabilize auth probe and realtime listener
TalexDreamSoul Apr 11, 2026
9021652
fix(resources): align inserts and single-client queries
TalexDreamSoul Apr 11, 2026
fa1d2c1
feat(workspace): refresh project workspace surfaces
TalexDreamSoul Apr 11, 2026
4cccb96
fix(workspace): sync sidebar density variables
TalexDreamSoul Apr 11, 2026
65f1f30
feat(scene): add structured scene preview tooling
TalexDreamSoul Apr 11, 2026
53025e2
feat(platform): add auth session probe and meeting providers
TalexDreamSoul Apr 11, 2026
f69a37c
test(server): add project resource sql order coverage
TalexDreamSoul Apr 11, 2026
58a0af1
fix(resource-preview): bypass conversion for image uploads
TalexDreamSoul Apr 11, 2026
d9af325
feat(scene): add vueflow scene document foundation
TalexDreamSoul Apr 11, 2026
faff34a
feat(design): add vueflow design workspace panel
TalexDreamSoul Apr 11, 2026
63294e4
feat(diagram): add graph-aware editor canvas
TalexDreamSoul Apr 11, 2026
69fc31c
fix(workspace-upload): dock drawer as true left aside
TalexDreamSoul Apr 12, 2026
5b5028d
feat(sentry): add staging smoke validation
TalexDreamSoul Apr 12, 2026
968497b
fix(ci): unblock dev image publish on smoke success
TalexDreamSoul Apr 12, 2026
c404359
fix(feishu-sync): support policy sync item validation
TalexDreamSoul Apr 12, 2026
2729186
fix(admin): remove legacy resource sync fields
TalexDreamSoul Apr 13, 2026
39a2245
fix(sync): sanitize legacy resource metadata
TalexDreamSoul Apr 13, 2026
db024ec
test(sync): cover legacy resource metadata cleanup
TalexDreamSoul Apr 13, 2026
9bc1af5
feat(design): restore workspace design shell integration
TalexDreamSoul Apr 14, 2026
e7e958c
feat(design): restore canvas runtime and project wiring
TalexDreamSoul Apr 14, 2026
7f5b57a
test(design): restore design workspace coverage
TalexDreamSoul Apr 14, 2026
ce31200
refactor(core): split domain types and bootstrap api handlers
TalexDreamSoul Apr 14, 2026
280211b
feat(auth): refresh login bindings and notification center
TalexDreamSoul Apr 14, 2026
968411f
feat(meeting): add provider testing and web client runtime
TalexDreamSoul Apr 14, 2026
5352776
feat(workspace): streamline shell loading and tab interactions
TalexDreamSoul Apr 14, 2026
30f11ef
feat(feishu): add persona preset sync backend
TalexDreamSoul Apr 14, 2026
58ef506
feat(feishu-admin): refine persona sync mapping config
TalexDreamSoul Apr 14, 2026
5843a55
test(feishu): cover persona preset sync flows
TalexDreamSoul Apr 14, 2026
9ca9833
feat(workspace): migrate design canvas to resource tabs
TalexDreamSoul Apr 14, 2026
5a292be
feat(workspace): add batch editing for workspace resources
TalexDreamSoul Apr 14, 2026
9d74d8d
feat(workspace): embed mode switch into ai composer
TalexDreamSoul Apr 14, 2026
e5dd135
feat(workspace): persist chat session tabs and shell state
TalexDreamSoul Apr 15, 2026
d65009a
feat(design): refine scene document and device frames
TalexDreamSoul Apr 15, 2026
6fed02e
chore(pwa): raise precache asset size limit
TalexDreamSoul Apr 15, 2026
d336afe
test(ci): align source assertions with current layout
TalexDreamSoul Apr 15, 2026
9a2a71c
fix(deploy): silence chat session backfill validation
TalexDreamSoul Apr 15, 2026
1e7d012
feat(workspace): split left rail upload and notification panels
TalexDreamSoul Apr 15, 2026
727d359
feat(ai): scope workspace orchestration by mode
TalexDreamSoul Apr 15, 2026
7b5a539
feat(design): support deep selection for projected frames
TalexDreamSoul Apr 15, 2026
cc3da62
fix(db): guard team-first hard cutover and restore path
TalexDreamSoul Apr 15, 2026
15ced86
feat(ai): expose runtime readiness for auth flows
TalexDreamSoul Apr 15, 2026
876358d
feat(canvas): add admin canvas library and project import flows
TalexDreamSoul Apr 15, 2026
9503d7d
feat(workspace): expand design library and ai workspace flows
TalexDreamSoul Apr 15, 2026
d58eb44
fix(canvas): preserve template device mappings on import
TalexDreamSoul Apr 15, 2026
a1a4a8f
fix(db): ignore team-first bridge objects during restore
TalexDreamSoul Apr 15, 2026
828206d
fix(workspace): block context menu while shell overlay is active
TalexDreamSoul Apr 15, 2026
d3da45e
refactor(design): simplify device mockup frame semantics
TalexDreamSoul Apr 15, 2026
d1f3c03
feat(ai): unify model pool and workspace scenes
TalexDreamSoul Apr 15, 2026
f38f69d
feat(feishu): add bitable auto sync and persona sync
TalexDreamSoul Apr 15, 2026
5445f9c
fix(feishu): scope nested drawer select popups
TalexDreamSoul Apr 15, 2026
517acde
feat(ai): add contextual workspace assistant modes
TalexDreamSoul Apr 15, 2026
6575959
feat(design): add mockup catalog and screen editing
TalexDreamSoul Apr 15, 2026
aac415d
chore(workspace): refresh workbench entry copy
TalexDreamSoul Apr 15, 2026
bfabd73
feat(mockup): add admin model management
TalexDreamSoul Apr 15, 2026
0f2192c
fix(ai): refine document assist composer states
TalexDreamSoul Apr 15, 2026
a7f77d5
fix(ai): submit document assist extra instructions
TalexDreamSoul Apr 15, 2026
73d24b1
fix(ai): polish document assist composer layout
TalexDreamSoul Apr 15, 2026
73f4991
test(ai): cover document assist composer states
TalexDreamSoul Apr 15, 2026
1811c4a
test(workspace): refresh ai and workbench assertions
TalexDreamSoul Apr 15, 2026
2609b85
feat(mockup): support preview asset bindings
TalexDreamSoul Apr 15, 2026
bde4662
fix(feishu-sync): 修复编辑器草稿与来源下拉交互
TalexDreamSoul Apr 15, 2026
bb416f4
fix(admin-ai): normalize ai prompts table column config
TalexDreamSoul Apr 15, 2026
a735ffa
feat(mockup-admin): support preview assets and flexible variant slots
TalexDreamSoul Apr 15, 2026
7bb5b40
feat(workspace-ai): add AgentDoc draft flow and inline completion
TalexDreamSoul Apr 15, 2026
bccab4d
feat(feishu-sync): add synced data explorer and better sync hints
TalexDreamSoul Apr 15, 2026
06edca4
fix(workspace-ai): relax qwen inline completion partial mode
TalexDreamSoul Apr 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,16 @@ WINLOOP_ONLYOFFICE_JWT_SECRET=
WINLOOP_PUBLIC_BASE_URL=
# 项目资源临时访问地址有效期(秒)
WINLOOP_PROJECT_RESOURCE_ACCESS_URL_TTL_SECONDS=600

# ===== Sentry(可选;未配置时应用仍可运行,只是不启用上报)=====
WINLOOP_SENTRY_DSN=
# 仅支持 staging / production;本地开发可留空
WINLOOP_SENTRY_ENVIRONMENT=
WINLOOP_SENTRY_TRACES_SAMPLE_RATE=0.1
# 可选;默认复用 WINLOOP_BUILD_VERSION
WINLOOP_SENTRY_RELEASE=

# ===== Sentry 构建期参数(仅 CI/CD 构建并上传 source map 时需要)=====
SENTRY_AUTH_TOKEN=
WINLOOP_SENTRY_ORG=
WINLOOP_SENTRY_PROJECT=
57 changes: 52 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ jobs:
- name: Project Visibility Guard
run: pnpm run test:project-visibility

build_and_smoke:
test_unit:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
Expand All @@ -79,8 +78,56 @@ jobs:
- name: Install
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm run build
- name: Unit Tests
run: pnpm run test:unit

smoke:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: lts/*
package-manager-cache: false

- name: Enable Corepack (pnpm)
run: |
corepack enable
corepack prepare pnpm@10.29.2 --activate
pnpm --version

- name: Install
run: pnpm install --frozen-lockfile

- name: Smoke
run: pnpm run ci:smoke
run: pnpm run test:smoke

e2e_smoke:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: lts/*
package-manager-cache: false

- name: Enable Corepack (pnpm)
run: |
corepack enable
corepack prepare pnpm@10.29.2 --activate
pnpm --version

- name: Install
run: pnpm install --frozen-lockfile

- name: E2E Smoke
env:
WINLOOP_PG_URL: ${{ secrets.WINLOOP_PG_URL }}
run: |
if [ -z "$WINLOOP_PG_URL" ]; then
echo "WINLOOP_PG_URL 未配置,跳过 E2E smoke。"
exit 0
fi
pnpm run test:e2e
189 changes: 189 additions & 0 deletions .github/workflows/github-feishu-notify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
name: GitHub Feishu Notify

on:
issues:
types:
- opened
- reopened
pull_request_target:
types:
- opened
- reopened
- ready_for_review

permissions:
contents: read

jobs:
notify-feishu:
name: Notify Feishu
runs-on: ubuntu-latest
steps:
- name: Check webhook configuration
id: config
env:
FEISHU_WEBHOOK_URL: ${{ secrets.FEISHU_GITHUB_WEBHOOK_URL }}
run: |
set -euo pipefail

if [ -n "${FEISHU_WEBHOOK_URL}" ]; then
echo "enabled=true" >> "${GITHUB_OUTPUT}"
else
echo "enabled=false" >> "${GITHUB_OUTPUT}"
echo "Skip Feishu notification because FEISHU_GITHUB_WEBHOOK_URL is not configured."
fi

- name: Send Feishu notification
if: steps.config.outputs.enabled == 'true'
env:
FEISHU_WEBHOOK_URL: ${{ secrets.FEISHU_GITHUB_WEBHOOK_URL }}
FEISHU_WEBHOOK_SECRET: ${{ secrets.FEISHU_GITHUB_WEBHOOK_SECRET }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_EVENT_ACTION: ${{ github.event.action }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_ACTOR: ${{ github.actor }}
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_RUN_ID: ${{ github.run_id }}
GITHUB_EVENT_PATH: ${{ github.event_path }}
run: |
set -euo pipefail

python3 <<'PY'
import base64
import hashlib
import hmac
import json
import os
import time
import urllib.request

def to_text(value) -> str:
return str(value or "").strip()

def shorten(value: str, limit: int = 180) -> str:
text = to_text(value)
if len(text) <= limit:
return text
return f"{text[: max(0, limit - 3)]}..."

def read_event_payload() -> dict:
path = to_text(os.environ.get("GITHUB_EVENT_PATH"))
with open(path, "r", encoding="utf-8") as handle:
return json.load(handle)

def build_issue_message(payload: dict) -> str:
issue = payload.get("issue") or {}
action = to_text(os.environ.get("GITHUB_EVENT_ACTION"))
number = issue.get("number") or payload.get("number") or "-"
title = to_text(issue.get("title")) or "-"
url = to_text(issue.get("html_url"))
labels = ", ".join(
to_text(item.get("name"))
for item in (issue.get("labels") or [])
if to_text(item.get("name"))
) or "-"
body_preview = shorten(issue.get("body") or "", 220) or "-"
actor = to_text(os.environ.get("GITHUB_ACTOR")) or "-"
repository = to_text(os.environ.get("GITHUB_REPOSITORY")) or "-"
action_label = "新建" if action == "opened" else "重新打开"
run_url = f"{to_text(os.environ.get('GITHUB_SERVER_URL'))}/{repository}/actions/runs/{to_text(os.environ.get('GITHUB_RUN_ID'))}"
return "\n".join([
"GitHub Issue 通知",
f"动作:{action_label}",
f"仓库:{repository}",
f"Issue:#{number} {title}",
f"发起人:{actor}",
f"标签:{labels}",
f"摘要:{body_preview}",
f"链接:{url}",
f"Workflow:{run_url}",
])

def build_pr_message(payload: dict) -> str:
pr = payload.get("pull_request") or {}
action = to_text(os.environ.get("GITHUB_EVENT_ACTION"))
number = pr.get("number") or payload.get("number") or "-"
title = to_text(pr.get("title")) or "-"
url = to_text(pr.get("html_url"))
actor = to_text(os.environ.get("GITHUB_ACTOR")) or "-"
repository = to_text(os.environ.get("GITHUB_REPOSITORY")) or "-"
base_ref = to_text(((pr.get("base") or {}).get("ref"))) or "-"
head_ref = to_text(((pr.get("head") or {}).get("ref"))) or "-"
is_draft = bool(pr.get("draft"))
labels = ", ".join(
to_text(item.get("name"))
for item in (pr.get("labels") or [])
if to_text(item.get("name"))
) or "-"
body_preview = shorten(pr.get("body") or "", 220) or "-"
action_label_map = {
"opened": "新建",
"reopened": "重新打开",
"ready_for_review": "转为可评审",
}
action_label = action_label_map.get(action, action or "触发")
draft_label = "是" if is_draft else "否"
run_url = f"{to_text(os.environ.get('GITHUB_SERVER_URL'))}/{repository}/actions/runs/{to_text(os.environ.get('GITHUB_RUN_ID'))}"
return "\n".join([
"GitHub PR 通知",
f"动作:{action_label}",
f"仓库:{repository}",
f"PR:#{number} {title}",
f"发起人:{actor}",
f"分支:{head_ref} -> {base_ref}",
f"Draft:{draft_label}",
f"标签:{labels}",
f"摘要:{body_preview}",
f"链接:{url}",
f"Workflow:{run_url}",
])

def build_message() -> str:
payload = read_event_payload()
event_name = to_text(os.environ.get("GITHUB_EVENT_NAME"))
if event_name == "issues":
return build_issue_message(payload)
if event_name == "pull_request_target":
return build_pr_message(payload)
raise SystemExit(f"Unsupported event: {event_name}")

def build_signature(secret: str) -> tuple[str, str]:
timestamp = str(int(time.time()))
string_to_sign = f"{timestamp}\n{secret}"
signature = base64.b64encode(
hmac.new(string_to_sign.encode("utf-8"), digestmod=hashlib.sha256).digest()
).decode("utf-8")
return timestamp, signature

webhook_url = to_text(os.environ.get("FEISHU_WEBHOOK_URL"))
webhook_secret = to_text(os.environ.get("FEISHU_WEBHOOK_SECRET"))
if not webhook_url:
raise SystemExit("Missing FEISHU_GITHUB_WEBHOOK_URL")

payload = {
"msg_type": "text",
"content": {
"text": build_message(),
},
}
if webhook_secret:
timestamp, sign = build_signature(webhook_secret)
payload["timestamp"] = timestamp
payload["sign"] = sign

request = urllib.request.Request(
webhook_url,
data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
headers={"Content-Type": "application/json; charset=utf-8"},
method="POST",
)
with urllib.request.urlopen(request, timeout=15) as response:
body = response.read().decode("utf-8", errors="replace")

result = json.loads(body) if body else {}
code = result.get("code", 0)
if code not in (0, "0", None):
raise SystemExit(f"Feishu webhook returned code={code}, msg={result.get('msg', '')}")

print("Feishu notification sent successfully.")
PY
Loading
Loading