Skip to content

Commit 6c862c3

Browse files
committed
Merge pull request #193 from larksuite/main
Change-Id: I7e164a39f7635c2147ca010e657e17303a4cd03f feat: add drive import, export, move, task result shortcuts
2 parents 46a6d71 + eb8b542 commit 6c862c3

46 files changed

Lines changed: 2930 additions & 28508 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/pull_request_template.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
## Summary
2+
<!-- Briefly describe the motivation and scope of this change in 1-3 sentences. -->
3+
4+
## Changes
5+
<!-- List the main changes in this PR. -->
6+
- Change 1
7+
- Change 2
8+
9+
## Test Plan
10+
<!-- Describe how this change was verified. -->
11+
- [ ] Unit tests pass
12+
- [ ] Manual local verification confirms the `lark xxx` command works as expected
13+
14+
## Related Issues
15+
<!-- Link related issues. Use Closes/Fixes to close them automatically. -->
16+
- None
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
name: PR Preview Package Comment
2+
3+
on:
4+
workflow_run:
5+
workflows: ["PR Preview Package"]
6+
types: [completed]
7+
8+
permissions:
9+
actions: read
10+
contents: read
11+
issues: write
12+
pull-requests: write
13+
14+
jobs:
15+
comment:
16+
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request'
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: Check comment payload artifact
21+
id: payload
22+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
23+
with:
24+
script: |
25+
const runId = context.payload.workflow_run?.id;
26+
const { data } = await github.rest.actions.listWorkflowRunArtifacts({
27+
owner: context.repo.owner,
28+
repo: context.repo.repo,
29+
run_id: runId,
30+
per_page: 100,
31+
});
32+
const found = Boolean(
33+
data.artifacts?.some((artifact) => artifact.name === "pkg-pr-new-comment-payload")
34+
);
35+
core.setOutput("found", found ? "true" : "false");
36+
if (!found) {
37+
core.notice("No comment payload artifact found for this run; skipping comment.");
38+
}
39+
40+
- name: Download comment payload
41+
if: steps.payload.outputs.found == 'true'
42+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
43+
with:
44+
name: pkg-pr-new-comment-payload
45+
repository: ${{ github.repository }}
46+
run-id: ${{ github.event.workflow_run.id }}
47+
github-token: ${{ github.token }}
48+
49+
- name: Comment install command
50+
if: steps.payload.outputs.found == 'true'
51+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
52+
with:
53+
script: |
54+
const fs = require("fs");
55+
const payload = JSON.parse(fs.readFileSync("pkg-pr-new-comment-payload.json", "utf8"));
56+
const url = payload?.url;
57+
const payloadPr = payload?.pr;
58+
const sourceRepo = payload?.sourceRepo;
59+
const sourceBranch = payload?.sourceBranch;
60+
if (!Number.isInteger(payloadPr)) {
61+
throw new Error(`Invalid PR number in artifact payload: ${payloadPr}`);
62+
}
63+
if (payloadPr <= 0) {
64+
throw new Error(`Invalid PR number in artifact payload: ${payloadPr}`);
65+
}
66+
const issueNumber = payloadPr;
67+
const runPrNumber = context.payload.workflow_run?.pull_requests?.[0]?.number;
68+
if (Number.isInteger(runPrNumber) && runPrNumber !== issueNumber) {
69+
throw new Error(
70+
`PR number mismatch between workflow_run (${runPrNumber}) and artifact payload (${issueNumber})`,
71+
);
72+
}
73+
74+
if (typeof url !== "string" || url.trim() !== url || /[\u0000-\u001F\u007F]/.test(url)) {
75+
throw new Error(`Invalid package URL in payload: ${url}`);
76+
}
77+
let parsedUrl;
78+
try {
79+
parsedUrl = new URL(url);
80+
} catch {
81+
throw new Error(`Invalid package URL in payload: ${url}`);
82+
}
83+
if (parsedUrl.protocol !== "https:" || parsedUrl.hostname !== "pkg.pr.new") {
84+
throw new Error(`Invalid package URL in payload: ${url}`);
85+
}
86+
87+
const safeRepoPattern = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
88+
const safeBranchPattern = /^[A-Za-z0-9._\/-]+$/;
89+
const hasSkillSource =
90+
typeof sourceRepo === "string" &&
91+
typeof sourceBranch === "string" &&
92+
safeRepoPattern.test(sourceRepo) &&
93+
safeBranchPattern.test(sourceBranch);
94+
const skillSection = hasSkillSource
95+
? [
96+
"",
97+
"### 🧩 Skill update",
98+
"",
99+
"```bash",
100+
`npx skills add ${sourceRepo}#${sourceBranch} -y -g`,
101+
"```",
102+
]
103+
: [
104+
"",
105+
"### 🧩 Skill update",
106+
"",
107+
"_Unavailable for this PR because source repo/branch metadata is missing._",
108+
];
109+
110+
const body = [
111+
"<!-- pkg-pr-new-install-guide -->",
112+
"## 🚀 PR Preview Install Guide",
113+
"",
114+
"### 🧰 CLI update",
115+
"",
116+
"```bash",
117+
`npm i -g ${url}`,
118+
"```",
119+
...skillSection,
120+
].join("\n");
121+
122+
const comments = await github.paginate(github.rest.issues.listComments, {
123+
owner: context.repo.owner,
124+
repo: context.repo.repo,
125+
issue_number: issueNumber,
126+
per_page: 100,
127+
});
128+
129+
const existing = comments.find((comment) =>
130+
comment.user?.login === "github-actions[bot]" &&
131+
typeof comment.body === "string" &&
132+
comment.body.includes("<!-- pkg-pr-new-install-guide -->")
133+
);
134+
135+
if (existing) {
136+
await github.rest.issues.updateComment({
137+
owner: context.repo.owner,
138+
repo: context.repo.repo,
139+
comment_id: existing.id,
140+
body,
141+
});
142+
} else {
143+
await github.rest.issues.createComment({
144+
owner: context.repo.owner,
145+
repo: context.repo.repo,
146+
issue_number: issueNumber,
147+
body,
148+
});
149+
}

.github/workflows/pkg-pr-new.yml

Lines changed: 34 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ on:
77

88
permissions:
99
contents: read
10-
pull-requests: write
1110

1211
jobs:
1312
publish:
@@ -31,74 +30,42 @@ jobs:
3130
- name: Publish to pkg.pr.new
3231
run: npx pkg-pr-new publish --no-compact --json output.json --comment=off ./.pkg-pr-new
3332

34-
- name: Comment install command
35-
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
36-
with:
37-
script: |
38-
const fs = require("fs");
39-
const output = JSON.parse(fs.readFileSync("output.json", "utf8"));
40-
const url = output?.packages?.[0]?.url;
41-
if (!url) {
42-
throw new Error("No package URL found in output.json");
43-
}
44-
const sourceRepo = context.payload.pull_request?.head?.repo?.full_name;
45-
const sourceBranch = context.payload.pull_request?.head?.ref;
46-
const hasSkillSource = Boolean(sourceRepo && sourceBranch);
33+
- name: Build comment payload
34+
env:
35+
PR_NUMBER: ${{ github.event.pull_request.number }}
36+
SOURCE_REPO: ${{ github.event.pull_request.head.repo.full_name }}
37+
SOURCE_BRANCH: ${{ github.event.pull_request.head.ref }}
38+
run: |
39+
node <<'NODE'
40+
const fs = require("fs");
4741
48-
const skillSection = hasSkillSource
49-
? [
50-
"",
51-
"### 🧩 Skill update",
52-
"",
53-
"```bash",
54-
`npx skills add ${sourceRepo}#${sourceBranch} -y -g`,
55-
"```",
56-
]
57-
: [
58-
"",
59-
"### 🧩 Skill update",
60-
"",
61-
"_Unavailable for this PR because source repo/branch metadata is missing._",
62-
];
42+
const output = JSON.parse(fs.readFileSync("output.json", "utf8"));
43+
const url = output?.packages?.[0]?.url;
44+
if (!url) throw new Error("No package URL found in output.json");
45+
if (!url.startsWith("https://pkg.pr.new/")) {
46+
throw new Error(`Unexpected package URL: ${url}`);
47+
}
6348
64-
const body = [
65-
"<!-- pkg-pr-new-install-guide -->",
66-
"## 🚀 PR Preview Install Guide",
67-
"",
68-
"### 🧰 CLI update",
69-
"",
70-
"```bash",
71-
`npm i -g ${url}`,
72-
"```",
73-
...skillSection,
74-
].join("\n");
75-
const issueNumber = context.issue.number;
49+
const pr = Number(process.env.PR_NUMBER);
50+
if (!Number.isInteger(pr) || pr <= 0) {
51+
throw new Error(`Invalid PR_NUMBER: ${process.env.PR_NUMBER}`);
52+
}
7653
77-
const comments = await github.paginate(github.rest.issues.listComments, {
78-
owner: context.repo.owner,
79-
repo: context.repo.repo,
80-
issue_number: issueNumber,
81-
per_page: 100,
82-
});
54+
const payload = {
55+
pr,
56+
url,
57+
sourceRepo: process.env.SOURCE_REPO || "",
58+
sourceBranch: process.env.SOURCE_BRANCH || "",
59+
};
8360
84-
const existing = comments.find((comment) =>
85-
comment.user?.login === "github-actions[bot]" &&
86-
typeof comment.body === "string" &&
87-
comment.body.includes("<!-- pkg-pr-new-install-guide -->")
88-
);
61+
fs.writeFileSync(
62+
"pkg-pr-new-comment-payload.json",
63+
JSON.stringify(payload),
64+
);
65+
NODE
8966
90-
if (existing) {
91-
await github.rest.issues.updateComment({
92-
owner: context.repo.owner,
93-
repo: context.repo.repo,
94-
comment_id: existing.id,
95-
body,
96-
});
97-
} else {
98-
await github.rest.issues.createComment({
99-
owner: context.repo.owner,
100-
repo: context.repo.repo,
101-
issue_number: issueNumber,
102-
body,
103-
});
104-
}
67+
- name: Upload comment payload
68+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
69+
with:
70+
name: pkg-pr-new-comment-payload
71+
path: pkg-pr-new-comment-payload.json
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Test PR Label Logic
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- "scripts/pr-labels/**"
8+
- ".github/workflows/pr-labels-test.yml"
9+
pull_request:
10+
branches: [main]
11+
paths:
12+
- "scripts/pr-labels/**"
13+
- ".github/workflows/pr-labels-test.yml"
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
test-pr-labels:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- uses: actions/setup-node@v4
25+
with:
26+
node-version: '20'
27+
28+
- name: Run PR label regression tests
29+
env:
30+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31+
run: node scripts/pr-labels/test.js

.github/workflows/pr-labels.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: PR Labels
2+
3+
on:
4+
pull_request_target:
5+
# NOTE: This event runs with base-branch code and write permissions.
6+
# Do NOT add `ref: github.event.pull_request.head.sha` to the checkout step,
7+
# as that would execute untrusted PR code with elevated access.
8+
types:
9+
- opened
10+
- edited
11+
- reopened
12+
- synchronize
13+
- ready_for_review
14+
15+
permissions:
16+
contents: read
17+
pull-requests: write
18+
issues: write
19+
20+
jobs:
21+
sync-pr-labels:
22+
if: ${{ github.event.pull_request.state == 'open' }}
23+
runs-on: ubuntu-latest
24+
steps:
25+
- uses: actions/checkout@v4
26+
27+
- uses: actions/setup-node@v4
28+
with:
29+
node-version: '20'
30+
31+
- name: Sync managed PR labels
32+
id: sync_pr_labels
33+
# Labeling is best-effort and must not block PR merges.
34+
continue-on-error: true
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37+
run: node scripts/pr-labels/index.js
38+
39+
- name: Warn when label sync fails
40+
if: ${{ always() && steps.sync_pr_labels.outcome == 'failure' }}
41+
run: |
42+
echo "::warning::PR label sync failed; labels may be stale."
43+
echo "⚠️ PR label sync failed; labels may be stale." >> "$GITHUB_STEP_SUMMARY"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Skill Format Check
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- "skills/**"
8+
- "scripts/skill-format-check/**"
9+
- ".github/workflows/skill-format-check.yml"
10+
pull_request:
11+
branches: [main]
12+
paths:
13+
- "skills/**"
14+
- "scripts/skill-format-check/**"
15+
- ".github/workflows/skill-format-check.yml"
16+
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
check-format:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- name: Setup Node.js
27+
uses: actions/setup-node@v4
28+
with:
29+
node-version: '20'
30+
31+
- name: Run Skill Format Check
32+
run: node scripts/skill-format-check/index.js

0 commit comments

Comments
 (0)