feat: Add author filter option for CommitActivity

Add a new filter option to [GithubCommitActivity], allowing users to filter the commit activity by a specific author.

To make the filter more explicit, The label display "commits by [author]" for the total amount of commits and "commit activity by [author]" for other intervals when an author filter is selected.

To maintain a clear and organized code structure, The filtered author is added as an argument and not to the shield path.

The request to find the number of commits by the author is made using the REST api rather then the GraphQL api to make it in 1 request rather then 2.

Resolves #9215
This commit is contained in:
jNullj
2023-06-10 19:49:45 +03:00
committed by jNullj
parent 42603e139f
commit 37dbc7a567

View File

@@ -1,10 +1,15 @@
import gql from 'graphql-tag'
import Joi from 'joi'
import parseLinkHeader from 'parse-link-header'
import { InvalidResponse } from '../index.js'
import { metric } from '../text-formatters.js'
import { nonNegativeInteger } from '../validators.js'
import { GithubAuthV4Service } from './github-auth-service.js'
import { transformErrors, documentation } from './github-helpers.js'
import {
transformErrors,
documentation,
errorMessagesFor,
} from './github-helpers.js'
const schema = Joi.object({
data: Joi.object({
@@ -18,11 +23,16 @@ const schema = Joi.object({
}).required(),
}).required()
const queryParamSchema = Joi.object({
authorFilter: Joi.string(),
})
export default class GitHubCommitActivity extends GithubAuthV4Service {
static category = 'activity'
static route = {
base: 'github/commit-activity',
pattern: ':interval(t|y|m|4w|w)/:user/:repo/:branch*',
queryParamSchema,
}
static examples = [
@@ -31,6 +41,7 @@ export default class GitHubCommitActivity extends GithubAuthV4Service {
// Override the pattern to omit the deprecated interval "4w".
pattern: ':interval(t|y|m|w)/:user/:repo',
namedParams: { interval: 'm', user: 'eslint', repo: 'eslint' },
queryParams: { authorFilter: 'chris48s' },
staticPreview: this.render({ interval: 'm', commitCount: 457 }),
keywords: ['commits'],
documentation,
@@ -45,6 +56,7 @@ export default class GitHubCommitActivity extends GithubAuthV4Service {
repo: 'squint',
branch: 'main',
},
queryParams: { authorFilter: 'jnullj' },
staticPreview: this.render({ interval: 'm', commitCount: 5 }),
keywords: ['commits'],
documentation,
@@ -53,9 +65,10 @@ export default class GitHubCommitActivity extends GithubAuthV4Service {
static defaultBadgeData = { label: 'commit activity', color: 'blue' }
static render({ interval, commitCount }) {
static render({ interval, commitCount, authorFilter }) {
// If total commits selected change label from commit activity to commits
const label = interval === 't' ? 'commits' : undefined
const label = interval === 't' ? 'commits' : this.defaultBadgeData.label
const authorFilterLabel = authorFilter ? ` by ${authorFilter}` : ``
const intervalLabel = {
t: '',
@@ -66,7 +79,7 @@ export default class GitHubCommitActivity extends GithubAuthV4Service {
}[interval]
return {
label,
label: `${label}${authorFilterLabel}`,
message: `${metric(commitCount)}${intervalLabel}`,
}
}
@@ -103,6 +116,30 @@ export default class GitHubCommitActivity extends GithubAuthV4Service {
})
}
async fetchAuthorFilter({
interval,
user,
repo,
branch = 'HEAD',
authorFilter,
}) {
const since =
this.constructor.getIntervalQueryStartDate({ interval }) || undefined
return this._request({
url: `/repos/${user}/${repo}/commits`,
options: {
searchParams: {
sha: branch,
author: authorFilter,
per_page: '1',
since: since,
},
},
errorMessages: errorMessagesFor('repo not found'),
})
}
static transform({ data }) {
const {
repository: { object: repo },
@@ -115,6 +152,20 @@ export default class GitHubCommitActivity extends GithubAuthV4Service {
return repo.history.totalCount
}
static transformAuthorFilter({ res, buffer }) {
if (buffer.message === 'Not Found') {
throw new InvalidResponse({ prettyMessage: 'invalid branch' })
}
const parsed = parseLinkHeader(res.headers.link)
if (!parsed) {
return 0
}
return parsed.last.page
}
static getIntervalQueryStartDate({ interval }) {
const now = new Date()
@@ -131,9 +182,21 @@ export default class GitHubCommitActivity extends GithubAuthV4Service {
return now.toISOString()
}
async handle({ interval, user, repo, branch }) {
const json = await this.fetch({ interval, user, repo, branch })
const commitCount = this.constructor.transform(json)
return this.constructor.render({ interval, commitCount })
async handle({ interval, user, repo, branch }, { authorFilter }) {
let commitCount
if (authorFilter) {
const authorFilterRes = await this.fetchAuthorFilter({
interval,
user,
repo,
branch,
authorFilter,
})
commitCount = this.constructor.transformAuthorFilter(authorFilterRes)
} else {
const json = await this.fetch({ interval, user, repo, branch })
commitCount = this.constructor.transform(json)
}
return this.constructor.render({ interval, commitCount, authorFilter })
}
}