mirror of
https://github.com/dorny/test-reporter.git
synced 2025-12-16 14:27:10 +01:00
Add support for loading test results from artifacts
This commit is contained in:
parent
71f2f95ef0
commit
3510d9ac27
19 changed files with 11665 additions and 338 deletions
78
src/input-providers/artifact-provider.ts
Normal file
78
src/input-providers/artifact-provider.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import * as github from '@actions/github'
|
||||
import {GitHub} from '@actions/github/lib/utils'
|
||||
|
||||
import Zip from 'adm-zip'
|
||||
import picomatch from 'picomatch'
|
||||
|
||||
import {FileContent, InputProvider, ReportInput} from './input-provider'
|
||||
import {downloadArtifact, listFiles} from '../utils/github-utils'
|
||||
|
||||
export class ArtifactProvider implements InputProvider {
|
||||
private readonly artifactNameMatch: (name: string) => boolean
|
||||
private readonly fileNameMatch: (name: string) => boolean
|
||||
private readonly getReportName: (name: string) => string
|
||||
|
||||
constructor(
|
||||
readonly octokit: InstanceType<typeof GitHub>,
|
||||
readonly artifact: string,
|
||||
readonly name: string,
|
||||
readonly pattern: string[],
|
||||
readonly sha: string,
|
||||
readonly runId: number
|
||||
) {
|
||||
if (this.artifact.startsWith('/')) {
|
||||
const re = new RegExp(this.artifact)
|
||||
this.artifactNameMatch = (str: string) => re.test(str)
|
||||
this.getReportName = (str: string) => {
|
||||
const match = str.match(re)
|
||||
if (match === null) {
|
||||
throw new Error(`Artifact name '${str}' does not match regex ${this.artifact}`)
|
||||
}
|
||||
let reportName = this.name
|
||||
for (let i = 1; i < match.length; i++) {
|
||||
reportName = reportName.replace(new RegExp(`$${i}`, 'g'), match[i])
|
||||
}
|
||||
return reportName
|
||||
}
|
||||
} else {
|
||||
this.artifactNameMatch = (str: string) => str === this.artifact
|
||||
this.getReportName = () => this.name
|
||||
}
|
||||
|
||||
this.fileNameMatch = picomatch(pattern)
|
||||
}
|
||||
|
||||
async load(): Promise<ReportInput> {
|
||||
const result: ReportInput = {}
|
||||
|
||||
const resp = await this.octokit.actions.listWorkflowRunArtifacts({
|
||||
...github.context.repo,
|
||||
run_id: this.runId
|
||||
})
|
||||
|
||||
const artifacts = resp.data.artifacts.filter(a => this.artifactNameMatch(a.name))
|
||||
for (const art of artifacts) {
|
||||
await downloadArtifact(this.octokit, art.id, art.name)
|
||||
const reportName = this.getReportName(art.name)
|
||||
const files: FileContent[] = []
|
||||
const zip = new Zip(art.name)
|
||||
for (const entry of zip.getEntries()) {
|
||||
const file = entry.name
|
||||
if (entry.isDirectory || !this.fileNameMatch(file)) continue
|
||||
const content = zip.readAsText(entry)
|
||||
files.push({file, content})
|
||||
}
|
||||
if (result[reportName]) {
|
||||
result[reportName].push(...files)
|
||||
} else {
|
||||
result[reportName] = files
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async listTrackedFiles(): Promise<string[]> {
|
||||
return listFiles(this.octokit, this.sha)
|
||||
}
|
||||
}
|
||||
13
src/input-providers/input-provider.ts
Normal file
13
src/input-providers/input-provider.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export interface ReportInput {
|
||||
[reportName: string]: FileContent[]
|
||||
}
|
||||
|
||||
export interface FileContent {
|
||||
file: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export interface InputProvider {
|
||||
load(): Promise<ReportInput>
|
||||
listTrackedFiles(): Promise<string[]>
|
||||
}
|
||||
25
src/input-providers/local-file-provider.ts
Normal file
25
src/input-providers/local-file-provider.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import * as fs from 'fs'
|
||||
import glob from 'fast-glob'
|
||||
import {FileContent, InputProvider, ReportInput} from './input-provider'
|
||||
import {listFiles} from '../utils/git'
|
||||
|
||||
export class LocalFileProvider implements InputProvider {
|
||||
constructor(readonly name: string, readonly pattern: string[]) {}
|
||||
|
||||
async load(): Promise<ReportInput> {
|
||||
const result: FileContent[] = []
|
||||
for (const pat of this.pattern) {
|
||||
const paths = await glob(pat, {dot: true})
|
||||
for (const file of paths) {
|
||||
const content = await fs.promises.readFile(file, {encoding: 'utf8'})
|
||||
result.push({file, content})
|
||||
}
|
||||
}
|
||||
|
||||
return {[this.name]: result}
|
||||
}
|
||||
|
||||
async listTrackedFiles(): Promise<string[]> {
|
||||
return listFiles()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue