From 61dd6c04433a4154b82d6031e5151943349f5673 Mon Sep 17 00:00:00 2001 From: chris48s <chris48s@users.noreply.github.com> Date: Thu, 15 Dec 2022 18:36:17 +0000 Subject: [PATCH] switch from github workflows to github actions workflows; test [githubactionsworkflowstatus githubworkflowstatus] (#8475) * switch from github workflows to github actions workflows * update github actions workflow badge to use api * add test case for missing branch param * custom deprecation message --- .../github-actions-workflow-status.service.js | 101 ++++++++++++++++ .../github-actions-workflow-status.tester.js | 59 ++++++++++ .../github/github-workflow-status.service.js | 110 +++--------------- .../github/github-workflow-status.tester.js | 33 +++--- 4 files changed, 195 insertions(+), 108 deletions(-) create mode 100644 services/github/github-actions-workflow-status.service.js create mode 100644 services/github/github-actions-workflow-status.tester.js diff --git a/services/github/github-actions-workflow-status.service.js b/services/github/github-actions-workflow-status.service.js new file mode 100644 index 0000000000..2f18965895 --- /dev/null +++ b/services/github/github-actions-workflow-status.service.js @@ -0,0 +1,101 @@ +import Joi from 'joi' +import { isBuildStatus, renderBuildStatusBadge } from '../build-status.js' +import { NotFound } from '../index.js' +import { GithubAuthV3Service } from './github-auth-service.js' +import { documentation, errorMessagesFor } from './github-helpers.js' + +const schema = Joi.object({ + workflow_runs: Joi.array() + .items( + Joi.object({ + conclusion: Joi.alternatives() + .try(isBuildStatus, Joi.equal('no status')) + .required(), + }) + ) + .required() + .min(0) + .max(1), +}).required() + +const queryParamSchema = Joi.object({ + event: Joi.string(), + branch: Joi.string().required(), +}).required() + +const keywords = ['action', 'actions'] + +export default class GithubActionsWorkflowStatus extends GithubAuthV3Service { + static category = 'build' + + static route = { + base: 'github/actions/workflow/status', + pattern: ':user/:repo/:workflow+', + queryParamSchema, + } + + static examples = [ + { + title: 'GitHub Workflow Status', + namedParams: { + user: 'actions', + repo: 'toolkit', + workflow: 'unit-tests.yml', + }, + queryParams: { + branch: 'main', + }, + staticPreview: renderBuildStatusBadge({ + status: 'passing', + }), + documentation, + keywords, + }, + { + title: 'GitHub Workflow Status (with event)', + namedParams: { + user: 'actions', + repo: 'toolkit', + workflow: 'unit-tests.yml', + }, + queryParams: { + event: 'push', + branch: 'main', + }, + staticPreview: renderBuildStatusBadge({ + status: 'passing', + }), + documentation, + keywords, + }, + ] + + static defaultBadgeData = { + label: 'build', + } + + async fetch({ user, repo, workflow, branch, event }) { + return await this._requestJson({ + schema, + url: `/repos/${user}/${repo}/actions/workflows/${workflow}/runs`, + options: { + searchParams: { + branch, + event, + page: '1', + per_page: '1', + exclude_pull_requests: 'true', + }, + }, + errorMessages: errorMessagesFor('repo or workflow not found'), + }) + } + + async handle({ user, repo, workflow }, { branch, event }) { + const data = await this.fetch({ user, repo, workflow, branch, event }) + if (data.workflow_runs.length === 0) { + throw new NotFound({ prettyMessage: 'branch or event not found' }) + } + return renderBuildStatusBadge({ status: data.workflow_runs[0].conclusion }) + } +} diff --git a/services/github/github-actions-workflow-status.tester.js b/services/github/github-actions-workflow-status.tester.js new file mode 100644 index 0000000000..9ebc19e4a6 --- /dev/null +++ b/services/github/github-actions-workflow-status.tester.js @@ -0,0 +1,59 @@ +import Joi from 'joi' +import { isBuildStatus } from '../build-status.js' +import { createServiceTester } from '../tester.js' +export const t = await createServiceTester() + +const isWorkflowStatus = Joi.alternatives() + .try(isBuildStatus, Joi.equal('no status')) + .required() + +t.create('missing branch param') + .get('/actions/toolkit/unit-tests.yml.json') + .expectBadge({ + label: 'build', + message: 'invalid query parameter: branch', + }) + +t.create('nonexistent repo') + .get('/badges/shields-fakeness/fake.yml.json?branch=main') + .expectBadge({ + label: 'build', + message: 'repo or workflow not found', + }) + +t.create('nonexistent workflow') + .get('/actions/toolkit/not-a-real-workflow.yml.json?branch=main') + .expectBadge({ + label: 'build', + message: 'repo or workflow not found', + }) + +t.create('nonexistent branch') + .get('/actions/toolkit/unit-tests.yml.json?branch=not-a-real-branch') + .expectBadge({ + label: 'build', + message: 'branch or event not found', + }) + +t.create('nonexistent event') + .get( + '/actions/toolkit/unit-tests.yml.json?branch=main&event=not-a-real-event' + ) + .expectBadge({ + label: 'build', + message: 'branch or event not found', + }) + +t.create('valid workflow') + .get('/actions/toolkit/unit-tests.yml.json?branch=main') + .expectBadge({ + label: 'build', + message: isWorkflowStatus, + }) + +t.create('valid workflow (with event)') + .get('/actions/toolkit/unit-tests.yml.json?branch=main&event=push') + .expectBadge({ + label: 'build', + message: isWorkflowStatus, + }) diff --git a/services/github/github-workflow-status.service.js b/services/github/github-workflow-status.service.js index d1d47ca0bb..69e6e8f286 100644 --- a/services/github/github-workflow-status.service.js +++ b/services/github/github-workflow-status.service.js @@ -1,100 +1,28 @@ -import Joi from 'joi' -import { isBuildStatus, renderBuildStatusBadge } from '../build-status.js' -import { BaseSvgScrapingService } from '../index.js' -import { documentation } from './github-helpers.js' +import { BaseService } from '../index.js' -const schema = Joi.object({ - message: Joi.alternatives() - .try(isBuildStatus, Joi.equal('no status')) - .required(), -}).required() - -const queryParamSchema = Joi.object({ - event: Joi.string(), -}).required() - -const keywords = ['action', 'actions'] - -export default class GithubWorkflowStatus extends BaseSvgScrapingService { +export default class DeprecatedGithubWorkflowStatus extends BaseService { static category = 'build' static route = { base: 'github/workflow/status', - pattern: ':user/:repo/:workflow/:branch*', - queryParamSchema, - } - - static examples = [ - { - title: 'GitHub Workflow Status', - pattern: ':user/:repo/:workflow', - namedParams: { - user: 'actions', - repo: 'toolkit', - workflow: 'toolkit-unit-tests', - }, - staticPreview: renderBuildStatusBadge({ - status: 'passing', - }), - documentation, - keywords, - }, - { - title: 'GitHub Workflow Status (branch)', - pattern: ':user/:repo/:workflow/:branch', - namedParams: { - user: 'actions', - repo: 'toolkit', - workflow: 'toolkit-unit-tests', - branch: 'master', - }, - staticPreview: renderBuildStatusBadge({ - status: 'passing', - }), - documentation, - keywords, - }, - { - title: 'GitHub Workflow Status (event)', - pattern: ':user/:repo/:workflow', - namedParams: { - user: 'actions', - repo: 'toolkit', - workflow: 'toolkit-unit-tests', - }, - queryParams: { - event: 'push', - }, - staticPreview: renderBuildStatusBadge({ - status: 'passing', - }), - documentation, - keywords, - }, - ] - - static defaultBadgeData = { - label: 'build', - } - - async fetch({ user, repo, workflow, branch, event }) { - const { message: status } = await this._requestSvg({ - schema, - url: `https://github.com/${user}/${repo}/workflows/${encodeURIComponent( - workflow - )}/badge.svg`, - options: { searchParams: { branch, event } }, - valueMatcher: />([^<>]+)<\/tspan><\/text><\/g><path/, - errorMessages: { - 404: 'repo, branch, or workflow not found', - }, - }) - - return { status } + pattern: ':various+', } - async handle({ user, repo, workflow, branch }, { event }) { - const { status } = await this.fetch({ user, repo, workflow, branch, event }) - return renderBuildStatusBadge({ status }) + static examples = [] + + static defaultBadgeData = { label: 'build' } + + async handle() { + return { + label: 'build', + message: 'https://github.com/badges/shields/issues/8671', + /* + This is a 'special' deprecation because we are making a breaking change + We've implemented it as a custom class instead of a normal + deprecatedService so that we can include link. + */ + link: ['https://github.com/badges/shields/issues/8671'], + color: 'red', + } } } diff --git a/services/github/github-workflow-status.tester.js b/services/github/github-workflow-status.tester.js index 573a16e7b1..de27de37aa 100644 --- a/services/github/github-workflow-status.tester.js +++ b/services/github/github-workflow-status.tester.js @@ -1,43 +1,42 @@ -import Joi from 'joi' -import { isBuildStatus } from '../build-status.js' -import { createServiceTester } from '../tester.js' -export const t = await createServiceTester() +import { ServiceTester } from '../tester.js' -const isWorkflowStatus = Joi.alternatives() - .try(isBuildStatus, Joi.equal('no status')) - .required() +export const t = new ServiceTester({ + id: 'GithubWorkflowStatus', + title: 'Github Workflow Status', + pathPrefix: '/github/workflow/status', +}) -t.create('nonexistent repo') +t.create('no longer available (previously nonexistent repo)') .get('/badges/shields-fakeness/fake.json') .expectBadge({ label: 'build', - message: 'repo, branch, or workflow not found', + message: 'https://github.com/badges/shields/issues/8671', }) -t.create('nonexistent workflow') +t.create('no longer available (previously nonexistent workflow)') .get('/actions/toolkit/not-a-real-workflow.json') .expectBadge({ label: 'build', - message: 'repo, branch, or workflow not found', + message: 'https://github.com/badges/shields/issues/8671', }) -t.create('valid workflow') +t.create('no longer available (previously valid workflow)') .get('/actions/toolkit/toolkit-unit-tests.json') .expectBadge({ label: 'build', - message: isWorkflowStatus, + message: 'https://github.com/badges/shields/issues/8671', }) -t.create('valid workflow (branch)') +t.create('no longer available (previously valid workflow - branch)') .get('/actions/toolkit/toolkit-unit-tests/master.json') .expectBadge({ label: 'build', - message: isWorkflowStatus, + message: 'https://github.com/badges/shields/issues/8671', }) -t.create('valid workflow (event)') +t.create('no longer available (previously valid workflow - event)') .get('/actions/toolkit/toolkit-unit-tests.json?event=push') .expectBadge({ label: 'build', - message: isWorkflowStatus, + message: 'https://github.com/badges/shields/issues/8671', }) -- GitLab