Skip to content

Commit 3686c1a

Browse files
authored
Merge pull request #7055 from jandubois/merge-to-main
Cherry-pick into release-14: Merge to main: Use separate tokens for creating a branch
2 parents ac14479 + bb5a8b1 commit 3686c1a

3 files changed

Lines changed: 32 additions & 15 deletions

File tree

.github/workflows/release-merge-to-main.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
if: needs.check-for-token.outputs.has-token == 'true'
3030
runs-on: ubuntu-latest
3131
permissions:
32-
pull-requests: write
32+
contents: write
3333
steps:
3434
- uses: actions/checkout@v4
3535
- uses: actions/setup-node@v4
@@ -49,4 +49,5 @@ jobs:
4949

5050
- run: node scripts/ts-wrapper.js scripts/release-merge-to-main.ts
5151
env:
52-
GITHUB_TOKEN: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW }}
52+
GITHUB_WRITE_TOKEN: ${{ github.token }}
53+
GITHUB_PR_TOKEN: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW }}

scripts/lib/dependencies.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,24 @@ export type HasUnreleasedChangesResult = {latestReleaseTag: string, hasUnrelease
9797
export type GitHubRelease = Awaited<ReturnType<Octokit['rest']['repos']['listReleases']>>['data'][0];
9898

9999
let _octokit: Octokit | undefined;
100+
let _octokitAuthToken: string | undefined;
100101

101-
export function getOctokit() {
102-
if (_octokit) {
103-
return _octokit;
104-
}
105-
const personalAccessToken = process.env.GITHUB_TOKEN;
102+
/**
103+
* Get a cached instance of Octokit, or create a new one as needed. If the given token does not
104+
* match the one used to create the cached instance, a new one is created (and cached).
105+
* @param personalAccessToken Optional GitHub personal access token; defaults to GITHUB_TOKEN.
106+
*/
107+
export function getOctokit(personalAccessToken?: string): Octokit {
108+
personalAccessToken ||= process.env.GITHUB_TOKEN;
106109

107110
if (!personalAccessToken) {
108111
throw new Error('Please set GITHUB_TOKEN to a PAT to check versions of github-based dependencies.');
109112
}
110113

114+
if (_octokit && _octokitAuthToken === personalAccessToken) {
115+
return _octokit;
116+
}
117+
111118
function makeLimitHandler(type: string, maxRetries: number): NonNullable<ThrottlingOptions['onSecondaryRateLimit']> {
112119
return (retryAfter, options, octokit, retryCount) => {
113120
function getOpt(prop: string) {
@@ -132,13 +139,16 @@ export function getOctokit() {
132139
};
133140
}
134141

135-
return new Octokit({
142+
_octokit = new Octokit({
136143
auth: personalAccessToken,
137144
throttle: {
138145
onRateLimit: makeLimitHandler('primary', 3),
139146
onSecondaryRateLimit: makeLimitHandler('secondary', 3),
140147
},
141148
});
149+
_octokitAuthToken = personalAccessToken;
150+
151+
return _octokit;
142152
}
143153

144154
export type IssueOrPullRequest = Awaited<ReturnType<Octokit['rest']['search']['issuesAndPullRequests']>>['data']['items'][0];

scripts/release-merge-to-main.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
// Environment:
55
// GITHUB_REPOSITORY, GITHUB_EVENT_PATH, and others
66
// See https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
7-
// GITHUB_TOKEN: GitHub authorization token.
8-
// Must have write permissions for `actions`, `contents`, `pull_requests`.
7+
// GITHUB_WRITE_TOKEN: GitHub authorization token for creating a branch.
8+
// Must have `contents:write` permissions.
9+
// GITHUB_PR_TOKEN: GitHub authorization token.
10+
// Must have write permissions for `actions` and `pull_requests`.
911

1012
import fs from 'fs';
1113

@@ -19,7 +21,8 @@ import { getOctokit } from './lib/dependencies';
1921
type EnvironmentVariableName =
2022
'GITHUB_REPOSITORY' |
2123
'GITHUB_EVENT_PATH' |
22-
'GITHUB_TOKEN';
24+
'GITHUB_WRITE_TOKEN' |
25+
'GITHUB_PR_TOKEN';
2326

2427
/**
2528
* Partial contents of the event payload, for a release event.
@@ -59,7 +62,7 @@ function getEnv(variable: EnvironmentVariableName): string {
5962
*/
6063
async function ensureBranch(owner: string, repo: string, branchName: string, tagName: string): Promise<void> {
6164
const ref = `heads/${ branchName }`;
62-
const { git } = getOctokit().rest;
65+
const { git } = getOctokit(getEnv('GITHUB_WRITE_TOKEN')).rest;
6366
const { data: tagRef } = await git.getRef({
6467
owner, repo, ref: `tags/${ tagName }`,
6568
});
@@ -77,11 +80,14 @@ async function ensureBranch(owner: string, repo: string, branchName: string, tag
7780
await git.updateRef({
7881
owner, repo, ref, sha,
7982
});
83+
} else {
84+
console.log(`Branch ${ owner }/${ repo }/${ ref } is already up-to-date.`);
8085
}
8186
} catch (ex) {
8287
if (!(ex instanceof RequestError) || ex.status !== 404) {
8388
throw ex;
8489
}
90+
console.log(`Creating new branch ${ owner }/${ repo }/${ ref } at ${ sha }`);
8591
// Branch does not exist; create it.
8692
await git.createRef({
8793
// Only this API takes a `refs/` prefix; get & update omit it.
@@ -100,14 +106,14 @@ async function ensureBranch(owner: string, repo: string, branchName: string, tag
100106
async function findExisting(owner: string, repo: string, branch: string) {
101107
const fullRepo = `${ owner }/${ repo }`;
102108
const query = `type:pr is:open repo:${ fullRepo } base:${ base } head:${ branch } sort:updated`;
103-
const result = await getOctokit().rest.search.issuesAndPullRequests({ q: query });
109+
const result = await getOctokit(getEnv('GITHUB_WRITE_TOKEN')).rest.search.issuesAndPullRequests({ q: query });
104110

105111
for (const item of result.data.items) {
106112
// Must be an open item, and that item must be a pull request.
107113
if (item.state !== 'open' || !item.pull_request) {
108114
continue;
109115
}
110-
const { data: pr } = await getOctokit().rest.pulls.get({
116+
const { data: pr } = await getOctokit(getEnv('GITHUB_PR_TOKEN')).rest.pulls.get({
111117
owner, repo, pull_number: item.number,
112118
});
113119

@@ -169,7 +175,7 @@ async function findExisting(owner: string, repo: string, branch: string) {
169175
console.log(`Creating new PR on ${ owner }/${ repo }: ${ base } <- ${ branchName }`);
170176
await ensureBranch(owner, repo, branchName, tagName);
171177
const title = `Merge release ${ tagName } back into ${ base }`;
172-
const { data: item } = await getOctokit().rest.pulls.create({
178+
const { data: item } = await getOctokit(getEnv('GITHUB_PR_TOKEN')).rest.pulls.create({
173179
owner, repo, title, head: branchName, base, maintainer_can_modify: true,
174180
});
175181

0 commit comments

Comments
 (0)