Skip to content

Commit 8d264c0

Browse files
committed
feat(git-node): add limited support for cross-repo PRs
Node.js security patches are prepared on a separate repo, it can be useful to be able to run `git node land` without needing to touch the local config.
1 parent 5034b4f commit 8d264c0

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

lib/landing_session.js

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,38 @@ export default class LandingSession extends Session {
8282
}
8383

8484
async downloadAndPatch() {
85-
const { cli, upstream, prid, expectedCommitShas } = this;
85+
const { cli, upstream, prid, expectedCommitShas, crossRepoPR } = this;
86+
87+
if (crossRepoPR) {
88+
const { owner, repo } = this;
89+
cli.warn(`The configured remote "${upstream}" does not point to the ` +
90+
'Pull Request repository.');
91+
const isHeadAMergeCommit = () => {
92+
try {
93+
return runSync('git', ['rev-parse', 'FETCH_HEAD^2']).trim();
94+
} catch {}
95+
};
96+
do {
97+
cli.warn('Fetching commits from a different upstream might require user intervention.');
98+
99+
cli.info('Run the following command to fetch the commit(s):');
100+
cli.info(`git fetch git@github.com:${owner}/${repo}.git refs/pull/${prid}/merge`);
101+
const response = await cli.prompt('Should NCU run the command for you?',
102+
{ defaultAnswer: false });
103+
if (response) {
104+
cli.startSpinner(`Downloading patch for ${prid}`);
105+
await forceRunAsync('git',
106+
['fetch', `git@github.com:${owner}/${repo}.git`, `refs/pull/${prid}/merge`],
107+
{ ignoreFailure: false });
108+
}
109+
} while (!isHeadAMergeCommit());
110+
} else {
111+
cli.startSpinner(`Downloading patch for ${prid}`);
112+
await runAsync('git', [
113+
'fetch', upstream,
114+
`refs/pull/${prid}/merge`]);
115+
}
86116

87-
cli.startSpinner(`Downloading patch for ${prid}`);
88-
await runAsync('git', [
89-
'fetch', upstream,
90-
`refs/pull/${prid}/merge`]);
91117
// We fetched the commit that would result if we used `git merge`.
92118
// ^1 and ^2 refer to the PR base and the PR head, respectively.
93119
const [base, head] = await runAsync('git',
@@ -472,7 +498,7 @@ export default class LandingSession extends Session {
472498
}
473499

474500
cli.separator();
475-
cli.log('The following commits are ready to be pushed to ' +
501+
cli.log('The following commits are landable on ' +
476502
`${upstream}/${branch}`);
477503
cli.log(`- ${strayVerbose.join('\n- ')}`);
478504
cli.separator();
@@ -483,8 +509,15 @@ export default class LandingSession extends Session {
483509
willBeLanded = `${head}...${willBeLanded}`;
484510
}
485511

512+
cli.startSpinner('Removing temporary files');
486513
this.cleanFiles();
487-
cli.log('Temporary files removed.');
514+
cli.stopSpinner('Temporary files removed.');
515+
if (this.crossRepoPR) {
516+
cli.warn(`The configured remote "${upstream}" does not point to the ` +
517+
'Pull Request repository.');
518+
cli.info(`${willBeLanded} should likely not be pushed to "${upstream}"`);
519+
return;
520+
}
488521
cli.log('To finish landing:');
489522
cli.log('1. Run: ');
490523
cli.log(` git push ${upstream} ${branch}`);

lib/session.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ export default class Session {
3333
const upstreamHref = runSync('git', [
3434
'config', '--get',
3535
`remote.${upstream}.url`]).trim();
36-
if (!new RegExp(`${owner}/${repo}(?:.git)?$`).test(upstreamHref)) {
36+
if (!upstreamHref.endsWith(`${owner}/${repo}.git`) &&
37+
!upstreamHref.endsWith(`${owner}/${repo}`)) {
3738
cli.warn('Remote repository URL does not point to the expected ' +
3839
`repository ${owner}/${repo}`);
39-
cli.setExitCode(1);
40+
this.crossRepoPR = true;
4041
}
4142
}
4243
}

0 commit comments

Comments
 (0)