Skip to content

Commit aab0d49

Browse files
authored
Stale Notifications For Issues and Pulls (#57)
* update configuration to load defaults for pulls and issues stale settings. * Unit tests updated for handler and added stale. * update README with stale feature information.
1 parent 8ec8b59 commit aab0d49

11 files changed

+369
-102
lines changed

__fixtures__/helper.js

+8
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ module.exports = {
100100
},
101101
status: 'completed'
102102
}
103+
},
104+
105+
mockConfigWithContext: (context, configString) => {
106+
context.github.repos.getContent = () => {
107+
return Promise.resolve({ data: {
108+
content: Buffer.from(configString).toString('base64') }
109+
})
110+
}
103111
}
104112

105113
}

__tests__/configuration.test.js

+95-70
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ test('that Configuration validates root node in yml', () => {
1010
})
1111

1212
// write test to test for bad yml
13-
1413
test('that constructor loads settings correctly', () => {
1514
let config = new Configuration(`
1615
mergeable:
@@ -33,6 +32,7 @@ test('that defaults load correctly when mergeable is null', () => {
3332
expect(mergeable.title).toBe(Configuration.DEFAULTS.title)
3433
expect(mergeable.label).toBe(Configuration.DEFAULTS.label)
3534
expect(mergeable.exclude).toBe(undefined)
35+
expect(mergeable.stale).toBe(Configuration.DEFAULTS.stale)
3636
})
3737

3838
test('that defaults load correctly when mergeable has partial properties defined', () => {
@@ -48,29 +48,12 @@ test('that defaults load correctly when mergeable has partial properties defined
4848
})
4949

5050
test('that instanceWithContext returns the right Configuration', async () => {
51-
let context = {
52-
repo: jest.fn().mockReturnValue({
53-
repo: '',
54-
owner: ''
55-
}),
56-
payload: {
57-
pull_request: {
58-
number: 1
59-
}
60-
},
61-
github: {
62-
repos: {
63-
getContent: jest.fn().mockReturnValue(
64-
Promise.resolve({ data: { content: Buffer.from(`
65-
mergeable:
66-
approvals: 5
67-
label: 'label regex'
68-
title: 'title regex'
69-
`).toString('base64') }})
70-
)
71-
}
72-
}
73-
}
51+
let context = createMockGhConfig(`
52+
mergeable:
53+
approvals: 5
54+
label: 'label regex'
55+
title: 'title regex'
56+
`)
7457

7558
Configuration.instanceWithContext(context).then(config => {
7659
let mergeable = config.settings.mergeable
@@ -82,29 +65,12 @@ test('that instanceWithContext returns the right Configuration', async () => {
8265
})
8366

8467
test('that instanceWithContext returns the right Configuration (pull_requrests)', async () => {
85-
let context = {
86-
repo: jest.fn().mockReturnValue({
87-
repo: '',
88-
owner: ''
89-
}),
90-
payload: {
91-
pull_request: {
92-
number: 1
93-
}
94-
},
95-
github: {
96-
repos: {
97-
getContent: jest.fn().mockReturnValue(
98-
Promise.resolve({ data: { content: Buffer.from(`
99-
mergeable:
100-
pull_requests:
101-
label: 'label issue regex'
102-
title: 'title issue regex'
103-
`).toString('base64') }})
104-
)
105-
}
106-
}
107-
}
68+
let context = createMockGhConfig(`
69+
mergeable:
70+
pull_requests:
71+
label: 'label issue regex'
72+
title: 'title issue regex'
73+
`)
10874

10975
await Configuration.instanceWithContext(context).then(config => {
11076
let mergeable = config.settings.mergeable
@@ -117,29 +83,12 @@ test('that instanceWithContext returns the right Configuration (pull_requrests)'
11783
})
11884

11985
test('that instanceWithContext returns the right Configuration (issues)', async () => {
120-
let context = {
121-
repo: jest.fn().mockReturnValue({
122-
repo: '',
123-
owner: ''
124-
}),
125-
payload: {
126-
pull_request: {
127-
number: 1
128-
}
129-
},
130-
github: {
131-
repos: {
132-
getContent: jest.fn().mockReturnValue(
133-
Promise.resolve({ data: { content: Buffer.from(`
134-
mergeable:
135-
issues:
136-
label: 'label issue regex'
137-
title: 'title issue regex'
138-
`).toString('base64') }})
139-
)
140-
}
141-
}
142-
}
86+
let context = createMockGhConfig(`
87+
mergeable:
88+
issues:
89+
label: 'label issue regex'
90+
title: 'title issue regex'
91+
`)
14392

14493
await Configuration.instanceWithContext(context).then(config => {
14594
let mergeable = config.settings.mergeable
@@ -151,6 +100,58 @@ test('that instanceWithContext returns the right Configuration (issues)', async
151100
expect(context.github.repos.getContent.mock.calls.length).toBe(1)
152101
})
153102

103+
test('that instanceWithContext loads the configuration for stale correctly when specified for pull_requests and issues separately', async () => {
104+
let context = createMockGhConfig(`
105+
mergeable:
106+
pull_requests:
107+
label: 'label issue regex'
108+
title: 'title issue regex'
109+
stale:
110+
days: 20
111+
`)
112+
113+
await Configuration.instanceWithContext(context).then(config => {
114+
let mergeable = config.settings.mergeable
115+
expect(mergeable.pull_requests.stale !== undefined).toBe(true)
116+
expect(mergeable.pull_requests.stale.days).toBe(20)
117+
expect(mergeable.pull_requests.stale.message).toBe(Configuration.DEFAULTS.stale.message)
118+
})
119+
120+
context = createMockGhConfig(`
121+
mergeable:
122+
issues:
123+
stale:
124+
days: 20
125+
`)
126+
127+
await Configuration.instanceWithContext(context).then(config => {
128+
let mergeable = config.settings.mergeable
129+
expect(mergeable.issues.stale !== undefined).toBe(true)
130+
expect(mergeable.issues.stale.days).toBe(20)
131+
expect(mergeable.issues.stale.message).toBe(Configuration.DEFAULTS.stale.message)
132+
})
133+
134+
context = createMockGhConfig(`
135+
mergeable:
136+
issues:
137+
stale:
138+
days: 20
139+
message: Issue test
140+
pull_requests:
141+
stale:
142+
days: 20
143+
message: PR test
144+
`)
145+
146+
await Configuration.instanceWithContext(context).then(config => {
147+
let mergeable = config.settings.mergeable
148+
expect(mergeable.issues.stale !== undefined).toBe(true)
149+
expect(mergeable.issues.stale.days).toBe(20)
150+
expect(mergeable.issues.stale.message).toBe('Issue test')
151+
expect(mergeable.pull_requests.stale.message).toBe('PR test')
152+
})
153+
})
154+
154155
test('that instanceWithContext still returns the Configuration when repo does not content mergeable.yml', async () => {
155156
let context = {
156157
repo: () => {
@@ -187,6 +188,30 @@ test('that instanceWithContext still returns the Configuration when repo does no
187188
expect(context.github.repos.getContent.mock.calls.length).toBe(1)
188189
})
189190

191+
// helper method to return mocked configiration.
192+
const createMockGhConfig = (json) => {
193+
return {
194+
repo: jest.fn().mockReturnValue({
195+
repo: '',
196+
owner: ''
197+
}),
198+
payload: {
199+
pull_request: {
200+
number: 1
201+
}
202+
},
203+
github: {
204+
repos: {
205+
getContent: jest.fn().mockReturnValue(
206+
Promise.resolve({
207+
data: { content: Buffer.from(json).toString('base64') }
208+
})
209+
)
210+
}
211+
}
212+
}
213+
}
214+
190215
// to mimic HttpError (https://github.com/octokit/rest.js/blob/fc8960ccf3415b5d77e50372d3bb873cfec80c55/lib/request/http-error.js)
191216
class HttpError extends Error {
192217
constructor (message, code, status) {

__tests__/handler.test.js

+67-13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,54 @@ const Handler = require('../lib/handler')
33
const Configuration = require('../lib/configuration')
44
Configuration.DEFAULTS.approvals = 0
55

6+
test('handleStale calls search.issues only when settings exists for days', async () => {
7+
// setup context with no added configuration.
8+
let context = mockContext('title')
9+
const expectMockCalls = async (config, expected) => {
10+
mockConfigWithContext(context, config)
11+
await Handler.handleStale(context)
12+
expect(context.github.search.issues.mock.calls.length).toBe(expected)
13+
context.github.search.issues.mockClear()
14+
}
15+
16+
context.github.search = {
17+
issues: jest.fn().mockReturnValue({
18+
data: { items: [] }
19+
})
20+
}
21+
22+
await Handler.handleStale(context)
23+
expect(context.github.search.issues.mock.calls.length).toBe(0)
24+
context.github.search.issues.mockClear()
25+
26+
// setup context with PR configuration.
27+
await expectMockCalls(`
28+
mergeable:
29+
pull_requests:
30+
stale:
31+
days: 10
32+
`, 1)
33+
34+
// setup context with issues configuration.
35+
await expectMockCalls(`
36+
mergeable:
37+
issues:
38+
stale:
39+
days: 10
40+
`, 1)
41+
42+
// setup context with both issues and pr configuration.
43+
await expectMockCalls(`
44+
mergeable:
45+
issues:
46+
stale:
47+
days: 10
48+
pull_requests:
49+
stale:
50+
days: 10
51+
`, 2)
52+
})
53+
654
test('handlePullRequest when it is mergeable', async () => {
755
let context = mockContext('title')
856
await expectSuccessStatus(context)
@@ -32,26 +80,24 @@ test('one exclude configuration will exclude the validation', async () => {
3280
let context = Helper.mockContext({ title: 'wip', body: 'body' })
3381
context.repo = mockRepo()
3482

35-
context.github.repos.getContent = () => {
36-
return Promise.resolve({ data: { content: Buffer.from(`
37-
mergeable:
38-
approvals: 0
39-
exclude: 'title'
40-
`).toString('base64') }})
41-
}
83+
mockConfigWithContext(context, `
84+
mergeable:
85+
approvals: 0
86+
exclude: 'title'
87+
`)
88+
4289
await expectSuccessStatus(context)
4390
})
4491

4592
test('more than one exclude configuration will exclude the validation', async () => {
4693
let context = Helper.mockContext({ title: 'wip', label: ['proof of concept'], body: 'body' })
4794
context.repo = mockRepo()
4895

49-
context.github.repos.getContent = () => {
50-
return Promise.resolve({ data: { content: Buffer.from(`
51-
mergeable:
52-
exclude: 'approvals, title, label'
53-
`).toString('base64') }})
54-
}
96+
mockConfigWithContext(context, `
97+
mergeable:
98+
exclude: 'approvals, title, label'
99+
`)
100+
55101
await expectSuccessStatus(context)
56102
})
57103

@@ -66,6 +112,14 @@ const expectSuccessStatus = async (context) => {
66112
})
67113
}
68114

115+
const mockConfigWithContext = (context, configString) => {
116+
context.github.repos.getContent = () => {
117+
return Promise.resolve({ data: {
118+
content: Buffer.from(configString).toString('base64') }
119+
})
120+
}
121+
}
122+
69123
const mockContext = (title) => {
70124
let context = Helper.mockContext({ title: title, body: 'body' })
71125
context.repo = mockRepo()

__tests__/projects.test.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ const createMockPR = ({description, number}) => {
3333

3434
const createMockContext = (data) => {
3535
const repoProjects = [
36-
{name: 'Project One', id: 1},
37-
{name: 'Porject Two', id: 2}
36+
{name: 'Project One', id: 1},
37+
{name: 'Porject Two', id: 2}
3838
]
3939
const projectColumns = [
40-
{id: 1}
40+
{id: 1}
4141
]
4242
const projectCards = [
43-
{content_url: 'testRepo/issues/1'},
44-
{content_url: 'testRepo/issues/2'}
43+
{content_url: 'testRepo/issues/1'},
44+
{content_url: 'testRepo/issues/2'}
4545
]
4646

4747
return Helper.mockContext({repoProjects: repoProjects, projectColumns: projectColumns, projectCards: projectCards})

0 commit comments

Comments
 (0)