diff --git a/services/github/github-latest-branch-release.service.js b/services/github/github-latest-branch-release.service.js new file mode 100644 index 0000000000000..0f2497f73f379 --- /dev/null +++ b/services/github/github-latest-branch-release.service.js @@ -0,0 +1,69 @@ +import Joi from 'joi' +import { GithubAuthV3Service } from './github-auth-service.js' +import { documentation, httpErrorsFor } from './github-helpers.js' + +const MAXIMUM_SEARCHING_PAGE_NUMBER = 5 + +const schema = Joi.array().items( + Joi.object({ + target_commitish: Joi.string(), + tag_name: Joi.string(), + }), +) + +export default class GithubLatestBranchRelease extends GithubAuthV3Service { + static category = 'version' + static route = { + base: 'github/v/latest-branch-release', + pattern: ':user/:repo/:branch', + } + + static examples = [ + { + title: 'GitHub latest branch release', + namedParams: { user: 'laravel', repo: 'framework', branch: '10.x' }, + staticPreview: Object.assign(this.render({ releases: [] }), { + label: 'latest-release@10.x', + message: 'v10.28.0', + style: 'social', + }), + queryParams: {}, + documentation, + }, + ] + + static defaultBadgeData = { namedLogo: 'github' } + + static render({ branch, latestBranchTag }) { + return { + label: `latest-release@${branch}`, + message: latestBranchTag || '', + color: 'blue', + } + } + + async handle({ user, repo, branch }) { + let shouldRetry = true + let currentPage = 0 + let latestBranchTag + + while (shouldRetry && currentPage < MAXIMUM_SEARCHING_PAGE_NUMBER) { + currentPage++ + const releases = await this._requestJson({ + url: `/repos/${user}/${repo}/releases?per_page=100&page=${currentPage}`, + schema, + httpErrors: httpErrorsFor('user not found'), + }) + + latestBranchTag = releases.filter( + release => release.target_commitish === branch, + )[0]?.tag_name + + if (latestBranchTag) { + shouldRetry = false + } + } + + return this.constructor.render({ branch, latestBranchTag }) + } +} diff --git a/services/github/github-latest-branch-release.tester.js b/services/github/github-latest-branch-release.tester.js new file mode 100644 index 0000000000000..700045afd22e9 --- /dev/null +++ b/services/github/github-latest-branch-release.tester.js @@ -0,0 +1,33 @@ +import Joi from 'joi' +import { isSemver } from '../test-validators.js' +import { ServiceTester } from '../tester.js' + +export const t = new ServiceTester({ + id: 'GithubLatestBranchRelease', + title: 'Github Latest Branch Release', + pathPrefix: '/github', +}) + +t.create('Release') + .get('/v/release/expressjs/express.json') + .expectBadge({ label: 'release', message: isSemver, color: 'blue' }) + +t.create('Prerelease') + .get('/v/release/expressjs/express.json?include_prereleases') + .expectBadge({ + label: 'release', + message: isSemver, + color: Joi.string().allow('blue', 'orange').required(), + }) + +t.create('Latest release (release)') + .get('/v/release/expressjs/express.json?display_name=release') + .expectBadge({ label: 'release', message: isSemver, color: 'blue' }) + +t.create('Release (No releases)') + .get('/v/release/badges/daily-tests.json') + .expectBadge({ label: 'release', message: 'no releases or repo not found' }) + +t.create('Release (repo not found)') + .get('/v/release/badges/helmets.json') + .expectBadge({ label: 'release', message: 'no releases or repo not found' })