Skip to content

Commit 169d499

Browse files
committed
use async execFile, update documentation
1 parent 8653556 commit 169d499

File tree

4 files changed

+106
-55
lines changed

4 files changed

+106
-55
lines changed

README.md

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ jobs:
4545
autoupdate:
4646
runs-on: ubuntu-latest
4747
steps:
48+
# This step is only necessary if you want to update branches from forks,
49+
# as it uses a completely different process (git) than updating branches from the same repository (api call).
50+
- name: Configure git
51+
run: |
52+
# The username of the "UPDATE_FORK_PAT" owner
53+
git config --global user.name "username"
54+
# The email of the "UPDATE_FORK_PAT" owner
55+
git config --global user.email "[email protected]"
4856
- uses: sequelize/pr-auto-update-and-handle-conflicts@v1
4957
with:
5058
conflict-label: 'conflicted'
@@ -56,13 +64,23 @@ jobs:
5664
update-excluded-authors: 'bot/renovate'
5765
update-excluded-labels: 'no-autoupdate'
5866
env:
59-
# The GITHUB_TOKEN will handle operations that the GitHub Bot can perform,
60-
# such as searching the repository, adding/removing labels, and drafting PRs.
67+
# The GITHUB_TOKEN to use for all operations, unless one of the two properties
68+
# below are specified.
6169
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
62-
# The PAT is used to perform operations that the GitHub Bot cannot perform: updating the PR branch
63-
# If not specified, the GITHUB_TOKEN will be used, in which case the GITHUB_TOKEN must be one
64-
# with the necessary permission to update the PR branch (assuming the feature is enabled).
65-
PAT: '${{ secrets.PAT }}'
70+
71+
# The default GITHUB_TOKEN does not cause the branch update to trigger subsequent workflows,
72+
# which means that CI checks will not run on the updated branch.
73+
# To solve this, you need to use a different token. Either one that belongs to a user, or to a GitHub App.
74+
# Defaults to the GITHUB_TOKEN env
75+
UPDATE_BRANCH_PAT: '${{ secrets.UPDATE_BRANCH_PAT }}'
76+
77+
# Same reasoning as UPDATE_BRANCH_PAT, but for updating branches from a fork.
78+
# This one _requires_ using a user PAT. A GitHub App PAT will not work if the update includes workflow files.
79+
# This token must have the Read & Write permissions for "contents" and "workflows"
80+
# If you do not want to update branches from forks, you can set the "update-requires-source" option to "branches"
81+
# Defaults to the GITHUB_TOKEN env
82+
UPDATE_FORK_PAT: '${{ secrets.PAT }}'
83+
UPDATE_FORK_USERNAME: 'ephys'
6684
```
6785
6886
## Options

action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ inputs:
5050
required: false
5151
default: ''
5252
update-requires-source:
53-
description: 'Only update PRs that are either forks or branches from the same repository. Accepts "all" (default), "forks", and "branches"'
53+
description: 'Only update PRs that are either forks or branches from the same repository. Accepts "all" (default), "forks", and "branch"'
5454
required: false
5555
default: 'all'
5656
dry-run:

lib/action.mjs

Lines changed: 17 additions & 17 deletions
Large diffs are not rendered by default.

src/action.ts

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ import core from '@actions/core';
22
import github from '@actions/github';
33
import type { PullRequestEvent, PushEvent } from '@octokit/webhooks-types';
44
import { isString } from '@sequelize/utils';
5-
import { execFileSync } from 'node:child_process';
5+
import childProcess from 'node:child_process';
66
import fs from 'node:fs/promises';
77
import * as path from 'node:path';
88
import { setTimeout } from 'node:timers/promises';
9+
import { promisify } from 'node:util';
10+
11+
const execFile = promisify(childProcess.execFile);
912

1013
isString.assert(process.env.GITHUB_TOKEN, 'GITHUB_TOKEN env must be provided');
1114

@@ -32,6 +35,10 @@ const updateBranchBot = process.env.UPDATE_BRANCH_PAT
3235
* We recommend using a user PAT for this, as:
3336
* - Using the GITHUB_TOKEN will not trigger subsequent workflows.
3437
* - Using a bot PAT will cause an error if the branch update includes a workflow file.
38+
*
39+
* This will need the following permissions:
40+
* - contents (read & write)
41+
* - workflows (read & write)
3542
*/
3643
const updateForkPat = process.env.UPDATE_FORK_PAT || process.env.GITHUB_TOKEN;
3744
const updateForkUsername = process.env.UPDATE_FORK_USERNAME || 'x-access-token';
@@ -73,7 +80,7 @@ const updateExcludedAuthors = getCommaSeparatedInput('update-excluded-authors');
7380
const updateRequiresSource = getEnumInput('update-requires-source', [
7481
'all',
7582
'fork',
76-
'branches',
83+
'branch',
7784
] as const);
7885

7986
interface RepositoryId {
@@ -305,22 +312,24 @@ async function updatePrBranch(repositoryId: RepositoryId, pullRequest: PullReque
305312

306313
updatedPrs.push(pullRequest.number);
307314

308-
console.info(`[PR ${pullRequest.number}] ✅ Updating branch.`);
309-
310315
if (dryRun) {
311316
return;
312317
}
313318

314319
// The "update-branch" endpoint does not allow modifying pull requests from repositories we do not own,
315320
// even if the "allow maintainers to modify" setting is enabled on the PR.
316321
if (!isForkPr(pullRequest)) {
322+
console.info(`[PR ${pullRequest.number}] ✅ Updating branch via API.`);
323+
317324
// This operation cannot be done with GITHUB_TOKEN, as the GITHUB_TOKEN does not trigger subsequent workflows.
318325
return updateBranchBot.rest.pulls.updateBranch({
319326
...repositoryId,
320327
pull_number: pullRequest.number,
321328
});
322329
}
323330

331+
console.info(`[PR ${pullRequest.number}] ✅ Updating fork via git.`);
332+
324333
// For fork PRs, we use git directly instead:
325334
// - Clone the repository in a new directory
326335
// - Merge the base branch into the PR branch
@@ -333,36 +342,60 @@ async function updatePrBranch(repositoryId: RepositoryId, pullRequest: PullReque
333342
const parentRepositoryUrl = `https://${updateForkUsername}:${updateForkPat}@github.com/${pullRequest.baseRepository.nameWithOwner}.git`;
334343

335344
// clone fork repository in the correct branch
336-
console.log(
337-
`git clone ${forkRepositoryUrl} ${targetDirectoryName} --branch ${pullRequest.headRef.name}`,
338-
);
339-
execFileSync(
340-
'git',
341-
['clone', forkRepositoryUrl, targetDirectoryName, '--branch', pullRequest.headRef.name],
342-
{
343-
stdio: 'inherit',
344-
},
345-
);
345+
{
346+
const { stdout, stderr } = await execFile('git', [
347+
'clone',
348+
'--quiet',
349+
forkRepositoryUrl,
350+
targetDirectoryName,
351+
'--branch',
352+
pullRequest.headRef.name,
353+
]);
354+
355+
stdout && console.info(`[PR ${pullRequest.number}] ${stdout}`);
356+
stderr && console.error(`[PR ${pullRequest.number}] ${stderr}`);
357+
}
346358

347359
// add parent repository as remote
348-
console.log(`git remote add parent ${parentRepositoryUrl}`);
349-
execFileSync('git', ['remote', 'add', 'parent', parentRepositoryUrl], {
350-
cwd: targetDirectoryPath,
351-
stdio: 'inherit',
352-
});
360+
{
361+
const { stdout, stderr } = await execFile(
362+
'git',
363+
['remote', 'add', 'parent', parentRepositoryUrl],
364+
{
365+
cwd: targetDirectoryPath,
366+
},
367+
);
368+
369+
stdout && console.info(`[PR ${pullRequest.number}] ${stdout}`);
370+
stderr && console.error(`[PR ${pullRequest.number}] ${stderr}`);
371+
}
353372

354373
// merge parent branch in local branch
355-
console.log(`git pull parent ${pullRequest.baseRef.name} --no-edit --no-rebase`);
356-
execFileSync('git', ['pull', 'parent', pullRequest.baseRef.name, '--no-edit', '--no-rebase'], {
357-
cwd: targetDirectoryPath,
358-
stdio: 'inherit',
359-
});
360-
361-
console.log(`git push origin ${pullRequest.headRef.name}`);
362-
execFileSync('git', ['push', 'origin', pullRequest.headRef.name], {
363-
cwd: targetDirectoryPath,
364-
stdio: 'inherit',
365-
});
374+
{
375+
const { stdout, stderr } = await execFile(
376+
'git',
377+
['pull', '--quiet', 'parent', pullRequest.baseRef.name, '--no-edit', '--no-rebase'],
378+
{
379+
cwd: targetDirectoryPath,
380+
},
381+
);
382+
383+
stdout && console.info(`[PR ${pullRequest.number}] ${stdout}`);
384+
stderr && console.error(`[PR ${pullRequest.number}] ${stderr}`);
385+
}
386+
387+
{
388+
const { stdout, stderr } = await execFile(
389+
'git',
390+
['push', '--quiet', 'origin', pullRequest.headRef.name],
391+
{
392+
cwd: targetDirectoryPath,
393+
},
394+
);
395+
396+
stdout && console.info(`[PR ${pullRequest.number}] ${stdout}`);
397+
stderr && console.error(`[PR ${pullRequest.number}] ${stderr}`);
398+
}
366399
}
367400

368401
async function handleConflict(repositoryId: RepositoryId, pullRequest: PullRequest): Promise<void> {
@@ -539,7 +572,7 @@ function prMatchesSource(pullRequest: PullRequest, source: typeof updateRequires
539572
case 'fork':
540573
return isForkPr(pullRequest);
541574

542-
case 'branches':
575+
case 'branch':
543576
return !isForkPr(pullRequest);
544577
}
545578
}

0 commit comments

Comments
 (0)