Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ado-gha-axe-core): Add Job Summary to GH Action #1204

Merged
merged 2 commits into from Jun 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/gh-action/src/ioc/setup-ioc-container.ts
Expand Up @@ -10,20 +10,23 @@ import { GitHubIocTypes } from './gh-ioc-types';
import { CheckRunCreator } from '../check-run/check-run-creator';
import { GitHubArtifactsInfoProvider } from '../gh-artifacts-info-provider';
import { ConsoleCommentCreator } from '../console/console-comment-creator';
import { JobSummaryCreator } from '../job-summary/job-summary-creator';

export function setupIocContainer(container = new inversify.Container({ autoBindInjectable: true })): inversify.Container {
container = setupSharedIocContainer(container);
container.bind(GitHubIocTypes.Github).toConstantValue(github);
container.bind(iocTypes.TaskConfig).to(GHTaskConfig).inSingletonScope();
container.bind(CheckRunCreator).toSelf().inSingletonScope();
container.bind(JobSummaryCreator).toSelf().inSingletonScope();
container.bind(ConsoleCommentCreator).toSelf().inSingletonScope();
container
.bind(iocTypes.ProgressReporters)
.toDynamicValue((context) => {
const consoleCommentCreator = context.container.get(ConsoleCommentCreator);
const checkRunCreator = context.container.get(CheckRunCreator);
const jobSummaryCreator = context.container.get(JobSummaryCreator);

return [checkRunCreator, consoleCommentCreator];
return [checkRunCreator, consoleCommentCreator, jobSummaryCreator];
})
.inSingletonScope();

Expand Down
61 changes: 61 additions & 0 deletions packages/gh-action/src/job-summary/job-summary-creator.spec.ts
@@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import 'reflect-metadata';
import { IMock, Mock } from 'typemoq';
import { Logger, ReportMarkdownConvertor } from '@accessibility-insights-action/shared';
import { CombinedReportParameters } from 'accessibility-insights-report';
import { JobSummaryCreator } from './job-summary-creator';
import { GHTaskConfig } from '../task-config/gh-task-config';

describe(JobSummaryCreator, () => {
let testSubject: JobSummaryCreator;
let reportMarkdownConvertorMock: IMock<ReportMarkdownConvertor>;
let loggerMock: IMock<Logger>;
let taskConfigMock: IMock<GHTaskConfig>;

const markdownContent = 'test markdown content';
const combinedReportResult = { serviceName: 'combinedReportResult' } as CombinedReportParameters;

beforeEach(() => {
taskConfigMock = Mock.ofType<GHTaskConfig>();
reportMarkdownConvertorMock = Mock.ofType(ReportMarkdownConvertor);
loggerMock = Mock.ofType(Logger);
testSubject = new JobSummaryCreator(taskConfigMock.object, reportMarkdownConvertorMock.object, loggerMock.object);
});

afterEach(() => {
reportMarkdownConvertorMock.verifyAll();
loggerMock.verifyAll();
});

describe('start', () => {
it('does nothing', async () => {
await expect(testSubject.start()).resolves.toBeUndefined();
});
});

describe('didScanSucceed', () => {
it('returns true by default', async () => {
await expect(testSubject.didScanSucceed()).resolves.toBe(true);
});

it('returns false after failRun() is called', async () => {
await testSubject.failRun();
await expect(testSubject.didScanSucceed()).resolves.toBe(false);
});
});

describe('completeRun', () => {
it('converts to markdown and writes the job summary', async () => {
reportMarkdownConvertorMock
.setup((a) => a.convert(combinedReportResult))
.returns(() => markdownContent)
.verifiable();
taskConfigMock
.setup((a) => a.writeJobSummary(markdownContent))
.returns(() => Promise.resolve())
.verifiable();
await testSubject.completeRun(combinedReportResult);
});
});
});
39 changes: 39 additions & 0 deletions packages/gh-action/src/job-summary/job-summary-creator.ts
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { inject, injectable } from 'inversify';
import { iocTypes, Logger, ProgressReporter, ReportMarkdownConvertor } from '@accessibility-insights-action/shared';
import { CombinedReportParameters } from 'accessibility-insights-report';
import { GHTaskConfig } from '../task-config/gh-task-config';

@injectable()
export class JobSummaryCreator extends ProgressReporter {
private scanSucceeded = true;

constructor(
@inject(iocTypes.TaskConfig) private readonly taskConfig: GHTaskConfig,
@inject(ReportMarkdownConvertor) private readonly reportMarkdownConvertor: ReportMarkdownConvertor,
@inject(Logger) private readonly logger: Logger,
) {
super();
}

public start(): Promise<void> {
this.logger.logDebug('job summary creator started');
return Promise.resolve();
}

public async completeRun(combinedReportResult: CombinedReportParameters): Promise<void> {
const reportMarkdown = this.reportMarkdownConvertor.convert(combinedReportResult);
return await this.taskConfig.writeJobSummary(reportMarkdown);
}

// eslint-disable-next-line @typescript-eslint/require-await
public async failRun(): Promise<void> {
this.scanSucceeded = false;
}

public didScanSucceed(): Promise<boolean> {
return Promise.resolve(this.scanSucceeded);
}
}
17 changes: 17 additions & 0 deletions packages/gh-action/src/task-config/gh-task-config.spec.ts
Expand Up @@ -12,17 +12,20 @@ describe(GHTaskConfig, () => {
let processStub: any;
let actionCoreMock: IMock<typeof actionCore>;
let taskConfig: GHTaskConfig;
let markdownSummaryMock: IMock<typeof actionCore.summary>;

beforeEach(() => {
processStub = {
env: {},
} as any;
actionCoreMock = Mock.ofType<typeof actionCore>();
markdownSummaryMock = Mock.ofType<typeof actionCore.summary>();
taskConfig = new GHTaskConfig(processStub, actionCoreMock.object);
});

afterEach(() => {
actionCoreMock.verifyAll();
markdownSummaryMock.verifyAll();
});

function getPlatformAgnosticPath(inputPath: string): string {
Expand Down Expand Up @@ -126,4 +129,18 @@ describe(GHTaskConfig, () => {

expect(actualRunId).toBe(runId);
});

it('should write job summary', async () => {
const markdownStub = 'markdownStub';

markdownSummaryMock
.setup((o) => o.addRaw(markdownStub))
.returns(() => markdownSummaryMock.object)
.verifiable();
markdownSummaryMock.setup((o) => o.write()).verifiable();

actionCoreMock.setup((o) => o.summary).returns(() => markdownSummaryMock.object);

await taskConfig.writeJobSummary(markdownStub);
});
});
4 changes: 4 additions & 0 deletions packages/gh-action/src/task-config/gh-task-config.ts
Expand Up @@ -98,6 +98,10 @@ export class GHTaskConfig extends TaskConfig {
return keyToName[key];
}

public async writeJobSummary(jobSummaryMarkdown: string): Promise<void> {
await this.actionCoreObj.summary.addRaw(jobSummaryMarkdown).write();
}

public getUsageDocsUrl(): string {
const url = 'https://github.com/microsoft/accessibility-insights-action/blob/main/docs/gh-action-usage.md';
return url;
Expand Down