-
Notifications
You must be signed in to change notification settings - Fork 54
NEW @W-16891765@ Config action mentions outfile #1649
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # common.summary-header | ||
|
|
||
| Summary | ||
|
|
||
| # common.logfile-location | ||
|
|
||
| Additional log information written to: | ||
|
|
||
| # config-action.no-outfiles | ||
|
|
||
| No output file was specified. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Analogous to |
||
|
|
||
| # config-action.outfile-location | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Analogous to |
||
|
|
||
| Configuration written to: | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -114,7 +114,9 @@ abstract class YamlFormatter { | |
| this.toYamlRuleOverrides() + '\n' + | ||
| '\n' + | ||
| this.toYamlComment(topLevelDescription.fieldDescriptions!.engines) + '\n' + | ||
| this.toYamlEngineOverrides() + '\n'; | ||
| this.toYamlEngineOverrides() + '\n' + | ||
| '\n' + | ||
| this.toYamlSectionHeadingComment(getMessage(BundleName.ConfigModel, 'template.common.end-of-config')) + '\n'; | ||
|
Comment on lines
+117
to
+119
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this end of config message might end up in the file as well. I was hoping it would just be for the terminal output only. |
||
| } | ||
|
|
||
| private toYamlRuleOverrides(): string { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import {Display} from '../Display'; | ||
| import {toStyledHeader, indent} from '../utils/StylingUtil'; | ||
| import {BundleName, getMessage} from '../messages'; | ||
|
|
||
| abstract class AbstractActionSummaryViewer { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's only one child class right now, but the parent class will be helpful for porting the Run Summary Viewer to the new style. |
||
| protected readonly display: Display; | ||
|
|
||
| protected constructor(display: Display) { | ||
| this.display = display; | ||
| } | ||
|
|
||
| protected displaySummaryHeader(): void { | ||
| this.display.displayLog(toStyledHeader(getMessage(BundleName.ActionSummaryViewer, 'common.summary-header'))); | ||
| } | ||
|
|
||
| protected displayLineSeparator(): void { | ||
| this.display.displayLog(""); | ||
| } | ||
|
|
||
| protected displayLogFileInfo(logFile: string): void { | ||
| this.display.displayLog(getMessage(BundleName.ActionSummaryViewer, 'common.logfile-location')); | ||
| this.display.displayLog(indent(logFile)); | ||
| } | ||
| } | ||
|
|
||
| export class ConfigActionSummaryViewer extends AbstractActionSummaryViewer { | ||
| public constructor(display: Display) { | ||
| super(display); | ||
| } | ||
|
|
||
| public view(logFile: string, outfile?: string): void { | ||
| this.displaySummaryHeader(); | ||
| this.displayLineSeparator(); | ||
|
|
||
| if (outfile) { | ||
| this.displayOutfile(outfile); | ||
| } else { | ||
| this.display.displayLog(getMessage(BundleName.ActionSummaryViewer, 'config-action.no-outfiles')); | ||
| } | ||
| this.displayLineSeparator(); | ||
|
|
||
| this.displayLogFileInfo(logFile); | ||
| } | ||
|
|
||
| private displayOutfile(outfile: string): void { | ||
| this.display.displayLog(getMessage(BundleName.ActionSummaryViewer, 'config-action.outfile-location')); | ||
| this.display.displayLog(indent(outfile)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,7 @@ import {Display} from '../Display'; | |
| import {exists} from '../utils/FileUtil'; | ||
|
|
||
| export interface ConfigWriter { | ||
| write(model: ConfigModel): Promise<void>; | ||
| write(model: ConfigModel): Promise<boolean>; | ||
| } | ||
|
|
||
| export class ConfigFileWriter implements ConfigWriter { | ||
|
|
@@ -20,10 +20,13 @@ export class ConfigFileWriter implements ConfigWriter { | |
| this.display = display; | ||
| } | ||
|
|
||
| public async write(model: ConfigModel): Promise<void> { | ||
| public async write(model: ConfigModel): Promise<boolean> { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this method isn't guaranteed to actually write anything, it now returns a boolean to indicate whether it did. |
||
| // Only write to the file if it doesn't already exist, or if the user confirms that they want to overwrite it. | ||
| if (!(await exists(this.file)) || await this.display.confirm(getMessage(BundleName.ConfigWriter, 'prompt.overwrite-existing-file', [this.file]))) { | ||
| fs.writeFileSync(this.file, model.toFormattedOutput(this.format)); | ||
| return true; | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| === Summary | ||
|
|
||
| No output file was specified. | ||
|
|
||
| Additional log information written to: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| === Summary | ||
|
|
||
| Configuration written to: | ||
| out-config.yml | ||
|
|
||
| Additional log information written to: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # ====================================================================== | ||
| # END OF CODE ANALYZER CONFIGURATION | ||
| # ====================================================================== |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,8 @@ import {CodeAnalyzerConfigFactory} from "../../../src/lib/factories/CodeAnalyzer | |
| import {EnginePluginsFactory} from '../../../src/lib/factories/EnginePluginsFactory'; | ||
| import {ConfigAction, ConfigDependencies, ConfigInput} from '../../../src/lib/actions/ConfigAction'; | ||
| import {AnnotatedConfigModel} from '../../../src/lib/models/ConfigModel'; | ||
| import {ConfigStyledYamlViewer} from '../../../lib/lib/viewers/ConfigViewer'; | ||
| import {ConfigStyledYamlViewer} from '../../../src/lib/viewers/ConfigViewer'; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Import path was wrong here. |
||
| import {ConfigActionSummaryViewer} from '../../../src/lib/viewers/ActionSummaryViewer'; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Testing through |
||
|
|
||
| import {SpyConfigWriter} from '../../stubs/SpyConfigWriter'; | ||
| import {DisplayEventType, SpyDisplay} from '../../stubs/SpyDisplay'; | ||
|
|
@@ -36,17 +37,21 @@ describe('ConfigAction tests', () => { | |
| viewer: new ConfigStyledYamlViewer(spyDisplay), | ||
| configFactory: new DefaultStubCodeAnalyzerConfigFactory(), | ||
| modelGenerator: AnnotatedConfigModel.fromSelection, | ||
| actionSummaryViewer: new ConfigActionSummaryViewer(spyDisplay), | ||
| pluginsFactory: new StubEnginePluginFactory() | ||
| }; | ||
| }); | ||
|
|
||
| it('Top-level overview-comment is correct', async () => { | ||
| it.each([ | ||
| {position: 'start'}, | ||
| {position: 'end'} | ||
| ])('Top-level $position comment is correct', async ({position}) => { | ||
| // ==== TESTED BEHAVIOR ==== | ||
| // Just select all rules for this test, since we don't care about the rules here. | ||
| const output = await runActionAndGetDisplayedConfig(dependencies, ['all']); | ||
|
|
||
| // ==== ASSERTIONS ==== | ||
| const goldFileContents = await readGoldFile(path.join(PATH_TO_COMPARISON_DIR, 'header-comments', 'top-level.yml.goldfile')); | ||
| const goldFileContents = await readGoldFile(path.join(PATH_TO_COMPARISON_DIR, 'header-comments', `top-level-${position}.yml.goldfile`)); | ||
| expect(output).toContain(goldFileContents); | ||
| }); | ||
|
|
||
|
|
@@ -159,12 +164,16 @@ describe('ConfigAction tests', () => { | |
| viewer: new ConfigStyledYamlViewer(spyDisplay), | ||
| configFactory: stubConfigFactory, | ||
| modelGenerator: AnnotatedConfigModel.fromSelection, | ||
| actionSummaryViewer: new ConfigActionSummaryViewer(spyDisplay), | ||
| pluginsFactory: new StubEnginePluginFactory() | ||
| }; | ||
| }); | ||
|
|
||
|
|
||
| it('Top-level overview-comment is correct', async () => { | ||
| it.each([ | ||
| {position: 'start'}, | ||
| {position: 'end'} | ||
| ])('Top-level $position comment is correct', async ({position}) => { | ||
| // ==== SETUP ==== | ||
| // Set the dummy config properties to null; it's fine for this test. | ||
| stubConfigFactory.setDummyConfigRoot('null'); | ||
|
|
@@ -175,7 +184,7 @@ describe('ConfigAction tests', () => { | |
| const output = await runActionAndGetDisplayedConfig(dependencies, ['all']); | ||
|
|
||
| // ==== ASSERTIONS ==== | ||
| const goldFileContents = await readGoldFile(path.join(PATH_TO_COMPARISON_DIR, 'header-comments', 'top-level.yml.goldfile')); | ||
| const goldFileContents = await readGoldFile(path.join(PATH_TO_COMPARISON_DIR, 'header-comments', `top-level-${position}.yml.goldfile`)); | ||
| expect(output).toContain(goldFileContents); | ||
| }); | ||
|
|
||
|
|
@@ -389,6 +398,7 @@ describe('ConfigAction tests', () => { | |
| viewer: new ConfigStyledYamlViewer(spyDisplay), | ||
| configFactory: new DefaultStubCodeAnalyzerConfigFactory(), | ||
| modelGenerator: AnnotatedConfigModel.fromSelection, | ||
| actionSummaryViewer: new ConfigActionSummaryViewer(spyDisplay), | ||
| pluginsFactory: new StubEnginePluginFactory() | ||
| }; | ||
| }); | ||
|
|
@@ -406,6 +416,74 @@ describe('ConfigAction tests', () => { | |
| expect(spyWriter.getCallHistory()).toHaveLength(1); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Summary generation', () => { | ||
| beforeEach(() => { | ||
| spyDisplay = new SpyDisplay(); | ||
| dependencies = { | ||
| logEventListeners: [], | ||
| progressEventListeners: [], | ||
| viewer: new ConfigStyledYamlViewer(spyDisplay), | ||
| configFactory: new DefaultStubCodeAnalyzerConfigFactory(), | ||
| modelGenerator: AnnotatedConfigModel.fromSelection, | ||
| actionSummaryViewer: new ConfigActionSummaryViewer(spyDisplay), | ||
| pluginsFactory: new StubEnginePluginFactory() | ||
| } | ||
| }); | ||
|
|
||
| it('When an Outfile is created, it is mentioned by the Summarizer', async () => { | ||
| // ==== SETUP ==== | ||
| // Assign a Writer to the dependencies. | ||
| dependencies.writer = new SpyConfigWriter(true); | ||
|
|
||
| // ==== TESTED BEHAVIOR ==== | ||
| // Invoke the action, specifying an outfile. | ||
| const action = ConfigAction.createAction(dependencies); | ||
| const input: ConfigInput = { | ||
| 'rule-selector': ['all'], | ||
| 'output-file': 'out-config.yml' | ||
| }; | ||
| await action.execute(input); | ||
|
|
||
| // ==== ASSERTIONS ==== | ||
| const displayEvents = spyDisplay.getDisplayEvents(); | ||
| const displayedLogEvents = ansis.strip(displayEvents | ||
| .filter(e => e.type === DisplayEventType.LOG) | ||
| .map(e => e.data) | ||
| .join('\n')); | ||
|
|
||
| const goldfileContents: string = await readGoldFile(path.join(PATH_TO_COMPARISON_DIR, 'action-summaries', 'outfile-created.txt.goldfile')); | ||
| expect(displayedLogEvents).toContain(goldfileContents); | ||
| }); | ||
|
|
||
| it.each([ | ||
| {case: 'an Outfile is specified but not written', writer: new SpyConfigWriter(false), outfile: 'out-config.yml'}, | ||
| {case: 'an Outfile is not specified at all', writer: undefined, outfile: undefined} | ||
| ])('When $case, the Summarizer mentions no outfile', async ({writer, outfile}) => { | ||
| // ==== SETUP ==== | ||
| // Add the specified Writer (or lack-of-Writer) to the dependencies. | ||
| dependencies.writer = writer; | ||
|
|
||
| // ==== TESTED BEHAVIOR ==== | ||
| // Invoke the action, specifying an outfile (or lack of one). | ||
| const action = ConfigAction.createAction(dependencies); | ||
| const input: ConfigInput = { | ||
| 'rule-selector': ['all'], | ||
| 'output-file': outfile | ||
| }; | ||
| await action.execute(input); | ||
|
|
||
| // ==== ASSERTIONS ==== | ||
| const displayEvents = spyDisplay.getDisplayEvents(); | ||
| const displayedLogEvents = ansis.strip(displayEvents | ||
| .filter(e => e.type === DisplayEventType.LOG) | ||
| .map(e => e.data) | ||
| .join('\n')); | ||
|
|
||
| const goldfileContents: string = await readGoldFile(path.join(PATH_TO_COMPARISON_DIR, 'action-summaries', 'no-outfile-created.txt.goldfile')); | ||
| expect(displayedLogEvents).toContain(goldfileContents); | ||
| }); | ||
| }) | ||
| // ====== HELPER FUNCTIONS ====== | ||
|
|
||
| async function readGoldFile(goldFilePath: string): Promise<string> { | ||
|
|
@@ -425,7 +503,6 @@ describe('ConfigAction tests', () => { | |
|
|
||
| // ==== OUTPUT PROCESSING ==== | ||
| const displayEvents = spyDisplay.getDisplayEvents(); | ||
| expect(displayEvents).toHaveLength(1); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Array length is now variable, so we're not checking for an exact length anymore. |
||
| expect(displayEvents[0].type).toEqual(DisplayEventType.LOG); | ||
| return ansis.strip(displayEvents[0].data); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copied from
run-summary-viewer.md. Namedcommon.blahto allow for porting the existingRunSummaryViewerimplementation to this new style.