Add [github] Milestone service (#4747)

* Add isMetricOverMetric test validator

* Add Github Milestone and Milestone-Detail

Co-authored-by: Pierre-Yves B <PyvesDev@gmail.com>
This commit is contained in:
Jacob Colvin
2020-03-09 17:10:12 -04:00
committed by GitHub
parent 1d90e102ac
commit 792ecb7c01
5 changed files with 298 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
'use strict'
const Joi = require('@hapi/joi')
const { metric } = require('../text-formatters')
const { nonNegativeInteger } = require('../validators')
const { GithubAuthV3Service } = require('./github-auth-service')
const { documentation, errorMessagesFor } = require('./github-helpers')
const schema = Joi.object({
open_issues: nonNegativeInteger,
closed_issues: nonNegativeInteger,
title: Joi.string().required(),
}).required()
module.exports = class GithubMilestoneDetail extends GithubAuthV3Service {
static get category() {
return 'issue-tracking'
}
static get route() {
return {
base: 'github/milestones',
pattern:
':variant(issues-closed|issues-open|issues-total|progress|progress-percent)/:user/:repo/:number([0-9]+)',
}
}
static get examples() {
return [
{
title: 'GitHub milestone',
namedParams: {
variant: 'issues-open',
user: 'badges',
repo: 'shields',
number: '1',
},
staticPreview: {
label: 'milestone issues',
message: '17/22',
color: 'blue',
},
documentation,
},
]
}
static get defaultBadgeData() {
return {
label: 'milestones',
color: 'informational',
}
}
static render({ user, repo, variant, number, milestone }) {
let milestoneMetric
let color
let label = ''
switch (variant) {
case 'issues-open':
milestoneMetric = milestone.open_issues
color = 'red'
label = 'open issues'
break
case 'issues-closed':
milestoneMetric = milestone.closed_issues
color = 'green'
label = 'closed issues'
break
case 'issues-total':
milestoneMetric = milestone.open_issues + milestone.closed_issues
color = 'blue'
label = 'issues'
break
case 'progress':
milestoneMetric = `${milestone.closed_issues}/${milestone.open_issues +
milestone.closed_issues}`
color = 'blue'
break
case 'progress-percent':
milestoneMetric = `${Math.floor(
(milestone.closed_issues /
(milestone.open_issues + milestone.closed_issues)) *
100
)}%`
color = 'blue'
}
return {
label: `${milestone.title} ${label}`,
message: metric(milestoneMetric),
color,
link: [`https://github.com/${user}/${repo}/milestone/${number}`],
}
}
async fetch({ user, repo, number }) {
return this._requestJson({
url: `/repos/${user}/${repo}/milestones/${number}`,
schema,
errorMessages: errorMessagesFor(`repo or milestone not found`),
})
}
async handle({ user, repo, variant, number }) {
const milestone = await this.fetch({ user, repo, number })
return this.constructor.render({ user, repo, variant, number, milestone })
}
}

View File

@@ -0,0 +1,55 @@
'use strict'
const {
isMetric,
isMetricOverMetric,
isIntegerPercentage,
} = require('../test-validators')
const t = (module.exports = require('../tester').createServiceTester())
t.create('Milestone Open Issues')
.get('/issues-open/MacroPower/milestone-test/1.json')
.expectBadge({
label: 'openWithOneOpenIssue open issues',
message: isMetric,
link: [`https://github.com/MacroPower/milestone-test/milestone/1`],
})
t.create('Milestone Closed Issues')
.get('/issues-closed/MacroPower/milestone-test/3.json')
.expectBadge({
label: 'closedWithOneClosedIssue closed issues',
message: isMetric,
link: [`https://github.com/MacroPower/milestone-test/milestone/3`],
})
t.create('Milestone Total Issues')
.get('/issues-total/MacroPower/milestone-test/2.json')
.expectBadge({
label: 'openWithOneOpenOneClosedIssue issues',
message: isMetric,
link: [`https://github.com/MacroPower/milestone-test/milestone/2`],
})
t.create('Milestone Progress')
.get('/progress/MacroPower/milestone-test/2.json')
.expectBadge({
label: 'openWithOneOpenOneClosedIssue',
message: isMetricOverMetric,
link: [`https://github.com/MacroPower/milestone-test/milestone/2`],
})
t.create('Milestone Progress (Percent)')
.get('/progress-percent/MacroPower/milestone-test/2.json')
.expectBadge({
label: 'openWithOneOpenOneClosedIssue',
message: isIntegerPercentage,
link: [`https://github.com/MacroPower/milestone-test/milestone/2`],
})
t.create('Milestones (repo or milestone not found)')
.get('/progress/badges/helmets/1.json')
.expectBadge({
label: 'milestones',
message: 'repo or milestone not found',
})

View File

@@ -0,0 +1,93 @@
'use strict'
const Joi = require('@hapi/joi')
const { metric } = require('../text-formatters')
const { GithubAuthV3Service } = require('./github-auth-service')
const { documentation, errorMessagesFor } = require('./github-helpers')
const schema = Joi.array()
.items(
Joi.object({
state: Joi.string().required(),
})
)
.required()
module.exports = class GithubMilestone extends GithubAuthV3Service {
static get category() {
return 'issue-tracking'
}
static get route() {
return {
base: 'github/milestones',
pattern: ':variant(open|closed|all)/:user/:repo',
}
}
static get examples() {
return [
{
title: 'GitHub milestones',
namedParams: {
user: 'badges',
repo: 'shields',
variant: 'open',
},
staticPreview: {
label: 'milestones',
message: '2',
color: 'red',
},
documentation,
},
]
}
static get defaultBadgeData() {
return {
label: 'milestones',
color: 'informational',
}
}
static render({ user, repo, variant, milestones }) {
const milestoneLength = milestones.length
let color
let label = ''
switch (variant) {
case 'all':
color = 'blue'
break
case 'open':
color = 'red'
label = 'active'
break
case 'closed':
color = 'green'
label = 'completed'
break
}
return {
label: `${label} milestones`,
message: metric(milestoneLength),
color,
link: [`https://github.com/${user}/${repo}/milestones`],
}
}
async fetch({ user, repo, variant }) {
return this._requestJson({
url: `/repos/${user}/${repo}/milestones?state=${variant}`,
schema,
errorMessages: errorMessagesFor(`repo not found`),
})
}
async handle({ user, repo, variant }) {
const milestones = await this.fetch({ user, repo, variant })
return this.constructor.render({ user, repo, variant, milestones })
}
}

View File

@@ -0,0 +1,35 @@
'use strict'
const { isMetric } = require('../test-validators')
const t = (module.exports = require('../tester').createServiceTester())
t.create('All Milestones')
.get('/all/MacroPower/milestone-test.json')
.expectBadge({
label: 'milestones',
message: isMetric,
link: [`https://github.com/MacroPower/milestone-test/milestones`],
})
t.create('Open Milestones')
.get('/open/MacroPower/milestone-test.json')
.expectBadge({
label: 'active milestones',
message: isMetric,
link: [`https://github.com/MacroPower/milestone-test/milestones`],
})
t.create('Closed Milestones')
.get('/closed/MacroPower/milestone-test.json')
.expectBadge({
label: 'completed milestones',
message: isMetric,
link: [`https://github.com/MacroPower/milestone-test/milestones`],
})
t.create('Milestones (repo not found)')
.get('/all/badges/helmets.json')
.expectBadge({
label: 'milestones',
message: 'repo not found',
})

View File

@@ -68,6 +68,10 @@ const isMetricOpenIssues = withRegex(
/^([1-9][0-9]*[kMGTPEZY]?|[1-9]\.[1-9][kMGTPEZY]) open$/
)
const isMetricOverMetric = withRegex(
/^([1-9][0-9]*[kMGTPEZY]?|[1-9]\.[1-9][kMGTPEZY])\/([1-9][0-9]*[kMGTPEZY]?|[1-9]\.[1-9][kMGTPEZY])$/
)
const isMetricOverTimePeriod = withRegex(
/^([1-9][0-9]*[kMGTPEZY]?|[1-9]\.[1-9][kMGTPEZY])\/(year|month|four weeks|week|day)$/
)
@@ -144,6 +148,7 @@ module.exports = {
isStarRating,
isMetric,
isMetricOpenIssues,
isMetricOverMetric,
isMetricOverTimePeriod,
isPercentage,
isIntegerPercentage,