Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/fix-cross-repo-closer-octokit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
---

fix(ci): rename the cross-repo client — `github-script` already declares `octokit`

Release-nothing: touches `.github/workflows/cross-repo-issue-closer.yml` only.

`actions/github-script` injects an `octokit` binding into the script scope, so
the `const octokit = require('@actions/github').getOctokit(token)` added in
#4553 aborted the run before a single line of logic executed:

SyntaxError: Identifier 'octokit' has already been declared

This surfaced on #4553's own merge — the first time the workflow ever ran, and
the first time any of its runtime behaviour was exercised. Until this lands,
every merged pull request in this repository carries one red check.

The pre-merge validation missed it for an instructive reason. The script was
syntax-checked against a hand-written wrapper declaring `{github, context,
core, require}` — and a wrapper that omits an injected identifier cannot
possibly see a collision with it. The check reported clean because it was
asking a narrower question than the runtime asks. The wrapper now carries the
full injected set, and the previous spelling fails it.
20 changes: 14 additions & 6 deletions .github/workflows/cross-repo-issue-closer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ jobs:
'gi',
);

// Report credential state on EVERY run, before any early return.
// Otherwise a repository with the secret and one without look
// identical until a cross-repo reference happens to show up —
// which can be days — and "is it configured?" stays unanswerable.
// Presence only; the value is never read into the log.
const token = process.env.CROSS_REPO_TOKEN;
core.info(
`CROSS_REPO_ISSUE_TOKEN: ${token ? 'configured' : 'ABSENT — cross-repo closes will be reported, not performed'}`,
);

const targets = new Map();
for (const [, owner, repo, number] of body.matchAll(pattern)) {
const key = `${owner}/${repo}#${number}`;
Expand All @@ -75,8 +85,6 @@ jobs:
}
core.info(`Cross-repo targets: ${[...targets.keys()].join(', ')}`);

const token = process.env.CROSS_REPO_TOKEN;

if (!token) {
// Degrade VISIBLY. Someone has to close these by hand, and this
// comment is the only thing that will tell them so.
Expand All @@ -103,25 +111,25 @@ jobs:

// A second client: `github` is bound to GITHUB_TOKEN, which has no
// write access outside this repository.
const octokit = require('@actions/github').getOctokit(token);
const crossRepo = require('@actions/github').getOctokit(token);

for (const [key, t] of targets) {
try {
const { data: issue } = await octokit.rest.issues.get({
const { data: issue } = await crossRepo.rest.issues.get({
owner: t.owner, repo: t.repo, issue_number: t.number,
});
if (issue.state === 'closed') {
core.info(`${key} is already closed — skipping.`);
continue;
}
await octokit.rest.issues.createComment({
await crossRepo.rest.issues.createComment({
owner: t.owner, repo: t.repo, issue_number: t.number,
body:
`已由 ${thisRepo} 的 ${prUrl} 修复并合并。\n\n` +
`(跨仓库的关闭关键字不会自动生效,本条由 \`cross-repo-issue-closer\` 工作流代为收口。)\n\n` +
`---\n_Generated by [Claude Code](https://claude.ai/code)_`,
});
await octokit.rest.issues.update({
await crossRepo.rest.issues.update({
owner: t.owner, repo: t.repo, issue_number: t.number,
state: 'closed', state_reason: 'completed',
});
Expand Down
Loading