forked from probot/scheduler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
116 lines (90 loc) · 3.29 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
const Bottleneck = require('bottleneck')
const limiter = new Bottleneck({ maxConcurrent: 1, minTime: 0 })
const ignoredAccounts = (process.env.IGNORED_ACCOUNTS || '')
.toLowerCase()
.split(',')
const defaults = {
delay: !process.env.DISABLE_DELAY, // Should the first run be put on a random delay?
interval: 60 * 60 * 1000 // 1 hour
}
module.exports = (app, options) => {
options = Object.assign({}, defaults, options || {})
const intervals = {}
// https://developer.github.com/v3/activity/events/types/#installationrepositoriesevent
app.on('installation.created', async event => {
const installation = event.payload.installation
eachRepository(installation, repository => {
schedule(installation, repository)
})
})
// https://developer.github.com/v3/activity/events/types/#installationrepositoriesevent
app.on('installation_repositories.added', async event => {
return setupInstallation(event.payload.installation)
})
setup()
function setup () {
return eachInstallation(setupInstallation)
}
function setupInstallation (installation) {
if (ignoredAccounts.includes(installation.account.login.toLowerCase())) {
app.log.info({ installation }, 'Installation is ignored')
return
}
limiter.schedule(eachRepository, installation, repository => {
schedule(installation, repository)
})
}
function schedule (installation, repository) {
if (intervals[repository.id]) {
return
}
// Wait a random delay to more evenly distribute requests
const delay = options.delay ? options.interval * Math.random() : 0
app.log.debug({ repository, delay, interval: options.interval }, `Scheduling interval`)
intervals[repository.id] = setTimeout(() => {
const event = {
name: 'schedule',
payload: { action: 'repository', installation, repository }
}
// Trigger events on this repository on an interval
intervals[repository.id] = setInterval(
() => app.receive(event),
options.interval
)
// Trigger the first event now
app.receive(event)
}, delay)
}
async function eachInstallation (callback) {
app.log.trace('Fetching installations')
const github = await app.auth()
const installations = await github.paginate(
github.apps.listInstallations.endpoint.merge({ per_page: 100 })
)
const filteredInstallations = options.filter
? installations.filter(inst => options.filter(inst))
: installations
return filteredInstallations.forEach(callback)
}
async function eachRepository (installation, callback) {
app.log.trace({ installation }, 'Fetching repositories for installation')
const github = await app.auth(installation.id)
const repositories = await github.paginate(
github.apps.listRepos.endpoint.merge({ per_page: 100 }),
response => {
return response.data.repositories
}
)
const filteredRepositories = options.filter
? repositories.filter(repo => options.filter(installation, repo))
: repositories
return filteredRepositories.forEach(async repository =>
callback(repository, github)
)
}
function stop (repository) {
app.log.info({ repository }, `Canceling interval`)
clearInterval(intervals[repository.id])
}
return { stop }
}