feat: add directory mapping to map between Docker image and local path

This commit is contained in:
Martin Fillafer 2023-03-27 10:44:43 +02:00
parent 3ec78ee9ff
commit 9b503434d1
6 changed files with 35 additions and 9 deletions

View file

@ -11,6 +11,7 @@ const input: Record<string, string> = {
'max-annotations': '10', 'max-annotations': '10',
'fail-on-error': 'true', 'fail-on-error': 'true',
'only-summary': 'false', 'only-summary': 'false',
'directory-mapping': 'mnt/extra-addons:mypath',
token: '***' token: '***'
} }
@ -56,7 +57,7 @@ describe('integration test', () => {
}) })
jest jest
.spyOn(LocalFileProvider.prototype, 'listTrackedFiles') .spyOn(LocalFileProvider.prototype, 'listTrackedFiles')
.mockResolvedValue(['addons/product_changes/tests/first_test.py']) .mockResolvedValue(['mypath/product_changes/tests/first_test.py'])
await import('../src/main') await import('../src/main')
// trick to wait for the pending "main" Promise // trick to wait for the pending "main" Promise
@ -68,7 +69,7 @@ describe('integration test', () => {
output: expect.objectContaining({ output: expect.objectContaining({
annotations: [ annotations: [
expect.objectContaining({ expect.objectContaining({
path: 'addons/product_changes/tests/first_test.py' path: 'mypath/product_changes/tests/first_test.py'
}) })
] ]
}) })

View file

@ -68,6 +68,11 @@ inputs:
Detailed listing of test suites and test cases will be skipped. Detailed listing of test suites and test cases will be skipped.
default: 'false' default: 'false'
required: false required: false
directory-mapping:
description: |
Map part of the file paths to something else, so they match the paths of the repository.
This is needed when you use run your code in a container with a different path than the source code repository.
required: false
token: token:
description: GitHub Access Token description: GitHub Access Token
required: false required: false

17
dist/index.js generated vendored
View file

@ -297,6 +297,7 @@ class TestReporter {
this.workDirInput = core.getInput('working-directory', { required: false }); this.workDirInput = core.getInput('working-directory', { required: false });
this.onlySummary = core.getInput('only-summary', { required: false }) === 'true'; this.onlySummary = core.getInput('only-summary', { required: false }) === 'true';
this.token = core.getInput('token', { required: true }); this.token = core.getInput('token', { required: true });
this.directoryMapping = core.getInput('directory-mapping', { required: true });
this.context = (0, github_utils_1.getCheckRunContext)(); this.context = (0, github_utils_1.getCheckRunContext)();
this.octokit = github.getOctokit(this.token); this.octokit = github.getOctokit(this.token);
if (this.listSuites !== 'all' && this.listSuites !== 'failed') { if (this.listSuites !== 'all' && this.listSuites !== 'failed') {
@ -329,12 +330,14 @@ class TestReporter {
const parseErrors = this.maxAnnotations > 0; const parseErrors = this.maxAnnotations > 0;
const trackedFiles = parseErrors ? yield inputProvider.listTrackedFiles() : []; const trackedFiles = parseErrors ? yield inputProvider.listTrackedFiles() : [];
const workDir = this.artifact ? undefined : (0, path_utils_1.normalizeDirPath)(process.cwd(), true); const workDir = this.artifact ? undefined : (0, path_utils_1.normalizeDirPath)(process.cwd(), true);
const [from, to] = this.directoryMapping.split(':');
if (parseErrors) if (parseErrors)
core.info(`Found ${trackedFiles.length} files tracked by GitHub`); core.info(`Found ${trackedFiles.length} files tracked by GitHub`);
const options = { const options = {
workDir, workDir,
trackedFiles, trackedFiles,
parseErrors parseErrors,
directoryMapping: { from, to }
}; };
core.info(`Using test report parser '${this.reporter}'`); core.info(`Using test report parser '${this.reporter}'`);
const parser = this.getParser(this.reporter, options); const parser = this.getParser(this.reporter, options);
@ -1495,25 +1498,31 @@ class PytestJunitParser {
const line = Number.parseInt(pos); const line = Number.parseInt(pos);
if (path && Number.isFinite(line)) { if (path && Number.isFinite(line)) {
return { return {
path: this.getAbsolutePath(path), path: this.applyDirectoryMapping(this.getAbsolutePath(path)),
line, line,
message: lines[1] message: lines[1]
}; };
} }
return undefined; return undefined;
} }
applyDirectoryMapping(path) {
if (this.options.directoryMapping && this.options.directoryMapping.from) {
return path.replace(this.options.directoryMapping.from, this.options.directoryMapping.to);
}
return path;
}
getRelativePath(path) { getRelativePath(path) {
path = (0, path_utils_1.normalizeFilePath)(path); path = (0, path_utils_1.normalizeFilePath)(path);
const workDir = this.getWorkDir(path); const workDir = this.getWorkDir(path);
if (workDir !== undefined && path.startsWith(workDir)) { if (workDir !== undefined && path.startsWith(workDir)) {
path = path.substring(workDir.length + 1); path = path.substring(workDir.length);
} }
return path; return path;
} }
getAbsolutePath(path) { getAbsolutePath(path) {
const relativePath = this.getRelativePath(path); const relativePath = this.getRelativePath(path);
for (const file of this.options.trackedFiles) { for (const file of this.options.trackedFiles) {
if (file.endsWith(relativePath)) { if (relativePath.endsWith(file)) {
return file; return file;
} }
} }

View file

@ -44,6 +44,7 @@ class TestReporter {
readonly workDirInput = core.getInput('working-directory', {required: false}) readonly workDirInput = core.getInput('working-directory', {required: false})
readonly onlySummary = core.getInput('only-summary', {required: false}) === 'true' readonly onlySummary = core.getInput('only-summary', {required: false}) === 'true'
readonly token = core.getInput('token', {required: true}) readonly token = core.getInput('token', {required: true})
readonly directoryMapping = core.getInput('directory-mapping', {required: true})
readonly octokit: InstanceType<typeof GitHub> readonly octokit: InstanceType<typeof GitHub>
readonly context = getCheckRunContext() readonly context = getCheckRunContext()
@ -94,13 +95,15 @@ class TestReporter {
const parseErrors = this.maxAnnotations > 0 const parseErrors = this.maxAnnotations > 0
const trackedFiles = parseErrors ? await inputProvider.listTrackedFiles() : [] const trackedFiles = parseErrors ? await inputProvider.listTrackedFiles() : []
const workDir = this.artifact ? undefined : normalizeDirPath(process.cwd(), true) const workDir = this.artifact ? undefined : normalizeDirPath(process.cwd(), true)
const [from, to] = this.directoryMapping.split(':')
if (parseErrors) core.info(`Found ${trackedFiles.length} files tracked by GitHub`) if (parseErrors) core.info(`Found ${trackedFiles.length} files tracked by GitHub`)
const options: ParseOptions = { const options: ParseOptions = {
workDir, workDir,
trackedFiles, trackedFiles,
parseErrors parseErrors,
directoryMapping: {from, to}
} }
core.info(`Using test report parser '${this.reporter}'`) core.info(`Using test report parser '${this.reporter}'`)

View file

@ -103,7 +103,7 @@ export class PytestJunitParser implements TestParser {
if (path && Number.isFinite(line)) { if (path && Number.isFinite(line)) {
return { return {
path: this.getAbsolutePath(path), path: this.applyDirectoryMapping(this.getAbsolutePath(path)),
line, line,
message: lines[1] message: lines[1]
} }
@ -112,11 +112,18 @@ export class PytestJunitParser implements TestParser {
return undefined return undefined
} }
private applyDirectoryMapping(path: string): string {
if (this.options.directoryMapping && this.options.directoryMapping.from) {
return path.replace(this.options.directoryMapping.from, this.options.directoryMapping.to)
}
return path
}
private getRelativePath(path: string): string { private getRelativePath(path: string): string {
path = normalizeFilePath(path) path = normalizeFilePath(path)
const workDir = this.getWorkDir(path) const workDir = this.getWorkDir(path)
if (workDir !== undefined && path.startsWith(workDir)) { if (workDir !== undefined && path.startsWith(workDir)) {
path = path.substring(workDir.length + 1) path = path.substring(workDir.length)
} }
return path return path
} }

View file

@ -4,6 +4,7 @@ export interface ParseOptions {
parseErrors: boolean parseErrors: boolean
workDir?: string workDir?: string
trackedFiles: string[] trackedFiles: string[]
directoryMapping?: {from: string; to: string}
} }
export interface TestParser { export interface TestParser {