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

JUnit #103

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open

JUnit #103

wants to merge 8 commits into from

Conversation

FISHMANPET
Copy link

Fixes #58
As requested, a PR for my changes. I added a little bit since I wrote the comment last night, in
95cb1ff.

I added some time and timestamps because Azure Devops was complaining about not having them, and while Azure Devops could handle it I suspect other CIs might not. Since there are no time or duration values in the lintResult object that was already being constructed (and it doesn't look like the base markdownlint library produces any either) I just put in some simple defaults: The timestamp for the test suite will be the time the report is generated, the time for each testcase will just be 1 millisecond (spec is for time in seconds so 0.001 seconds), and the total time for the testcase will be the elapsed time between when the report generation started and when it finishes (which will only be a couple of milliseconds most likely).

I looked a bit at the junit-report-builder code to see what all options that could be used, and discovered failures could have a "type" in addition to a "message" so I added the name as the type for each failure.

I don't know that there's an official formal JUnit schema, but Azure Devops links to this one I'm not very good at reading xml schema documents but it looks like there's some fields that are required according to the schema but that this module doesn't support. I believe I've used every test suite and test case attribute that exists in the module, and based on its popularity I'm guessing what it produces is acceptable to most if not all CI tools, but if someone would ever report an issue about this generating something that their CI tool can't read, it would probably be an upstream issue for that module to support it before this project can support it.

I appreciated the pre-commit linter (once I realized it was linter errors that were preventing me from committing). I split up the test suite and test case across multiple lines since they were pretty long, I'm pretty sure there will be other style changes you'd like to see made.

And testing, if you point me in a direction I can try to implement some kind of testing.

@DavidAnson
Copy link
Collaborator

Great, thanks, I’ll try to review this tonight! One thing you might do if bored is look at how other projects, especially ESLint, handle some of these things (like time stamp) in their jUnit output. Probably can’t go wrong being consistent. :)

@FISHMANPET
Copy link
Author

Also it turns out this will still throw an exit code of 1 when there are test failures because of

process.exitCode = 1;

I thought about wrapping that in something like if (!program.junit) or adding a new parameter like --no-non-zero-exit-code-on-linting-errors but you said you wanted to consider that separately. I could open a new issue if you'd like to discuss that part.

@FISHMANPET
Copy link
Author

Good idea to look at what eslint does. I'll need to grok what they're doing a little bit, but at the very least it makes me realize that I'm not sure what will happen if there are no markdown errors, I think I need to add an explicit case like eslint to report a single successful test case if there are no issues.

Based on how eslint generates these reports, just setting all times to 0
Add single passed test case if now lint errors found
@DavidAnson
Copy link
Collaborator

Sorry, didn’t get to this again. Fully expect to tomorrow, thanks for your patience!

Copy link
Collaborator

@DavidAnson DavidAnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for doing this! I’ve left a lot of comments, but many of them are pretty trivial. The one thing that’s missing before I’d consider this done is test cases. But if you don’t feel like adding that, just let me know. I am happy to accept these changes and add the tests myself. Please let me know if any of my feedback is unclear.

markdownlint.js Outdated Show resolved Hide resolved
markdownlint.js Outdated Show resolved Hide resolved
markdownlint.js Outdated Show resolved Hide resolved
markdownlint.js Outdated Show resolved Hide resolved
markdownlint.js Outdated Show resolved Hide resolved
markdownlint.js Show resolved Hide resolved
markdownlint.js Outdated
.option('-f, --fix', 'fix basic errors (does not work with STDIN)')
.option('-s, --stdin', 'read from STDIN (does not work with files)')
.option('-o, --output [outputFile]', 'write issues to file (no console)')
.option('-o, --output <outputFile>', 'write issues to file (no console)')
.option('-j, --junit [junitFile]', 'write issues to file in junit format as well as to the console')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is “junit” the preferred capitalization?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like JUnit is the correct name, but I'm thinking it makes sense to leave the option name and file name in the current case, and just change the descriptive text?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed!

markdownlint.js Outdated Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
markdownlint.js Show resolved Hide resolved
Implementing changes requested in PR review
@FISHMANPET
Copy link
Author

I pushed changes for all the comments I resolved in c4e3f57. Looking at how tests are currently being done it shouldn't be too difficult to put some tests in.

Case/Situations I think should be tested:
JUnit report when there are issues (will pick one of your "incorrect" md test documents)
JUnit report when there aren't issues (will pick one of your "correct" md test documents)
When both -o and -j are specified, ensure that the -o section is what's run and the JUnit stuff will be skipped.

Anything else you'd like to see tested with these changes?

@FISHMANPET FISHMANPET changed the title Junit JUnit Jun 29, 2020
@FISHMANPET
Copy link
Author

OK, played around with this. Decided to replicate the four --output tests with --junit and started with the first one, which was nothing in via stdin. I settled on using an XML parser to parse the output XML, settling with xml-js (added as a dev dependency to package.json). I figured I'd push the first test to see if you agree with the methodology before I did more. I'm not sure if subsequent tests would be quite so rigorous, as it is that test checked everything that the builder writes, but subsequent tests should only need to test the things that are different from the first test.

Also writing the tests pointed out a few flaws (I love when that happens!) that I corrected in markdownlint.js. Now if the input is stdin then the classname will be stdin instead of program.args. And writing an empty string to console.error is different from not writing to console.error, so I set it to only write to the console if there are actual results.

@DavidAnson
Copy link
Collaborator

I haven’t had a chance to look at any of this yet, but saw this latest message fly by and wanted to chime in in case it could save you some time. What do you think about just doing a plain text comparison of the output instead of trying to re-parse it as XML? I don’t imagine the layout or format will change unexpectedly, so does this give us enough confidence (assuming that we make sure the text output is correct)? Or, if you’ve already done this, maybe it’s best to be general and I do like that there will be guaranteed validation of the XML structure with a parser.

Copy link
Collaborator

@DavidAnson DavidAnson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m loving it! Thanks very much for following up on the feedback. We’re getting very close now, just a need to round out the test story.

@@ -63,6 +64,13 @@ Because this option makes changes to the input files, it is good to make a backu

> Because not all rules include fix information when reporting errors, fixes may overlap, and not all errors are fixable, `--fix` will not usually address all errors.

### JUnit report

If the `-j`/`--junit` option is specified, `markdownlint-cli` will output an XML report in JUnit format.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add link to some info about “JUnit format”, maybe?

If the `-j`/`--junit` option is specified, `markdownlint-cli` will output an XML report in JUnit format.
This report can be used in CI/CD environments to make the `markdownlint-cli` results available to your CI/CD tool.
If both `-j`/`--junit` and `-o`/`--output` are specified, `-o`/`--output` will take precedence.
Only one of these options should be specified.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe remove this, I think your previous line is clear.

@@ -67,7 +67,7 @@ function readConfiguration(args) {
markdownlint.readConfigSync(userConfigFile, configFileParsers);
config = require('deep-extend')(config, userConfig);
} catch (error) {
console.warn('Cannot read or parse config file ' + userConfigFile + ': ' + error.message);
console.warn(`Cannot read or parse config file ${userConfigFile}: ${error.message}`);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing the others!

});
} else {
const className = program.stdin ? 'stdin' : program.args;
testSuite.testCase().className(className).name('markdownlint').time(0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make this multi-line for consistency with above?

.option('-c, --config <configFile>', 'configuration file (JSON, JSONC, JS, or YAML)')
.option('-i, --ignore <file|directory|glob>', 'file(s) to ignore/exclude', concatArray, [])
.option('-p, --ignore-path <file>', 'path to file with ignore pattern(s)')
.option('-r, --rules <file|directory|glob|package>', 'custom rule files', concatArray, []);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed the extra space here, mind removing it?

const parsedXml = xmlParser.xml2js(xml, {compact: true});
t.is(result.stdout, '');
t.is(result.stderr, '');
t.is(Object.keys(parsedXml.testsuites).length, 1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my separate comment about maybe just comparing the output text directly. What you have here is more correct and thorough, but it’s a lot more typing and harder to follow. I’m fine with either choice - up to you if you want to type more. :)

fs.unlinkSync(junit);
});

// WIP
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your test cases make sense to me!

@FISHMANPET
Copy link
Author

FISHMANPET commented Jun 30, 2021

As is the case with open source, I got distracted from this for a while and now (exactly a year later!) I'm looking at it again.

I believe at the time I got caught up on tests, and decided to implement an overly rigorous test regime (using the XML parser). You recommended just comparing to a known file and... I'm not sure why I ignored that at the time.

I also see you've adapted much of this into markdownlint-cli2 so I'm not sure there's any benefit to "finishing" this. If you'd like I could redo the tests to just match against a known file, and align the output with what you've done with the junit formatter in cli2. But I read your post about why you wrote cli2, and my guess is you'd be fine just closing this without merging, since the bulk of the work has been implemented there.

@DavidAnson
Copy link
Collaborator

Glad to have you back! What do you do here is kind of up to you! I wrote CLI2 for the reasons you read about, but I don't expect everybody to migrate over immediately - or even ever. Having a compatible implementation for this project would be nice and probably benefit some people. On the other hand, not having it represents a small carrot for people to migrate. I'm happy to support whatever approach you choose. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[feature request] junit test reporter
2 participants