-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: send reminder comment to stale initial PRs
Turns out some of our users are confused why Greenkeeper is not enabled for their repos and it turns out, it's because they never merged the initial PR. With this, we send out a reminder comment on the PR so people have a clearer understanding of what happens. We don't nag them again once we reminded them for that repo. We also don't comment on very old PRs, as this likely causes more problems for our users then it does good (super outdated dependencies etc.) Hope this helps a couple of users to run Greenkeeper :)
- Loading branch information
Showing
6 changed files
with
235 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const md = require('./template') | ||
|
||
module.exports = () => md` | ||
Hey there 👋, | ||
we noticed that this PR is not merged yet. Just to let you know _Greenkeeper will | ||
not be enabled_ and you won't receive updates for your dependencies, if you don't merge | ||
this PR. | ||
In case you don't want to enable Greenkeeper, just close or ignore this PR, we | ||
won't nag you again. ✌️ | ||
Have a great day! 🌴 | ||
` |
5 changes: 5 additions & 0 deletions
5
couchdb/repositories/_design/open_initial_pr/views/open_initial_pr/map.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
function (doc) { | ||
if(doc.type === 'pr' && doc.initial && doc.state === 'open' && !doc.staleInitialPRReminder) { | ||
emit(doc.createdAt); | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
couchdb/repositories/_design/open_initial_pr/views/open_initial_pr/reduce
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
_count |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
const dbs = require('./lib/dbs') | ||
|
||
module.exports = async function () { | ||
const {repositories} = await dbs() | ||
const minAgeInDays = 7 | ||
const maxAgeInDays = 14 | ||
const startDate = new Date(Date.now() - maxAgeInDays * 24 * 60 * 60 * 1000).toJSON() | ||
const endDate = new Date(Date.now() - minAgeInDays * 24 * 60 * 60 * 1000).toJSON() | ||
|
||
const stalePRs = await repositories.query('open_initial_pr', { | ||
startkey: startDate, | ||
endkey: endDate, | ||
inclusive_end: true, | ||
include_docs: true | ||
}) | ||
return stalePRs.rows.map(function (row) { | ||
return { | ||
data: { | ||
name: 'send-stale-initial-pr-reminder', | ||
prNumber: row.doc.number, | ||
repositoryId: row.doc.repositoryId, | ||
accountId: row.doc.accountId | ||
} | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
const githubQueue = require('../lib/github-queue') | ||
const dbs = require('../lib/dbs') | ||
const upsert = require('../lib/upsert') | ||
const staleInitialPRReminderComment = require('../content/stale-initial-pr-reminder') | ||
|
||
module.exports = async function ( | ||
{ prNumber, repositoryId, accountId } | ||
) { | ||
accountId = String(accountId) | ||
repositoryId = String(repositoryId) | ||
|
||
const { installations, repositories } = await dbs() | ||
const installation = await installations.get(accountId) | ||
const repository = await repositories.get(repositoryId) | ||
const installationId = installation.installation | ||
const ghqueue = githubQueue(installationId) | ||
|
||
if (repository.enabled) return | ||
|
||
const [owner, repo] = repository.fullName.split('/') | ||
|
||
const issue = await ghqueue.read(github => github.issues.get({ | ||
owner, | ||
repo, | ||
number: prNumber | ||
})) | ||
|
||
if (issue.state !== 'open' || issue.locked) return | ||
|
||
await ghqueue.write(github => github.issues.createComment({ | ||
owner, | ||
repo, | ||
number: prNumber, | ||
body: staleInitialPRReminderComment | ||
})) | ||
|
||
await upsert(repositories, repositoryId, { | ||
staleInitialPRReminder: true | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
const { test } = require('tap') | ||
const nock = require('nock') | ||
const worker = require('../../jobs/send-stale-initial-pr-reminder') | ||
const upsert = require('../../lib/upsert') | ||
|
||
const dbs = require('../../lib/dbs') | ||
|
||
const waitFor = (milliseconds) => { | ||
return new Promise((resolve) => { | ||
setTimeout(resolve, milliseconds) | ||
}) | ||
} | ||
|
||
test('send-stale-initial-pr-reminder', async t => { | ||
const { installations, repositories } = await dbs() | ||
|
||
let githubNock | ||
|
||
t.beforeEach(async () => { | ||
githubNock = nock('https://api.github.com') | ||
.post('/installations/37/access_tokens') | ||
.reply(200, { | ||
token: 'secret' | ||
}) | ||
.get('/rate_limit') | ||
.reply(200, {}) | ||
|
||
await installations.put({ | ||
_id: '123', | ||
installation: 37 | ||
}) | ||
|
||
await repositories.put({ | ||
_id: '42', | ||
accountId: '123', | ||
enabled: false, | ||
fullName: 'finnp/test' | ||
}) | ||
}) | ||
|
||
t.afterEach(async () => { | ||
nock.cleanAll() | ||
await installations.remove(await installations.get('123')) | ||
await repositories.remove(await repositories.get('42')) | ||
}) | ||
|
||
t.test('send reminders for stale initial pr', async t => { | ||
t.plan(2) | ||
|
||
githubNock | ||
.get('/repos/finnp/test/issues/1234') | ||
.reply(200, { | ||
state: 'open', | ||
locked: false | ||
}) | ||
.post('/repos/finnp/test/issues/1234/comments') | ||
.reply(201, () => { | ||
t.pass('comment added') | ||
return {} | ||
}) | ||
|
||
await worker({ | ||
prNumber: 1234, | ||
repositoryId: 42, | ||
accountId: 123 | ||
}) | ||
|
||
const repoDoc = await repositories.get('42') | ||
t.ok(repoDoc.staleInitialPRReminder, 'staleInitialPRReminder set to true') | ||
await waitFor(50) | ||
}) | ||
|
||
t.test('does nothing if the repo is already enabled', async t => { | ||
t.plan(1) | ||
|
||
await upsert(repositories, '42', {enabled: true}) | ||
|
||
githubNock | ||
.get('/repos/finnp/test/issues/1234') | ||
.reply(200, () => { | ||
t.fail('Should not query issue status') | ||
return {} | ||
}) | ||
.post('/repos/finnp/test/issues/1234/comments') | ||
.reply(201, () => { | ||
t.fail('Should not post comment') | ||
return {} | ||
}) | ||
|
||
const newJob = await worker({ | ||
prNumber: 1234, | ||
repositoryId: 42, | ||
accountId: 123 | ||
}) | ||
|
||
t.notOk(newJob, 'no new job') | ||
await waitFor(50) | ||
}) | ||
|
||
t.test('does nothing if the issue was closed in the meanwhile', async t => { | ||
t.plan(1) | ||
|
||
githubNock | ||
.get('/repos/finnp/test/issues/1234') | ||
.reply(200, { | ||
state: 'closed', | ||
locked: false | ||
}) | ||
.post('/repos/finnp/test/issues/1234/comments') | ||
.reply(201, () => { | ||
t.fail('Should not post comment') | ||
return {} | ||
}) | ||
|
||
const newJob = await worker({ | ||
prNumber: 1234, | ||
repositoryId: 42, | ||
accountId: 123 | ||
}) | ||
|
||
t.notOk(newJob, 'no new job') | ||
await waitFor(50) | ||
}) | ||
|
||
t.test('does nothing if the issue was locked in the meanwhile', async t => { | ||
t.plan(1) | ||
|
||
githubNock | ||
.get('/repos/finnp/test/issues/1234') | ||
.reply(200, { | ||
state: 'open', | ||
locked: true | ||
}) | ||
.post('/repos/finnp/test/issues/1234/comments') | ||
.reply(201, () => { | ||
t.fail('Should not post comment') | ||
return {} | ||
}) | ||
|
||
const newJob = await worker({ | ||
prNumber: 1234, | ||
repositoryId: 42, | ||
accountId: 123 | ||
}) | ||
|
||
t.notOk(newJob, 'no new job') | ||
await waitFor(50) | ||
}) | ||
}) |