Merge branch 'main' into pr-179

This commit is contained in:
Michal Dorner 2022-11-30 18:40:51 +01:00
commit b45fb8b405
No known key found for this signature in database
GPG key ID: 7325B8B59CA1B65C
47 changed files with 24483 additions and 18386 deletions

View file

@ -50,7 +50,7 @@ export class ArtifactProvider implements InputProvider {
async load(): Promise<ReportInput> {
const result: ReportInput = {}
const resp = await this.octokit.actions.listWorkflowRunArtifacts({
const resp = await this.octokit.rest.actions.listWorkflowRunArtifacts({
...github.context.repo,
run_id: this.runId
})

View file

@ -25,7 +25,8 @@ async function main(): Promise<void> {
const testReporter = new TestReporter()
await testReporter.run()
} catch (error) {
core.setFailed(error.message)
if (error instanceof Error) core.setFailed(error)
else core.setFailed(JSON.stringify(error))
}
}
@ -153,7 +154,7 @@ class TestReporter {
}
core.info(`Creating check run ${name}`)
const createResp = await this.octokit.checks.create({
const createResp = await this.octokit.rest.checks.create({
head_sha: this.context.sha,
name,
status: 'in_progress',
@ -166,18 +167,18 @@ class TestReporter {
core.info('Creating report summary')
const {listSuites, listTests, onlySummary} = this
const baseUrl = createResp.data.html_url
const baseUrl = createResp.data.html_url as string
const summary = getReport(results, {listSuites, listTests, baseUrl, onlySummary})
core.info('Creating annotations')
const annotations = getAnnotations(results, this.maxAnnotations)
const isFailed = results.some(tr => tr.result === 'failed')
const isFailed = this.failOnError && results.some(tr => tr.result === 'failed')
const conclusion = isFailed ? 'failure' : 'success'
const icon = isFailed ? Icon.fail : Icon.success
core.info(`Updating check run conclusion (${conclusion}) and output`)
const resp = await this.octokit.checks.update({
const resp = await this.octokit.rest.checks.update({
check_run_id: createResp.data.id,
conclusion,
status: 'completed',

View file

@ -92,7 +92,8 @@ export class DartJsonParser implements TestParser {
try {
return JSON.parse(str)
} catch (e) {
const col = e.columnNumber !== undefined ? `:${e.columnNumber}` : ''
const errWithCol = e as {columnNumber?: number}
const col = errWithCol.columnNumber !== undefined ? `:${errWithCol.columnNumber}` : ''
throw new Error(`Invalid JSON at ${path}:${i + 1}${col}\n\n${e}`)
}
})
@ -194,7 +195,8 @@ export class DartJsonParser implements TestParser {
private getErrorMessage(message: string, print: string): string {
if (this.sdk === 'flutter') {
const uselessMessageRe = /^Test failed\. See exception logs above\.\nThe test description was:/m
const flutterPrintRe = /^ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK +\s+(.*)\s+When the exception was thrown, this was the stack:/ms
const flutterPrintRe =
/^ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK +\s+(.*)\s+When the exception was thrown, this was the stack:/ms
if (uselessMessageRe.test(message)) {
const match = print.match(flutterPrintRe)
if (match !== null) {

View file

@ -3,6 +3,7 @@ import {ParseOptions, TestParser} from '../../test-parser'
import {parseStringPromise} from 'xml2js'
import {JunitReport, SingleSuiteReport, TestCase, TestSuite} from './java-junit-types'
import {parseStackTraceElement} from './java-stack-trace-element-parser'
import {normalizeFilePath} from '../../utils/path-utils'
import {
@ -128,10 +129,12 @@ export class JavaJunitParser implements TestParser {
let filePath
let line
const src = this.exceptionThrowSource(details)
if (src) {
filePath = src.filePath
line = src.line
if (details != null) {
const src = this.exceptionThrowSource(details)
if (src) {
filePath = src.filePath
line = src.line
}
}
return {
@ -144,12 +147,11 @@ export class JavaJunitParser implements TestParser {
private exceptionThrowSource(stackTrace: string): {filePath: string; line: number} | undefined {
const lines = stackTrace.split(/\r?\n/)
const re = /^at (.*)\((.*):(\d+)\)$/
for (const str of lines) {
const match = str.match(re)
if (match !== null) {
const [_, tracePath, fileName, lineStr] = match
const stackTraceElement = parseStackTraceElement(str)
if (stackTraceElement) {
const {tracePath, fileName, lineStr} = stackTraceElement
const filePath = this.getFilePath(tracePath, fileName)
if (filePath !== undefined) {
const line = parseInt(lineStr)

View file

@ -0,0 +1,44 @@
export interface StackTraceElement {
classLoader: string | undefined
moduleNameAndVersion: string | undefined
tracePath: string
fileName: string
lineStr: string
}
// classloader and module name are optional:
// at <CLASSLOADER>/<MODULE_NAME_AND_VERSION>/<FULLY_QUALIFIED_METHOD_NAME>(<FILE_NAME>:<LINE_NUMBER>)
// https://github.com/eclipse-openj9/openj9/issues/11452#issuecomment-754946992
const re = /^\s*at (\S+\/\S*\/)?(.*)\((.*):(\d+)\)$/
export function parseStackTraceElement(stackTraceLine: string): StackTraceElement | undefined {
const match = stackTraceLine.match(re)
if (match !== null) {
const [_, maybeClassLoaderAndModuleNameAndVersion, tracePath, fileName, lineStr] = match
const {classLoader, moduleNameAndVersion} = parseClassLoaderAndModule(maybeClassLoaderAndModuleNameAndVersion)
return {
classLoader,
moduleNameAndVersion,
tracePath,
fileName,
lineStr
}
}
return undefined
}
function parseClassLoaderAndModule(maybeClassLoaderAndModuleNameAndVersion?: string): {
classLoader?: string
moduleNameAndVersion?: string
} {
if (maybeClassLoaderAndModuleNameAndVersion) {
const res = maybeClassLoaderAndModuleNameAndVersion.split('/')
const classLoader = res[0]
let moduleNameAndVersion: string | undefined = res[1]
if (moduleNameAndVersion === '') {
moduleNameAndVersion = undefined
}
return {classLoader, moduleNameAndVersion}
}
return {classLoader: undefined, moduleNameAndVersion: undefined}
}

View file

@ -48,6 +48,10 @@ export class JestJunitParser implements TestParser {
}
private getGroups(suite: TestSuite): TestGroupResult[] {
if (!suite.testcase) {
return []
}
const groups: {describe: string; tests: TestCase[]}[] = []
for (const tc of suite.testcase) {
let grp = groups.find(g => g.describe === tc.$.classname)

View file

@ -19,7 +19,7 @@ export interface TestSuite {
time: string
timestamp?: Date
}
testcase: TestCase[]
testcase?: TestCase[]
}
export interface TestCase {

View file

@ -1,6 +1,7 @@
import * as core from '@actions/core'
import {TestExecutionResult, TestRunResult, TestSuiteResult} from '../test-results'
import {Align, formatTime, Icon, link, table} from '../utils/markdown-utils'
import {DEFAULT_LOCALE} from '../utils/node-utils'
import {getFirstNonEmptyLine} from '../utils/parse-utils'
import {slug} from '../utils/slugger'
@ -79,9 +80,9 @@ function trimReport(lines: string[]): string {
}
function applySort(results: TestRunResult[]): void {
results.sort((a, b) => a.path.localeCompare(b.path))
results.sort((a, b) => a.path.localeCompare(b.path, DEFAULT_LOCALE))
for (const res of results) {
res.suites.sort((a, b) => a.name.localeCompare(b.name))
res.suites.sort((a, b) => a.name.localeCompare(b.name, DEFAULT_LOCALE))
}
}

View file

@ -1,3 +1,5 @@
import {DEFAULT_LOCALE} from './utils/node-utils'
export class TestRunResult {
constructor(readonly path: string, readonly suites: TestSuiteResult[], private totalTime?: number) {}
@ -28,7 +30,7 @@ export class TestRunResult {
}
sort(deep: boolean): void {
this.suites.sort((a, b) => a.name.localeCompare(b.name))
this.suites.sort((a, b) => a.name.localeCompare(b.name, DEFAULT_LOCALE))
if (deep) {
for (const suite of this.suites) {
suite.sort(deep)
@ -66,7 +68,7 @@ export class TestSuiteResult {
}
sort(deep: boolean): void {
this.groups.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''))
this.groups.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? '', DEFAULT_LOCALE))
if (deep) {
for (const grp of this.groups) {
grp.sort()
@ -100,7 +102,7 @@ export class TestGroupResult {
}
sort(): void {
this.tests.sort((a, b) => a.name.localeCompare(b.name))
this.tests.sort((a, b) => a.name.localeCompare(b.name, DEFAULT_LOCALE))
}
}

View file

@ -1,21 +0,0 @@
import {exec as execImpl, ExecOptions} from '@actions/exec'
// Wraps original exec() function
// Returns exit code and whole stdout/stderr
export default async function exec(commandLine: string, args?: string[], options?: ExecOptions): Promise<ExecResult> {
options = options || {}
let stdout = ''
let stderr = ''
options.listeners = {
stdout: (data: Buffer) => (stdout += data.toString()),
stderr: (data: Buffer) => (stderr += data.toString())
}
const code = await execImpl(commandLine, args, options)
return {code, stdout, stderr}
}
export interface ExecResult {
code: number
stdout: string
stderr: string
}

View file

@ -1,11 +1,11 @@
import * as core from '@actions/core'
import exec from './exec'
import {getExecOutput} from '@actions/exec'
export async function listFiles(): Promise<string[]> {
core.startGroup('Listing all files tracked by git')
let output = ''
try {
output = (await exec('git', ['ls-files', '-z'])).stdout
output = (await getExecOutput('git', ['ls-files', '-z'])).stdout
} finally {
fixStdOutNullTermination()
core.endGroup()

View file

@ -2,7 +2,7 @@ import {createWriteStream} from 'fs'
import * as core from '@actions/core'
import * as github from '@actions/github'
import {GitHub} from '@actions/github/lib/utils'
import {EventPayloads} from '@octokit/webhooks'
import type {PullRequest} from '@octokit/webhooks-types'
import * as stream from 'stream'
import {promisify} from 'util'
import got from 'got'
@ -11,7 +11,7 @@ const asyncStream = promisify(stream.pipeline)
export function getCheckRunContext(): {sha: string; runId: number} {
if (github.context.eventName === 'workflow_run') {
core.info('Action was triggered by workflow_run: using SHA and RUN_ID from triggering workflow')
const event = github.context.payload as EventPayloads.WebhookPayloadWorkflowRun
const event = github.context.payload
if (!event.workflow_run) {
throw new Error("Event of type 'workflow_run' is missing 'workflow_run' field")
}
@ -24,7 +24,7 @@ export function getCheckRunContext(): {sha: string; runId: number} {
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 as EventPayloads.WebhookPayloadPullRequestPullRequest
const pr = github.context.payload.pull_request as PullRequest
return {sha: pr.head.sha, runId}
}
@ -41,7 +41,7 @@ export async function downloadArtifact(
try {
core.info(`Artifact ID: ${artifactId}`)
const req = octokit.actions.downloadArtifact.endpoint({
const req = octokit.rest.actions.downloadArtifact.endpoint({
...github.context.repo,
artifact_id: artifactId,
archive_format: 'zip'
@ -86,7 +86,7 @@ export async function downloadArtifact(
export async function listFiles(octokit: InstanceType<typeof GitHub>, sha: string): Promise<string[]> {
core.startGroup('Fetching list of tracked files from GitHub')
try {
const commit = await octokit.git.getCommit({
const commit = await octokit.rest.git.getCommit({
commit_sha: sha,
...github.context.repo
})
@ -101,7 +101,7 @@ async function listGitTree(octokit: InstanceType<typeof GitHub>, sha: string, pa
const pathLog = path ? ` at ${path}` : ''
core.info(`Fetching tree ${sha}${pathLog}`)
let truncated = false
let tree = await octokit.git.getTree({
let tree = await octokit.rest.git.getTree({
recursive: 'true',
tree_sha: sha,
...github.context.repo
@ -109,7 +109,7 @@ async function listGitTree(octokit: InstanceType<typeof GitHub>, sha: string, pa
if (tree.data.truncated) {
truncated = true
tree = await octokit.git.getTree({
tree = await octokit.rest.git.getTree({
tree_sha: sha,
...github.context.repo
})
@ -121,7 +121,7 @@ async function listGitTree(octokit: InstanceType<typeof GitHub>, sha: string, pa
if (tr.type === 'blob') {
result.push(file)
} else if (tr.type === 'tree' && truncated) {
const files = await listGitTree(octokit, tr.sha, `${file}/`)
const files = await listGitTree(octokit, tr.sha as string, `${file}/`)
result.push(...files)
}
}

View file

@ -6,8 +6,8 @@ export enum Align {
}
export const Icon = {
skip: '✖️', // ':heavy_multiplication_x:'
success: '✔️', // ':heavy_check_mark:'
skip: '⚪', // ':white_circle:'
success: '✅', // ':white_check_mark:'
fail: '❌' // ':x:'
}

View file

@ -1,5 +1,7 @@
import {normalizeFilePath} from './path-utils'
export const DEFAULT_LOCALE = 'en-US'
export function getExceptionSource(
stackTrace: string,
trackedFiles: string[],