From 586edc12283ac4a0c7cedaabfe45548939912d3c Mon Sep 17 00:00:00 2001 From: Karol Wydmuch Date: Wed, 18 Oct 2023 12:47:18 +0200 Subject: [PATCH 1/2] add service --- services/github/github-issue-7929.service.js | 52 ++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 services/github/github-issue-7929.service.js diff --git a/services/github/github-issue-7929.service.js b/services/github/github-issue-7929.service.js new file mode 100644 index 0000000000000..9893a94e65d38 --- /dev/null +++ b/services/github/github-issue-7929.service.js @@ -0,0 +1,52 @@ +import fs from 'fs' +import Joi from 'joi' +import { nonNegativeInteger } from '../validators.js' +import { GithubAuthV3Service } from './github-auth-service.js' +import { documentation, httpErrorsFor } from './github-helpers.js' + +const schema = Joi.object({ + followers: nonNegativeInteger, +}).required() + +export default class GithubIssue7929Service 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: 'Follow', + style: 'social', + }), + queryParams: { label: 'Follow' }, + documentation, + }, + ] + + static defaultBadgeData = { label: 'latest@', namedLogo: 'github' } + + static render({ releases }) { + return { + message: releases?.length, + color: 'blue', + } + } + + async handle({ user, repo, branch }) { + const releases = await this._requestJson({ + url: `/repos/${user}/${repo}/releases?per_page=50`, + schema, + httpErrors: httpErrorsFor('user not found'), + }) + + fs.writeFileSync('./test.json', releases) + + console.log(releases) + + return this.constructor.render({ releases }) + } +} From a63bc374f98fdad46f2720764b74b75f06e22359 Mon Sep 17 00:00:00 2001 From: Karol Wydmuch Date: Wed, 18 Oct 2023 14:30:38 +0200 Subject: [PATCH 2/2] refactor and add tests --- services/github/github-issue-7929.service.js | 52 -------------- .../github-latest-branch-release.service.js | 69 +++++++++++++++++++ .../github-latest-branch-release.tester.js | 33 +++++++++ 3 files changed, 102 insertions(+), 52 deletions(-) delete mode 100644 services/github/github-issue-7929.service.js create mode 100644 services/github/github-latest-branch-release.service.js create mode 100644 services/github/github-latest-branch-release.tester.js diff --git a/services/github/github-issue-7929.service.js b/services/github/github-issue-7929.service.js deleted file mode 100644 index 9893a94e65d38..0000000000000 --- a/services/github/github-issue-7929.service.js +++ /dev/null @@ -1,52 +0,0 @@ -import fs from 'fs' -import Joi from 'joi' -import { nonNegativeInteger } from '../validators.js' -import { GithubAuthV3Service } from './github-auth-service.js' -import { documentation, httpErrorsFor } from './github-helpers.js' - -const schema = Joi.object({ - followers: nonNegativeInteger, -}).required() - -export default class GithubIssue7929Service 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: 'Follow', - style: 'social', - }), - queryParams: { label: 'Follow' }, - documentation, - }, - ] - - static defaultBadgeData = { label: 'latest@', namedLogo: 'github' } - - static render({ releases }) { - return { - message: releases?.length, - color: 'blue', - } - } - - async handle({ user, repo, branch }) { - const releases = await this._requestJson({ - url: `/repos/${user}/${repo}/releases?per_page=50`, - schema, - httpErrors: httpErrorsFor('user not found'), - }) - - fs.writeFileSync('./test.json', releases) - - console.log(releases) - - return this.constructor.render({ releases }) - } -} 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' })