This commit is contained in:
A. J. Kaptijn 2024-01-16 12:13:18 +01:00
parent 4da860cd59
commit 5473a04c5a
13 changed files with 22679 additions and 8953 deletions

View file

@ -1,123 +0,0 @@
import * as core from '@actions/core'
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,
readonly token: string
) {
if (this.artifact.startsWith('/')) {
const endIndex = this.artifact.lastIndexOf('/')
const rePattern = this.artifact.substring(1, endIndex)
const reOpts = this.artifact.substring(endIndex + 1)
const re = new RegExp(rePattern, reOpts)
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 = {
artifactFilePaths: [],
reports: {}
}
const resp = await this.octokit.rest.actions.listWorkflowRunArtifacts({
...github.context.repo,
run_id: this.runId
})
if (resp.data.artifacts.length === 0) {
core.warning(`No artifacts found in run ${this.runId}`)
return result
}
const artifacts = resp.data.artifacts.filter(a => this.artifactNameMatch(a.name))
if (artifacts.length === 0) {
core.warning(`No artifact matches ${this.artifact}`)
return result
}
const versionArtifact = resp.data.artifacts.find(a => a.name === 'version.txt')
if (versionArtifact) {
await downloadArtifact(this.octokit, versionArtifact.id, 'version.txt', this.token)
result.versionArtifactPath = 'version.txt'
} else {
core.warning(
`Could not find version.txt artifact among these artifacts: ${resp.data.artifacts.map(a => a.name).join(', ')}`
)
}
for (const art of artifacts) {
const fileName = `${art.name}.zip`
result.artifactFilePaths.push(fileName)
await downloadArtifact(this.octokit, art.id, fileName, this.token)
core.startGroup(`Reading archive ${fileName}`)
try {
const reportName = this.getReportName(art.name)
core.info(`Report name: ${reportName}`)
const files: FileContent[] = []
const zip = new Zip(fileName)
for (const entry of zip.getEntries()) {
const file = entry.entryName
if (entry.isDirectory) {
core.info(`Skipping ${file}: entry is a directory`)
continue
}
if (!this.fileNameMatch(file)) {
core.info(`Skipping ${file}: filename does not match pattern`)
continue
}
const content = zip.readAsText(entry)
files.push({file, content})
core.info(`Read ${file}: ${content.length} chars`)
}
if (result.reports[reportName]) {
result.reports[reportName].push(...files)
} else {
result.reports[reportName] = files
}
} finally {
core.endGroup()
}
}
return result
}
async listTrackedFiles(): Promise<string[]> {
return listFiles(this.octokit, this.sha)
}
}

View file

@ -1,6 +1,7 @@
import Zip from 'adm-zip'
export interface ReportInput {
artifactFilePaths: string[]
versionArtifactPath?: string
trxZip: Zip
reports: {
[reportName: string]: FileContent[]
}

View file

@ -2,6 +2,8 @@ import * as fs from 'fs'
import glob from 'fast-glob'
import {FileContent, InputProvider, ReportInput} from './input-provider.js'
import {listFiles} from '../utils/git.js'
import Zip from 'adm-zip'
import path from 'path'
export class LocalFileProvider implements InputProvider {
constructor(
@ -11,16 +13,19 @@ export class LocalFileProvider implements InputProvider {
async load(): Promise<ReportInput> {
const result: FileContent[] = []
const zip = new Zip()
for (const pat of this.pattern) {
const paths = await glob(pat, {dot: true})
for (const file of paths) {
const dir = path.dirname(file)
zip.addLocalFile(file, dir)
const content = await fs.promises.readFile(file, {encoding: 'utf8'})
result.push({file, content})
}
}
return {
artifactFilePaths: [],
trxZip: zip,
reports: {
[this.name]: result
}

View file

@ -2,7 +2,6 @@ import * as core from '@actions/core'
import * as github from '@actions/github'
import {GitHub} from '@actions/github/lib/utils.js'
import {ArtifactProvider} from './input-providers/artifact-provider.js'
import {LocalFileProvider} from './input-providers/local-file-provider.js'
import {FileContent} from './input-providers/input-provider.js'
import {ParseOptions, TestParser} from './test-parser.js'
@ -10,19 +9,14 @@ import {TestRunResult} from './test-results.js'
import {getAnnotations} from './report/get-annotations.js'
import {getReport} from './report/get-report.js'
import {DartJsonParser} from './parsers/dart-json/dart-json-parser.js'
import {DotnetTrxParser} from './parsers/dotnet-trx/dotnet-trx-parser.js'
import {JavaJunitParser} from './parsers/java-junit/java-junit-parser.js'
import {JestJunitParser} from './parsers/jest-junit/jest-junit-parser.js'
import {MochaJsonParser} from './parsers/mocha-json/mocha-json-parser.js'
import {SwiftXunitParser} from './parsers/swift-xunit/swift-xunit-parser.js'
import {normalizeDirPath, normalizeFilePath} from './utils/path-utils.js'
import {getCheckRunContext} from './utils/github-utils.js'
import {IncomingWebhook} from '@slack/webhook'
import fs from 'fs'
import bent from 'bent'
import { cwd } from 'process';
import {cwd} from 'process'
async function main(): Promise<void> {
try {
@ -86,17 +80,7 @@ class TestReporter {
const pathsList = this.path.split(',')
const pattern = this.pathReplaceBackslashes ? pathsList.map(normalizeFilePath) : pathsList
const inputProvider = this.artifact
? new ArtifactProvider(
this.octokit,
this.artifact,
this.name,
pattern,
this.context.sha,
this.context.runId,
this.token
)
: new LocalFileProvider(this.name, pattern)
const inputProvider = new LocalFileProvider(this.name, pattern)
const parseErrors = this.maxAnnotations > 0
const trackedFiles = parseErrors ? await inputProvider.listTrackedFiles() : []
@ -116,7 +100,6 @@ class TestReporter {
const results: TestRunResult[] = []
const input = await inputProvider.load()
try {
const readStream = input.trxZip.toBuffer()
const version = fs.existsSync('test/EVA.TestSuite.Core/bin/Release/version.txt')
@ -126,7 +109,9 @@ class TestReporter {
? fs.readFileSync('test/EVA.TestSuite.Core/bin/Release/commit.txt').toString()
: null
core.info(`Using EVA version ${version}, commit ${commitID}, branch ${this.context.branch}, current directory: ${cwd()}`)
core.info(
`Using EVA version ${version}, commit ${commitID}, branch ${this.context.branch}, current directory: ${cwd()}`
)
const post = bent(this.resultsEndpoint, 'POST', {}, 200)
await post(
@ -278,20 +263,8 @@ class TestReporter {
getParser(reporter: string, options: ParseOptions): TestParser {
switch (reporter) {
case 'dart-json':
return new DartJsonParser(options, 'dart')
case 'dotnet-trx':
return new DotnetTrxParser(options)
case 'flutter-json':
return new DartJsonParser(options, 'flutter')
case 'java-junit':
return new JavaJunitParser(options)
case 'jest-junit':
return new JestJunitParser(options)
case 'mocha-json':
return new MochaJsonParser(options)
case 'swift-xunit':
return new SwiftXunitParser(options)
default:
throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`)
}

View file

@ -1,5 +1,5 @@
import * as core from '@actions/core'
import { getExecOutput } from '@actions/exec'
import {getExecOutput} from '@actions/exec'
export async function listFiles(): Promise<string[]> {
core.startGroup('Listing all files tracked by git')

View file

@ -28,7 +28,7 @@ export function getCheckRunContext(): {sha: string; runId: number; branch: strin
const runId = github.context.runId
if (github.context.payload.pull_request) {
core.info(`Action was triggered by ${github.context.eventName}: using SHA from head of source branch`)
const pr = github.context.payload.pull_request;
const pr = github.context.payload.pull_request
return {sha: pr.head.sha, runId, branch}
}