Skip to content

Commit

Permalink
feat: Add progress indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
ofekatr committed May 11, 2022
1 parent 73bba28 commit 764e0ce
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 15 deletions.
18 changes: 17 additions & 1 deletion src/cli/commands/test/iac/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ import * as utils from '../utils';
import {
formatIacTestFailures,
getIacDisplayErrorFileOutput,
iacTestTitle,
shouldLogUserMessages,
spinnerFailureMessage,
spinnerMessage,
spinnerSuccessMessage,
} from '../../../../lib/formatters/iac-output';
import { getEcosystemForTest, testEcosystem } from '../../../../lib/ecosystems';
import {
Expand Down Expand Up @@ -72,6 +75,7 @@ import {
import config from '../../../../lib/config';
import { UnsupportedEntitlementError } from '../../../../lib/errors/unsupported-entitlement-error';
import { failuresTipOutput } from '../../../../lib/formatters/iac-output';
import * as ora from 'ora';

const debug = Debug('snyk-test');
const SEPARATOR = '\n-------------------------------------------------------\n';
Expand Down Expand Up @@ -119,6 +123,8 @@ export default async function(
}
}

let testSpinner: ora.Ora | undefined;

const resultOptions: Array<Options & TestOptions> = [];
const results = [] as any[];

Expand All @@ -130,7 +136,9 @@ export default async function(
const isNewIacOutputSupported = await hasFeatureFlag('iacCliOutput', options);

if (shouldLogUserMessages(options, isNewIacOutputSupported)) {
console.log(EOL + spinnerMessage);
console.log(EOL + iacTestTitle + EOL);

testSpinner = ora({ isSilent: options.quiet, stream: process.stdout });
}

const orgPublicId = (options.org as string) ?? config.org;
Expand All @@ -141,6 +149,8 @@ export default async function(
}

try {
testSpinner?.start(spinnerMessage);

const rulesOrigin = await initRules(iacOrgSettings, options);

for (const path of paths) {
Expand Down Expand Up @@ -218,6 +228,12 @@ export default async function(
const notSuccess = errorResults.length > 0;
const foundVulnerabilities = vulnerableResults.length > 0;

if (notSuccess) {
testSpinner?.fail(spinnerFailureMessage + EOL);
} else {
testSpinner?.succeed(spinnerSuccessMessage);
}

// resultOptions is now an array of 1 or more options used for
// the tests results is now an array of 1 or more test results
// values depend on `options.json` value - string or object
Expand Down
3 changes: 3 additions & 0 deletions src/lib/formatters/iac-output/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ export {
formatIacTestSummary,
getIacDisplayedIssues,
formatIacTestFailures,
iacTestTitle,
spinnerMessage,
spinnerSuccessMessage,
spinnerFailureMessage,
shouldLogUserMessages,
formatShareResultsOutput,
failuresTipOutput,
Expand Down
8 changes: 7 additions & 1 deletion src/lib/formatters/iac-output/v2/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
export { getIacDisplayedIssues } from './issues-list';
export { formatIacTestSummary } from './test-summary';
export { spinnerMessage, shouldLogUserMessages } from './user-messages';
export {
iacTestTitle,
spinnerMessage,
spinnerSuccessMessage,
spinnerFailureMessage,
shouldLogUserMessages,
} from './user-messages';
export { formatShareResultsOutput } from './share-results';
export { formatIacTestFailures, failuresTipOutput } from './failures';
21 changes: 19 additions & 2 deletions src/lib/formatters/iac-output/v2/user-messages.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import { IaCTestFlags } from '../../../../cli/commands/test/iac/local-execution/types';
import { colors } from './color-utils';

/**
* Displayed as the title of the test output.
*/
export const iacTestTitle = colors.info.bold('Snyk Infrastructure as Code');

/**
* Progress indication message while files are tested.
*/
export const spinnerMessage = colors.info.bold(
'Snyk testing Infrastructure as Code configuration issues...',
export const spinnerMessage = colors.info(
'Snyk testing Infrastructure as Code configuration issues.',
);

/**
* Displayed when a test resolves successfully.
*/
export const spinnerSuccessMessage = colors.info('Test completed.');

/**
* Displayed when a test fails.
*/
export const spinnerFailureMessage = colors.info(
'Unable to complete the test.',
);

/**
Expand Down
66 changes: 55 additions & 11 deletions test/jest/acceptance/iac/iac-output.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import chalk from 'chalk';
import { EOL } from 'os';
import * as pathLib from 'path';
import {
spinnerFailureMessage,
spinnerMessage,
spinnerSuccessMessage,
} from '../../../../src/lib/formatters/iac-output';

import { FakeServer } from '../../../acceptance/fake-server';
import { startMockServer } from './helpers';
Expand All @@ -16,9 +22,6 @@ describe('iac test output', () => {
) => Promise<{ stdout: string; stderr: string; exitCode: number }>;
let teardown: () => Promise<unknown>;

const initialMessage =
'Snyk testing Infrastructure as Code configuration issues...';

beforeAll(async () => {
({ server, run, teardown } = await startMockServer());
});
Expand All @@ -36,13 +39,41 @@ describe('iac test output', () => {
server.setFeatureFlag(IAC_CLI_OUTPUT_FF, true);
});

it('should show an initial message', async () => {
const { stdout } = await run('snyk iac test ./iac/arm/rule_test.json');
it('should show the IaC test title', async () => {
// Arrange
const dirPath = './iac/terraform';

// Act
const { stdout } = await run(`snyk iac test ${dirPath}`);

// Assert
expect(stdout).toContain('Snyk Infrastructure as Code');
});

it('should show the spinner message', async () => {
// Arrange
const dirPath = './iac/terraform';

// Act
const { stdout } = await run(`snyk iac test ${dirPath}`);

// Arrange
expect(stdout).toContain(
'Snyk testing Infrastructure as Code configuration issues...',
'Snyk testing Infrastructure as Code configuration issues.',
);
});

it('should show the test completion message', async () => {
// Arrange
const dirPath = './iac/terraform';

// Act
const { stdout } = await run(`snyk iac test ${dirPath}`);

// Assert
expect(stdout).toContain('Test completed.');
});

it('should show the issues list section with correct values', async () => {
const { stdout } = await run('snyk iac test ./iac/arm/rule_test.json');

Expand Down Expand Up @@ -131,13 +162,15 @@ Target file: ${dirPath}/`);
${'JSON'} | ${'--json'}
${'SARIF'} | ${'--sarif'}
`(
'when providing the $dataFormatFlag flag',
({ dataFormat, dataFormatFlag }) => {
it(`should not show an initial message for ${dataFormat} output`, async () => {
'when providing the $dataFormatFlag flag for the $dataFormat format',
({ dataFormatFlag }) => {
it(`should not show spinner messages`, async () => {
const { stdout } = await run(
`snyk iac test ${dataFormatFlag} ./iac/arm/rule_test.json`,
);
expect(stdout).not.toContain(initialMessage);
expect(stdout).not.toContain(chalk.reset(spinnerMessage));
expect(stdout).not.toContain(chalk.reset(spinnerFailureMessage));
expect(stdout).not.toContain(chalk.reset(spinnerSuccessMessage));
});
},
);
Expand Down Expand Up @@ -201,6 +234,17 @@ Target file: ${dirPath}/`);
});

describe('with only test failures', () => {
it('should the test failure message', async () => {
// Arrange
const dirPath = 'iac/only-invalid';

// Act
const { stdout } = await run(`snyk iac test ${dirPath}`);

// Assert
expect(stdout).toContain('Unable to complete the test.');
});

it('should display the failure reason for the first failed test', async () => {
// Arrange
const dirPath = 'iac/only-invalid';
Expand Down Expand Up @@ -345,7 +389,7 @@ Project path: ${filePath}

it('should not show an initial message', async () => {
const { stdout } = await run('snyk iac test ./iac/arm/rule_test.json');
expect(stdout).not.toContain(initialMessage);
expect(stdout).not.toContain(chalk.reset(spinnerMessage));
});

it('should not show a subtitle for medium severity issues', async () => {
Expand Down

0 comments on commit 764e0ce

Please sign in to comment.