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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Prow Github Actions ⛵️

This project is inspired by [Prow](https://github.com/kubernetes/test-infra/tree/master/prow) and brings it's chat-ops functionality and project management to a simple, Github actions workflow.
This project is inspired by [Prow](https://github.com/kubernetes/test-infra/tree/master/prow) and brings its chat-ops functionality and project management to a simple, Github actions workflow.

> Prow is a Kubernetes based CI/CD system ... and provides GitHub automation in the form of policy enforcement, chat-ops via /foo style commands, and automatic PR merging.

Expand Down
155 changes: 149 additions & 6 deletions __tests__/issueCommentTest/approve.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import nock from 'nock'

import {handleIssueComment} from '../../src/issueComment/handleIssueComment'
import { approve } from '../../src/issueComment/approve'

import * as utils from '../testUtils'

import pullReqListReviews from '../fixtures/pullReq/pullReqListReviews.json'
Expand All @@ -13,8 +15,72 @@ describe('/approve', () => {
nock.cleanAll()
utils.setupActionsEnv('/approve')
})
afterEach(()=>{
if (!nock.isDone()) {
throw new Error(
`Not all nock interceptors were used: ${JSON.stringify(
nock.pendingMocks()
)}`
)
}
})

it('throws if commenter is not an approver in OWNERS', async () => {
const owners = Buffer.from(`
reviewers:
- Codertocat
`).toString('base64')

const contentResponse = {
type: "file",
encoding: "base64",
size: 4096,
name: "OWNERS",
path: "OWNERS",
content: owners
}

nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(200, contentResponse)

issueCommentEventAssign.comment.body = '/approve'
const commentContext = new utils.mockContext(issueCommentEventAssign)

expect(() => approve(commentContext))
.rejects.toThrowError('Codertocat is not included in the approvers role in the OWNERS file')
})

it('throws if commenter is not an org member or collaborator', async () => {
nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(404)

issueCommentEventAssign.comment.body = '/approve'
const commentContext = new utils.mockContext(issueCommentEventAssign)

expect(() => approve(commentContext))
.rejects.toThrowError('Codertocat is not a org member or collaborator')
})

it('approves if commenter is an approver in OWNERS', async () => {
const owners = Buffer.from(`
approvers:
- Codertocat
`).toString('base64')

const contentResponse = {
type: "file",
encoding: "base64",
size: 4096,
name: "OWNERS",
path: "OWNERS",
content: owners
}
nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(200, contentResponse)

it('approves the pr with /approve command', async () => {
nock(utils.api)
.post('/repos/Codertocat/Hello-World/pulls/1/reviews', body => {
expect(body).toMatchObject({
Expand All @@ -28,11 +94,90 @@ describe('/approve', () => {
const commentContext = new utils.mockContext(issueCommentEventAssign)

await handleIssueComment(commentContext)
expect(nock.isDone()).toBe(true)
expect.assertions(2)
})

it('removes approval with the /approve cancel command', async () => {
it('approves if commenter is an org member', async () => {
nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(404)

nock(utils.api)
.get('/orgs/Codertocat/members/Codertocat')
.reply(204)

nock(utils.api)
.get('/repos/Codertocat/Hello-World/collaborators/Codertocat')
.reply(404)

nock(utils.api)
.post('/repos/Codertocat/Hello-World/pulls/1/reviews', body => {
expect(body).toMatchObject({
event: 'APPROVE'
})
return true
})
.reply(200)

issueCommentEventAssign.comment.body = '/approve'
const commentContext = new utils.mockContext(issueCommentEventAssign)

await handleIssueComment(commentContext)
})

it('removes approval with the /approve cancel command if approver in OWNERS file', async () => {
const owners = Buffer.from(`
approvers:
- some-user
`).toString('base64')

const contentResponse = {
type: "file",
encoding: "base64",
size: 4096,
name: "OWNERS",
path: "OWNERS",
content: owners
}
nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(200, contentResponse)

nock(utils.api)
.get('/repos/Codertocat/Hello-World/pulls/1/reviews')
.reply(200, pullReqListReviews)

nock(utils.api)
.put(
'/repos/Codertocat/Hello-World/pulls/1/reviews/80/dismissals',
body => {
expect(body).toMatchObject({
message: `Canceled through prow-github-actions by @some-user`
})
return true
}
)
.reply(200)

issueCommentEventAssign.comment.body = '/approve cancel'
issueCommentEventAssign.comment.user.login = 'some-user'
const commentContext = new utils.mockContext(issueCommentEventAssign)

await handleIssueComment(commentContext)
})

it('removes approval with the /approve cancel command if commenter is collaborator', async () => {
nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(404)

nock(utils.api)
.get('/orgs/Codertocat/members/some-user')
.reply(404)

nock(utils.api)
.get('/repos/Codertocat/Hello-World/collaborators/some-user')
.reply(204)

nock(utils.api)
.get('/repos/Codertocat/Hello-World/pulls/1/reviews')
.reply(200, pullReqListReviews)
Expand All @@ -54,7 +199,5 @@ describe('/approve', () => {
const commentContext = new utils.mockContext(issueCommentEventAssign)

await handleIssueComment(commentContext)
expect(nock.isDone()).toBe(true)
expect.assertions(2)
})
})
95 changes: 80 additions & 15 deletions __tests__/label/lgtm.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import nock from 'nock'

import {handleIssueComment} from '../../src/issueComment/handleIssueComment'
import * as core from '@actions/core'
import { lgtm } from '../../src/labels/lgtm'

import * as utils from '../testUtils'

import issueCommentEvent from '../fixtures/issues/issueCommentEvent.json'
import labelFileContents from '../fixtures/labels/labelFileContentsResp.json'
import issuePayload from '../fixtures/issues/issue.json'

nock.disableNetConnect()
Expand All @@ -15,6 +15,15 @@ describe('lgtm', () => {
nock.cleanAll()
utils.setupActionsEnv('/lgtm')
})
afterEach(()=>{
if (!nock.isDone()) {
throw new Error(
`Not all nock interceptors were used: ${JSON.stringify(
nock.pendingMocks()
)}`
)
}
})

it('labels the issue with the lgtm label', async () => {
issueCommentEvent.comment.body = '/lgtm'
Expand All @@ -36,11 +45,14 @@ describe('lgtm', () => {
.get('/repos/Codertocat/Hello-World/collaborators/Codertocat')
.reply(404)

nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(404)

await handleIssueComment(commentContext)
expect(parsedBody).toEqual({
labels: ['lgtm']
})
expect(nock.isDone()).toBe(true)
})

it('removes the lgtm label with /lgtm cancel', async () => {
Expand Down Expand Up @@ -73,11 +85,14 @@ describe('lgtm', () => {
.get('/repos/Codertocat/Hello-World/collaborators/Codertocat')
.reply(404)

nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(404)

await handleIssueComment(commentContext)
expect(nock.isDone()).toBe(true)
})

it('adds label if commentor is collaborator', async () => {
it('adds label if commenter is collaborator', async () => {
issueCommentEvent.comment.body = '/lgtm'
const commentContext = new utils.mockContext(issueCommentEvent)

Expand All @@ -97,14 +112,54 @@ describe('lgtm', () => {
.get('/repos/Codertocat/Hello-World/collaborators/Codertocat')
.reply(204)

nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(404)

await handleIssueComment(commentContext)
expect(parsedBody).toEqual({
labels: ['lgtm']
})
expect(nock.isDone()).toBe(true)
})

it('throws if commentor is not org member or collaborator', async () => {
it('throws if commenter is not reviewer in OWNERS', async () => {
const owners = Buffer.from(`
approvers:
- Codertocat
`).toString('base64')

const contentResponse = {
type: "file",
encoding: "base64",
size: 4096,
name: "OWNERS",
path: "OWNERS",
content: owners
}
nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(200, contentResponse)

issueCommentEvent.comment.body = '/lgtm'
const commentContext = new utils.mockContext(issueCommentEvent)

expect(() => lgtm(commentContext))
.rejects.toThrowError('Codertocat is not included in the reviewers role in the OWNERS file')
})

it('throws if commenter is not org member or collaborator', async () => {
nock(utils.api)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(404)

issueCommentEvent.comment.body = '/lgtm'
const commentContext = new utils.mockContext(issueCommentEvent)

expect(() => lgtm(commentContext))
.rejects.toThrowError('Codertocat is not a org member or collaborator')
})

it('adds label if commenter is reviewer in OWNERS', async() => {
issueCommentEvent.comment.body = '/lgtm'
const commentContext = new utils.mockContext(issueCommentEvent)

Expand All @@ -116,16 +171,26 @@ describe('lgtm', () => {
})
.reply(200)

const owners = Buffer.from(`
reviewers:
- Codertocat
`).toString('base64')

const contentResponse = {
type: "file",
encoding: "base64",
size: 4096,
name: "OWNERS",
path: "OWNERS",
content: owners
}
nock(utils.api)
.get('/orgs/Codertocat/members/Codertocat')
.reply(404)

nock(utils.api)
.get('/repos/Codertocat/Hello-World/collaborators/Codertocat')
.reply(404)
.get('/repos/Codertocat/Hello-World/contents/OWNERS')
.reply(200, contentResponse)

const spy = jest.spyOn(core, 'setFailed')
await handleIssueComment(commentContext)
expect(spy).toHaveBeenCalled()
expect(parsedBody).toEqual({
labels: ['lgtm']
})
})
})
Loading