Skip to content

Commit

Permalink
Add tests to cover pull request auto-merge
Browse files Browse the repository at this point in the history
  • Loading branch information
dgellow committed Sep 15, 2023
1 parent 8310594 commit 53b0d1b
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 3 deletions.
34 changes: 34 additions & 0 deletions __snapshots__/github.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export interface GitHubOptions {
octokitAPIs: OctokitAPIs;
logger?: Logger;
useGraphql?: boolean;
graphqlRetries?: number;
}

interface ProxyOption {
Expand All @@ -92,6 +93,7 @@ interface GitHubCreateOptions {
useGraphql?: boolean;
retries?: number;
throttlingRetries?: number;
graphqlRetries?: number;
}

type CommitFilter = (commit: Commit) => boolean;
Expand Down Expand Up @@ -248,6 +250,7 @@ export class GitHub {
private fileCache: RepositoryFileCache;
private logger: Logger;
private useGraphql: boolean;
private graphqlRetries: number;

private constructor(options: GitHubOptions) {
this.repository = options.repository;
Expand All @@ -257,6 +260,7 @@ export class GitHub {
this.fileCache = new RepositoryFileCache(this.octokit, this.repository);
this.logger = options.logger ?? defaultLogger;
this.useGraphql = options.useGraphql ?? true;
this.graphqlRetries = options.graphqlRetries ?? 5;

// required to be able to rely on functions from code-suggester
setupLogger(this.logger);
Expand Down Expand Up @@ -373,7 +377,7 @@ export class GitHub {
}),
};

const opts = {
const opts: GitHubOptions = {
repository: {
owner: options.owner,
repo: options.repo,
Expand All @@ -388,6 +392,7 @@ export class GitHub {
octokitAPIs: apis,
logger,
useGraphql: options.useGraphql,
graphqlRetries: options.graphqlRetries,
};
return new GitHub(opts);
}
Expand Down Expand Up @@ -745,7 +750,7 @@ export class GitHub {
maxRetries?: number;
}
) => {
let maxRetries = options?.maxRetries ?? 5;
let maxRetries = options?.maxRetries ?? this.graphqlRetries;
let seconds = 1;
while (maxRetries >= 0) {
try {
Expand Down Expand Up @@ -2388,7 +2393,7 @@ export class GitHub {
this.logger.debug(
'PR can be merged directly, do it instead of via GitHub auto-merge'
);
this.octokit.pulls.merge({
await this.octokit.pulls.merge({
owner: this.repository.owner,
repo: this.repository.repo,
pull_number: pullRequestNumber,
Expand Down
211 changes: 211 additions & 0 deletions test/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ describe('GitHub', () => {
owner: 'fake',
repo: 'fake',
defaultBranch: 'main',
graphqlRetries: 0,
retries: 0,
throttlingRetries: 0,
});

// This shared nock will take care of some common requests.
Expand Down Expand Up @@ -1171,6 +1174,104 @@ describe('GitHub', () => {
req.done();
});

it('handles auto-merge option', async () => {
const forkBranchStub = sandbox
.stub(github, <any>'forkBranch') // eslint-disable-line @typescript-eslint/no-explicit-any
.withArgs('release-please--branches--main--changes--next', 'next')
.resolves('the-pull-request-branch-sha');

const commitAndPushStub = sandbox
.stub(codeSuggesterCommitAndPush, 'commitAndPush')
.withArgs(
sinon.match.any,
'the-pull-request-branch-sha',
sinon.match.any,
sinon.match.has(
'branch',
'release-please--branches--main--changes--next'
),
sinon.match.string,
true
)
.resolves();

const getPullRequestStub = sandbox
.stub(github, 'getPullRequest')
.withArgs(123)
.resolves({
title: 'updated-title',
headBranchName: 'release-please--branches--main--changes--next',
baseBranchName: 'main',
number: 123,
body: 'updated body',
labels: [],
files: [],
});

req
.patch('/repos/fake/fake/pulls/123')
.reply(200, {
number: 123,
title: 'updated-title',
body: 'updated body',
labels: [],
head: {
ref: 'release-please--branches--main--changes--next',
},
base: {
ref: 'main',
},
})
.post('/graphql', body => {
snapshot(body);
expect(body.query).to.contain('query pullRequestId');
expect(body.variables).to.eql({
owner: 'fake',
repo: 'fake',
pullRequestNumber: 123,
});
return true;
})
.reply(200, {
data: {
repository: {
pullRequest: {
id: 'someIdForPR123',
},
},
},
})
.post('/graphql', body => {
snapshot(body);
expect(body.query).to.contain('mutation mutateEnableAutoMerge');
expect(body.variables).to.eql({
pullRequestId: 'someIdForPR123',
mergeMethod: 'REBASE',
});
return true;
})
.reply(200, {});

const pullRequest = {
title: PullRequestTitle.ofTargetBranch('main', 'next'),
body: new PullRequestBody(mockReleaseData(1000), {
useComponents: true,
}),
labels: [],
headRefName: 'release-please--branches--main--changes--next',
draft: false,
updates: [],
};

await github.updatePullRequest(123, pullRequest, 'main', 'next', {
autoMerge: {mergeMethod: 'rebase'},
});
sinon.assert.calledOnce(forkBranchStub);
sinon.assert.calledOnce(commitAndPushStub);
sinon.assert.calledOnce(getPullRequestStub);
req.done();
});

it('handles a PR body that is too big', async () => {
const commitAndPushStub = sandbox
.stub(codeSuggesterCommitAndPush, 'commitAndPush')
Expand Down Expand Up @@ -1225,6 +1326,116 @@ describe('GitHub', () => {
});
});

describe('createPullRequest', () => {
it('handles auto-merge option', async () => {
const forkBranchStub = sandbox
.stub(github, <any>'forkBranch') // eslint-disable-line @typescript-eslint/no-explicit-any
.withArgs('release-please--branches--main--changes--next', 'next')
.resolves('the-pull-request-branch-sha');

const commitAndPushStub = sandbox
.stub(codeSuggesterCommitAndPush, 'commitAndPush')
.withArgs(
sinon.match.any,
'the-pull-request-branch-sha',
sinon.match.any,
sinon.match.has(
'branch',
'release-please--branches--main--changes--next'
),
sinon.match.string,
true
)
.resolves();

const getPullRequestStub = sandbox
.stub(github, 'getPullRequest')
.withArgs(123)
.resolves({
title: 'updated-title',
headBranchName: 'release-please--branches--main--changes--next',
baseBranchName: 'main',
number: 123,
body: 'updated body',
labels: [],
files: [],
});

req
.post('/repos/fake/fake/pulls')
.reply(200, {
number: 123,
title: 'create pr title',
body: 'created pr body',
labels: [],
head: {
ref: 'release-please--branches--main--changes--next',
},
base: {
ref: 'main',
},
})
.post('/graphql', body => {
snapshot(body);
expect(body.query).to.contain('query pullRequestId');
expect(body.variables).to.eql({
owner: 'fake',
repo: 'fake',
pullRequestNumber: 123,
});
return true;
})
.reply(200, {
data: {
repository: {
pullRequest: {
id: 'someIdForPR123',
},
},
},
})
.post('/graphql', body => {
snapshot(body);
expect(body.query).to.contain('mutation mutateEnableAutoMerge');
expect(body.variables).to.eql({
pullRequestId: 'someIdForPR123',
mergeMethod: 'REBASE',
});
return true;
})
.reply(200, {});

const pullRequest: PullRequest = {
title: PullRequestTitle.ofTargetBranch('main', 'next').toString(),
body: new PullRequestBody(mockReleaseData(1000), {
useComponents: true,
}).toString(),
labels: [],
headBranchName: 'release-please--branches--main--changes--next',
baseBranchName: 'main',
number: 123,
files: [],
};

await github.createPullRequest(
pullRequest,
'main',
'next',
'some changes',
[],
{
autoMerge: {mergeMethod: 'rebase'},
}
);

req.done();

sinon.assert.calledOnce(forkBranchStub);
sinon.assert.calledOnce(commitAndPushStub);
sinon.assert.calledOnce(getPullRequestStub);
});
});

describe('isBranchASyncedWithB', () => {
it('returns true if branch A is ahead', async () => {
req = req
Expand Down

0 comments on commit 53b0d1b

Please sign in to comment.