Skip to content

Commit 4a4820d

Browse files
authored
feat: add Feishu PR notifications (#625)
- Add PR workflow and align issue/discussion flows to reuse GitHub App tokens - Update the notification script to report pull requests and skip internal authors via org membership checks - Document the new workflow and internal-author suppression in the nexu-pal specs
1 parent 1667c20 commit 4a4820d

5 files changed

Lines changed: 111 additions & 12 deletions

File tree

.github/workflows/feishu-discussion-notify.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,30 @@ on:
44
discussion:
55
types: [created]
66

7+
permissions:
8+
contents: read
9+
710
jobs:
811
notify:
912
name: Notify Feishu
1013
runs-on: ubuntu-latest
1114
steps:
15+
- name: Create GitHub App token
16+
id: app-token
17+
uses: actions/create-github-app-token@v1
18+
with:
19+
app-id: ${{ secrets.NEXU_PAL_APP_ID }}
20+
private-key: ${{ secrets.NEXU_PAL_PRIVATE_KEY_PEM }}
21+
1222
- uses: actions/checkout@v4
1323
with:
14-
sparse-checkout: scripts/notify
24+
sparse-checkout: scripts
1525
- name: Send Feishu notification
1626
env:
1727
WEBHOOK_URL: ${{ secrets.ISSUE_SYNC_FEISHU_BOT_WEBHOOK }}
1828
EVENT_TYPE: discussion
29+
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
30+
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
1931
TITLE: ${{ github.event.discussion.title }}
2032
URL: ${{ github.event.discussion.html_url }}
2133
NUMBER: ${{ github.event.discussion.number }}

.github/workflows/feishu-issue-notify.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,30 @@ on:
44
issues:
55
types: [opened]
66

7+
permissions:
8+
contents: read
9+
710
jobs:
811
notify:
912
name: Notify Feishu
1013
runs-on: ubuntu-latest
1114
steps:
15+
- name: Create GitHub App token
16+
id: app-token
17+
uses: actions/create-github-app-token@v1
18+
with:
19+
app-id: ${{ secrets.NEXU_PAL_APP_ID }}
20+
private-key: ${{ secrets.NEXU_PAL_PRIVATE_KEY_PEM }}
21+
1222
- uses: actions/checkout@v4
1323
with:
14-
sparse-checkout: scripts/notify
24+
sparse-checkout: scripts
1525
- name: Send Feishu notification
1626
env:
1727
WEBHOOK_URL: ${{ secrets.ISSUE_SYNC_FEISHU_BOT_WEBHOOK }}
1828
EVENT_TYPE: issue
29+
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
30+
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
1931
TITLE: ${{ github.event.issue.title }}
2032
URL: ${{ github.event.issue.html_url }}
2133
NUMBER: ${{ github.event.issue.number }}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Feishu Pull Request Notification
2+
3+
on:
4+
pull_request:
5+
types: [opened]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
notify:
12+
name: Notify Feishu
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Create GitHub App token
16+
id: app-token
17+
uses: actions/create-github-app-token@v1
18+
with:
19+
app-id: ${{ secrets.NEXU_PAL_APP_ID }}
20+
private-key: ${{ secrets.NEXU_PAL_PRIVATE_KEY_PEM }}
21+
22+
- uses: actions/checkout@v4
23+
with:
24+
sparse-checkout: scripts
25+
26+
- name: Send Feishu notification
27+
env:
28+
WEBHOOK_URL: ${{ secrets.ISSUE_SYNC_FEISHU_BOT_WEBHOOK }}
29+
EVENT_TYPE: pull_request
30+
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
31+
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
32+
TITLE: ${{ github.event.pull_request.title }}
33+
URL: ${{ github.event.pull_request.html_url }}
34+
NUMBER: ${{ github.event.pull_request.number }}
35+
AUTHOR: ${{ github.event.pull_request.user.login }}
36+
BODY: ${{ github.event.pull_request.body }}
37+
LABELS_OR_CATEGORY: ${{ join(github.event.pull_request.labels.*.name, ', ') }}
38+
REPO: ${{ github.repository }}
39+
run: node scripts/notify/feishu-notify.mjs

scripts/notify/feishu-notify.mjs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
#!/usr/bin/env node
22

3+
import { checkOrganizationMembership } from "../nexu-pal/lib/github-client.mjs";
4+
35
/**
46
* Send a Feishu interactive card notification via incoming webhook.
57
*
68
* Environment variables:
79
* WEBHOOK_URL — Feishu bot webhook URL
8-
* EVENT_TYPE — "issue" or "discussion"
10+
* EVENT_TYPE — "issue", "discussion", or "pull_request"
911
* TITLE — Event title
1012
* URL — Event HTML URL
1113
* NUMBER — Event number
1214
* AUTHOR — Event author login
1315
* BODY — Event body (may be empty)
1416
* LABELS_OR_CATEGORY — Comma-separated labels or discussion category name
1517
* REPO — owner/repo
18+
* GITHUB_TOKEN — GitHub App token for org-membership check
19+
* GITHUB_REPOSITORY_OWNER — owner/org login used for org-membership check
1620
*/
1721

1822
const webhookUrl = process.env.WEBHOOK_URL;
@@ -24,15 +28,44 @@ const author = process.env.AUTHOR ?? "";
2428
const body = process.env.BODY ?? "";
2529
const labelsOrCategory = process.env.LABELS_OR_CATEGORY || "none";
2630
const repo = process.env.REPO ?? "";
31+
const ghToken = process.env.GITHUB_TOKEN;
32+
const repositoryOwner = process.env.GITHUB_REPOSITORY_OWNER;
2733

2834
if (!webhookUrl) {
2935
console.error("WEBHOOK_URL is required");
3036
process.exit(1);
3137
}
3238

39+
if (!ghToken || !repositoryOwner || !author) {
40+
console.error(
41+
"GITHUB_TOKEN, GITHUB_REPOSITORY_OWNER, and AUTHOR are required",
42+
);
43+
process.exit(1);
44+
}
45+
46+
const isInternalAuthor = await checkOrganizationMembership({
47+
token: ghToken,
48+
org: repositoryOwner,
49+
username: author,
50+
});
51+
52+
if (isInternalAuthor) {
53+
console.log(`Skipping Feishu notification for internal author: ${author}`);
54+
process.exit(0);
55+
}
56+
3357
const isDiscussion = eventType === "discussion";
34-
const typeLabel = isDiscussion ? "Discussion" : "Issue";
35-
const headerColor = isDiscussion ? "turquoise" : "orange";
58+
const isPullRequest = eventType === "pull_request";
59+
const typeLabel = isDiscussion
60+
? "Discussion"
61+
: isPullRequest
62+
? "Pull Request"
63+
: "Issue";
64+
const headerColor = isDiscussion
65+
? "turquoise"
66+
: isPullRequest
67+
? "purple"
68+
: "orange";
3669
const metaLabel = isDiscussion ? "Category" : "Labels";
3770

3871
const bodySnippet =

specs/current/nexu-pal.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ GitHub issue/discussion automation around **nexu-pal** issue processing and Feis
1111
| `Feishu Issue Notification` | `issues: [opened]` | `scripts/notify/feishu-notify.mjs` |
1212
| `nexu-pal: needs-triage notify` | `issues: [labeled]` (when label is `needs-triage`) | `scripts/notify/feishu-triage-notify.mjs` |
1313
| `Feishu Discussion Notification` | `discussion: [created]` | `scripts/notify/feishu-notify.mjs` |
14+
| `Feishu Pull Request Notification` | `pull_request: [opened]` | `scripts/notify/feishu-notify.mjs` |
1415

1516
## On issue opened
1617

@@ -57,13 +58,14 @@ Current transitions:
5758

5859
## Feishu notifications
5960

60-
Three GitHub Actions send Feishu webhook notifications for GitHub content:
61+
Four GitHub Actions send Feishu webhook notifications for GitHub content:
6162

62-
1. **Issue notification** — On `issues: [opened]`, sends the existing issue card to the legacy webhook without changing the current chain.
63+
1. **Issue notification** — On `issues: [opened]`, sends the existing issue card to the legacy webhook, but skips notifications when the author is a repository-owner organization member.
6364
2. **Needs-triage issue notification** — On `issues: [labeled]`, when the added label is `needs-triage`, sends a triage card to either the bug or non-bug webhook based on the issue's current labels. The workflow maps GitHub secrets to internal env vars `BUG_WEBHOOK` and `REQ_WEBHOOK`.
64-
3. **Discussion notification** — On `discussion: [created]`, sends the existing discussion card format using the discussion category in place of labels.
65+
3. **Discussion notification** — On `discussion: [created]`, sends the existing discussion card format using the discussion category in place of labels, but skips notifications when the author is a repository-owner organization member.
66+
4. **Pull request notification** — On `pull_request: [opened]`, sends the existing card format using pull request labels, but skips notifications when the author is a repository-owner organization member.
6567

66-
The legacy issue/discussion workflows continue to run `node scripts/notify/feishu-notify.mjs`. The new triage workflow runs `node scripts/notify/feishu-triage-notify.mjs`.
68+
The issue/discussion/pull-request workflows run `node scripts/notify/feishu-notify.mjs`. The triage workflow runs `node scripts/notify/feishu-triage-notify.mjs`.
6769

6870
## Labels managed
6971

@@ -81,7 +83,7 @@ The legacy issue/discussion workflows continue to run `node scripts/notify/feish
8183

8284
The three **nexu-pal** workflows create a short-lived token via `actions/create-github-app-token@v1` using secrets `NEXU_PAL_APP_ID` and `NEXU_PAL_PRIVATE_KEY_PEM`. All GitHub API calls and the first-interaction action use this App token.
8385

84-
The Feishu notification workflows do not use the GitHub App. They use the default GitHub Actions context plus Feishu incoming-webhook secrets.
86+
The issue / discussion / pull-request Feishu notification workflows also create a short-lived GitHub App token so they can reuse the org-membership check and suppress notifications for internal authors. The `needs-triage` Feishu workflow continues to use GitHub Actions event data plus Feishu incoming-webhook secrets.
8587

8688
## Secrets
8789

@@ -91,7 +93,7 @@ The Feishu notification workflows do not use the GitHub App. They use the defaul
9193
| `NEXU_PAL_PRIVATE_KEY_PEM` | GitHub App private key |
9294
| `OPENAI_BASE_URL` | OpenRouter base URL |
9395
| `OPENAI_API_KEY` | OpenRouter API key |
94-
| `ISSUE_SYNC_FEISHU_BOT_WEBHOOK` | Feishu incoming webhook URL for the existing issue-opened and discussion notifications |
96+
| `ISSUE_SYNC_FEISHU_BOT_WEBHOOK` | Feishu incoming webhook URL for the issue-opened, discussion-created, and pull-request-opened notifications |
9597
| `ISSUE_TRIAGE_BUG_FEISHU_WEBHOOK` | Feishu incoming webhook URL for bug triage notifications |
9698
| `ISSUE_TRIAGE_REQ_FEISHU_WEBHOOK` | Feishu incoming webhook URL for non-bug triage notifications |
9799

@@ -104,6 +106,7 @@ The Feishu notification workflows do not use the GitHub App. They use the defaul
104106
feishu-issue-notify.yml
105107
nexu-pal-needs-triage-notify.yml
106108
feishu-discussion-notify.yml
109+
feishu-pr-notify.yml
107110
scripts/nexu-pal/
108111
process-issue-opened.mjs # opened-issue triage pipeline with bug-only labeling + needs-information pause
109112
process-triage-command.mjs # parse /triage comments, check permission, and apply terminal transitions
@@ -115,5 +118,5 @@ scripts/nexu-pal/
115118
lib/signals/duplicate-detector.mjs # duplicate detector stub
116119
scripts/notify/
117120
feishu-triage-notify.mjs # route needs-triage issue notifications via BUG_WEBHOOK / REQ_WEBHOOK
118-
feishu-notify.mjs # legacy issue-opened and discussion Feishu webhook card notification
121+
feishu-notify.mjs # issue / discussion / pull-request Feishu webhook card notification with internal-author suppression
119122
```

0 commit comments

Comments
 (0)