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
44 changes: 44 additions & 0 deletions __tests__/bundle/bundle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,50 @@ describe('dist/index.js', () => {
expectRequests(configReads(), [pullRead, ownersProbe, graphql])
})

it('a GraphQL error on the state read (a GHES without the queue fields) warns once and falls back to the direct merge', async () => {
gh.commitStatuses(repo, head, bound)
gh.route('GET', `${repo}/pulls/1`, { status: 200, body: mergeablePr('clean') })
gh.route('PUT', `${repo}/pulls/1/merge`, { status: 200, body: { merged: true } })
gh.mergeQueue({ pullRequestId: nodeId, headOid: head, enabled: true, queryError: 'Field \'isMergeQueueEnabled\' doesn\'t exist on type \'PullRequest\'' })

const result = await runPullRequest(labeledLgtm())

expect(result.status, result.stdout).toBe(0)
expect(result.errors).toEqual([])
expect(result.stdout).toContain('merged pr #1')
const warnings = result.stdout.split('\n').filter(line => line.startsWith('::warning::'))
expect(warnings.filter(w => w.includes('falling back to a direct merge'))).toHaveLength(1)
expectRequests(configReads(), [bind, pullRead, ownersProbe, bindingRead, graphql, merge])
})

it('an enqueue the token may not perform fails the run naming the permissions; no PUT merge', async () => {
gh.commitStatuses(repo, head, bound)
gh.route('GET', `${repo}/pulls/1`, { status: 200, body: mergeablePr('clean') })
gh.mergeQueue({ pullRequestId: nodeId, headOid: head, enabled: true, enqueueError: 'Resource not accessible by integration' })

const result = await runPullRequest(labeledLgtm())

expect(result.status, result.stdout).toBe(1)
expect(result.errors.some(e => e.includes('the token may not enqueue'))).toBe(true)
expect(result.errors.some(e => e.includes('automatic-merging.md#merge-queues'))).toBe(true)
expect(gh.requestsMatching('PUT', /./)).toEqual([])
expectRequests(configReads(), [bind, pullRead, ownersProbe, bindingRead, graphql, graphql])
})

it('pull_request unlabeled lgtm when the dequeue is refused: warns, leaves the entry, exits 0', async () => {
gh.route('GET', `${repo}/pulls/1`, { status: 200, body: mergeablePr('clean', []) })
gh.mergeQueue({ pullRequestId: nodeId, headOid: head, enabled: true, inQueue: true, entry: { state: 'AWAITING_CHECKS', position: 1, enqueuer: 'github-actions' }, dequeueError: 'Resource not accessible by integration' })

const result = await runBundle({ eventName: 'pull_request', payload: { ...pullReqOpenedEvent, action: 'unlabeled', label: { name: 'lgtm' } }, inputs: token, apiUrl: gh.url })

expect(result.status, result.stdout).toBe(0)
expect(result.errors).toEqual([])
expect(result.stdout).toContain('::warning::could not dequeue pr #1: Resource not accessible by integration')
expect(result.stdout).not.toContain('(dequeued)')
expect(gh.graphqlCalls('dequeuePullRequest')).toHaveLength(1)
expectRequests(configReads(), [pullRead, ownersProbe, graphql, graphql])
})

it('schedule jobs: lgtm enqueues a queue-branch pr and never dequeues a gate-failing one', async () => {
gh.route('GET', repo, { status: 200, body: { default_branch: 'master' } })
gh.route('GET', new RegExp(`^${repo}/pulls\\?`), (req) => {
Expand Down
11 changes: 10 additions & 1 deletion __tests__/bundle/fakeGithub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ export interface MergeQueueFixture {
enabled: boolean
inQueue?: boolean
entry?: { state: string, position: number, enqueuer: string }
/** GraphQL error message for the enqueue mutation */
enqueueError?: string
/** GraphQL error message for the state query */
queryError?: string
/** GraphQL error message for the dequeue mutation */
dequeueError?: string
}

export interface FakeGithub {
Expand Down Expand Up @@ -156,8 +161,12 @@ function mergeQueueRoute(queue: MergeQueueFixture): Route {
: { status: 200, body: { data: null, errors: [{ message: queue.enqueueError }] } }
}
if (query.includes('dequeuePullRequest')) {
return { status: 200, body: { data: { dequeuePullRequest: { mergeQueueEntry: { state: 'QUEUED', position: 1 } } } } }
return queue.dequeueError === undefined
? { status: 200, body: { data: { dequeuePullRequest: { mergeQueueEntry: { state: 'QUEUED', position: 1 } } } } }
: { status: 200, body: { data: null, errors: [{ message: queue.dequeueError }] } }
}
if (queue.queryError !== undefined)
return { status: 200, body: { data: null, errors: [{ message: queue.queryError }] } }
const entry = queue.entry
return { status: 200, body: { data: { repository: { pullRequest: {
id: queue.pullRequestId,
Expand Down
Loading