Skip to content

Commit

Permalink
feat: Support custom reporter in Github Actions
Browse files Browse the repository at this point in the history
  • Loading branch information
Kesin11 committed Sep 12, 2020
1 parent a712929 commit 1f2d44d
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 23 deletions.
53 changes: 37 additions & 16 deletions __tests__/config/github_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,45 @@ describe('parseConfig', () => {
})
})

it('when repos are object', () => {
const config = {
configDir: __dirname,
github: {
repos: [{
name: 'owner/repo',
tests: [
'**/*.xml'
]
}]
describe('when repos are object', () => {
it('that has tests', () => {
const config = {
configDir: __dirname,
github: {
repos: [{
name: 'owner/repo',
tests: [ '**/*.xml' ]
}]
}
}
}
const actual = parseConfig(config)
const actual = parseConfig(config)

expect(actual).toEqual({
repos: [
{ owner: 'owner', repo: 'repo', fullname: 'owner/repo', testGlob: ['**/*.xml'] }
]
expect(actual).toEqual({
repos: [
{ owner: 'owner', repo: 'repo', fullname: 'owner/repo', testGlob: ['**/*.xml'] }
]
})
})

it('that has custom_reports', () => {
const customReport = { name: 'custom', paths: ['custom.json'] }
const config = {
configDir: __dirname,
github: {
repos: [{
name: 'owner/repo',
custom_reports: [ customReport ]
}]
}
}
const actual = parseConfig(config)

expect(actual).toEqual({
repos: [{
owner: 'owner', repo: 'repo', fullname: 'owner/repo',
customReports: [ customReport ]
}]
})
})
})
})
32 changes: 29 additions & 3 deletions src/analyzer/github_analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { RestEndpointMethodTypes } from '@octokit/plugin-rest-endpoint-methods'
import { sumBy, min, max } from 'lodash'
import { Analyzer, diffSec, Status, TestReport, WorkflowParams, convertToReportTestSuites } from './analyzer'
import { RepositoryTagMap } from '../client/github_repository_client'
import { TestSuites, parse } from 'junit2json'
import AdmZip from 'adm-zip'
import { Artifact } from '../client/jenkins_client'
import { parse } from 'junit2json'
import { CustomReportArtifact, Artifact } from '../client/client'
import { CustomReportCollection, CustomReport } from '../custom_report_collection'
export type WorkflowRunsItem = RestEndpointMethodTypes['actions']['listWorkflowRunsForRepo']['response']['data']['workflow_runs'][0]
export type JobsItem = RestEndpointMethodTypes['actions']['listJobsForWorkflowRun']['response']['data']['jobs']

Expand Down Expand Up @@ -179,4 +179,30 @@ export class GithubAnalyzer implements Analyzer {
}
return testReports
}

async createCustomReportCollection(workflowReport: WorkflowReport, customReportArtifacts: CustomReportArtifact): Promise<CustomReportCollection> {
const reportCollection = new CustomReportCollection()
for (const [reportName, artifacts] of customReportArtifacts) {
const reports = artifacts.map((artifact) => {
let data: { [key: string]: unknown }
try {
const jsonString = Buffer.from(artifact.data).toString('utf8')
data = JSON.parse(jsonString)
} catch (error) {
console.error(`Error: Could not parse as JSON. ${artifact.path}`)
return
}

return {
workflowId: workflowReport.workflowId,
workflowRunId: workflowReport.workflowRunId,
createdAt: workflowReport.createdAt,
...data
} as CustomReport
}).filter((report) => report !== undefined) as CustomReport[]

reportCollection.set(reportName, reports)
}
return reportCollection
}
}
23 changes: 21 additions & 2 deletions src/client/github_client.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Octokit, RestEndpointMethodTypes } from "@octokit/rest";
import axios, { AxiosInstance } from 'axios'
import { axiosRequestLogger } from './client'
import { axiosRequestLogger, CustomReportArtifact, Artifact } from './client'
import { minBy } from "lodash";
import { ZipExtractor } from "../zip_extractor";
import { Artifact } from "./jenkins_client";
import { CustomReportConfig } from "../config/config";

// Oktokit document: https://octokit.github.io/rest.js/v18#actions

Expand Down Expand Up @@ -133,4 +133,23 @@ export class GithubClient {

return this.fetchArtifacts(owner, repo, runId, globs)
}

async fetchCustomReports(owner: string, repo: string, runId: number, customReportsConfigs: CustomReportConfig[]): Promise<CustomReportArtifact> {
// Skip if custom report config are not provided
if (customReportsConfigs.length < 1) return new Map()

// Fetch artifacts in parallel
const customReports: CustomReportArtifact = new Map<string, Artifact[]>()
const nameArtifacts = customReportsConfigs.map((customReportConfig) => {
return {
name: customReportConfig.name,
artifacts: this.fetchArtifacts(owner, repo, runId, customReportConfig.paths)
}
})
for (const { name, artifacts } of nameArtifacts) {
customReports.set(name, await artifacts)
}

return customReports
}
}
7 changes: 5 additions & 2 deletions src/config/github_config.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { YamlConfig, CommonConfig } from './config'
import { YamlConfig, CommonConfig, CustomReportConfig } from './config'

export type GithubConfig = CommonConfig & {
repos: {
owner: string
repo: string
fullname: string
testGlob: string[]
customReports: CustomReportConfig[]
}[]
}

type RepoYaml = string | {
name: string
tests: string[]
custom_reports: CustomReportConfig[]
}

export const parseConfig = (config: YamlConfig): GithubConfig | undefined => {
Expand All @@ -31,7 +33,8 @@ export const parseConfig = (config: YamlConfig): GithubConfig | undefined => {
owner,
repo,
fullname: repoYaml.name,
testGlob: repoYaml.tests
testGlob: repoYaml.tests,
customReports: repoYaml.custom_reports,
}
})

Expand Down
10 changes: 10 additions & 0 deletions src/runner/github_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { WorkflowReport, TestReport } from "../analyzer/analyzer"
import { CompositExporter } from "../exporter/exporter"
import { LastRunStore } from "../last_run_store"
import { GithubRepositoryClient } from "../client/github_repository_client"
import { CustomReportCollection } from "../custom_report_collection"

export class GithubRunner implements Runner {
service: string = 'github'
Expand Down Expand Up @@ -39,6 +40,7 @@ export class GithubRunner implements Runner {

let workflowReports: WorkflowReport[] = []
let testReports: TestReport[] = []
const customReportCollection = new CustomReportCollection()
for (const repo of this.config.repos) {
console.info(`Fetching ${this.service} - ${repo.fullname} ...`)
const repoWorkflowReports: WorkflowReport[] = []
Expand All @@ -50,13 +52,20 @@ export class GithubRunner implements Runner {
const tagMap = await this.repoClient.fetchRepositoryTagMap(repo.owner, repo.repo)

for (const workflowRun of workflowRuns) {
// Fetch data
const jobs = await this.client.fetchJobs(repo.owner, repo.repo, workflowRun.run.id)
const tests = await this.client.fetchTests(repo.owner, repo.repo, workflowRun.run.id, repo.testGlob)
const customReportArtifacts = await this.client.fetchCustomReports(repo.owner, repo.repo, workflowRun.run.id, repo.customReports)

// Create report
const workflowReport = this.analyzer.createWorkflowReport(workflowRun.name, workflowRun.run, jobs, tagMap)
const testReports = await this.analyzer.createTestReports(workflowReport, tests)
const runCustomReportCollection = await this.analyzer.createCustomReportCollection(workflowReport, customReportArtifacts)

// Aggregate
repoWorkflowReports.push(workflowReport)
repoTestReports = repoTestReports.concat(testReports)
customReportCollection.aggregate(runCustomReportCollection)
}
}
catch (error) {
Expand All @@ -73,6 +82,7 @@ export class GithubRunner implements Runner {
const exporter = new CompositExporter(this.service, this.configDir, this.config.exporter)
await exporter.exportWorkflowReports(workflowReports)
await exporter.exportTestReports(testReports)
await exporter.exportCustomReports(customReportCollection)

this.store.save()
console.info(`Success: done execute '${this.service}'`)
Expand Down

0 comments on commit 1f2d44d

Please sign in to comment.