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

Add an XSLT pre-analyse step #1096

Merged
merged 1 commit into from
Apr 29, 2017
Merged

Conversation

stefanweiser
Copy link

@stefanweiser stefanweiser commented Mar 21, 2017

Hi folks,

I implemented an XSLT translation. I currently does not support wildcards (don't know how to get the concrete file list out of a wildcard pattern in Java), but multiple input and output files seperated by comma. The translation of files is done before using the report file of the output sensor, so:

`sonar.cxx.xslt.1.stylesheet=MyStylesheets1.xslt
sonar.cxx.xslt.1.source=tool1/reports/xxx-1.xml
sonar.cxx.xslt.1.output=reports/other-tool1-1.xml

sonar.cxx.xslt.2.stylesheet=MyStylesheets2.xslt
sonar.cxx.xslt.2.source=reports/other-tool1-1.xml
sonar.cxx.xslt.2.output=reports/other-tool2-2.xml

sonar.cxx.other.reportPath=reports/other-tool2-2.xml`

will report "reports/other-tool2-2.xml" after translation from tool1/reports/xxx-1.xml to reports/other-tool1-1.xml to reports/other-tool2-2.xml.

I tested it on our own server, but was not able to provide a test case. I think I'm not able to understand the unit test infrastructure...

close #1080


This change is Reviewable

@guwirth guwirth changed the title Implementation for #1080 Add an XSLT pre-analyse step Mar 22, 2017
@guwirth guwirth added this to the 0.9.8 milestone Mar 22, 2017
Copy link
Collaborator

@guwirth guwirth left a comment

Choose a reason for hiding this comment

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

  • unit test is missing
  • UI integration is missing
    • think we need then hard coded properties?
  • if we add UI: would start with 5 only (instead 10)

*/
public class CxxExternalRulesSensor extends CxxReportSensor {
public static final Logger LOG = Loggers.get(CxxExternalRulesSensor.class);
public static final String REPORT_PATH_KEY = "sonar.cxx.other.reportPath";
public static final String SONAR_CXX_XSLT_KEY = "sonar.cxx.xslt.";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure, but I think should be in an extra sensor and not within CxxReportSensor?

Copy link
Collaborator

Choose a reason for hiding this comment

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

If yes: must be clarified how to define order of sensor execution

Copy link
Author

Choose a reason for hiding this comment

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

I was uncertain, too. I guess, it's a question of: Which other sensor could benefit? I don't see any use in transforming a report, that already fits to the sensor (which is the case elsewhere).

Copy link
Member

Choose a reason for hiding this comment

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

I do agree with Stefan, this kind of transformation seems applicable only to external sensor since it's the only one that forces users to provide a specific format, @guwirth which other sensors do you think would benefit from this?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

in this case, i think so. the XunitSensor is feeding test metrics, this is to feed issues so they have different purposes. what we can do is to use the same transformation code, @stefanweiser you could take a look into the xunit sensor how its done move the logic to own class and then reuse in both external sensor and xunit sensor?

Copy link
Author

Choose a reason for hiding this comment

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

To answer the question of being an extra sensor. This affects sensor execution order: I don't think, that we could enforce a specific order. The documentation do not say something about it. Somebody asked this already, but got not very much information: http://stackoverflow.com/q/42571579/3781684

Copy link
Collaborator

Choose a reason for hiding this comment

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

In case we keep it for 'other' name must be sonar.cxx.other.xslt.xxx.

Think it's not hard to change later one. Let's start as part of 'other'. There is also no problem with the sequence then.

Copy link
Member

Choose a reason for hiding this comment

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

String outputKey = SONAR_CXX_XSLT_KEY + i + OUTPUT_KEY;

String stylesheet = FilenameUtils.normalize(settings.getString(SONAR_CXX_XSLT_KEY + i + STYLESHEET_KEY));
String[] sources = settings.getStringArray(SONAR_CXX_XSLT_KEY + i + SOURCE_KEY);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would not support comma separated list. Would use wildcard pattern instead

Copy link
Author

Choose a reason for hiding this comment

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

I thought, that getStringArray would return an array of strings, that are comma-seperated in the settings file and I don't know how to solve wildcard patterns. Is there any reference implementation for this in sonar-cxx?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We are doing this in CxxReportSensor.getReports. This is a static function, maybe we can move it https://github.com/SonarOpenCommunity/sonar-cxx/tree/master/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/utils to make it more general?

public static List<File> getReports(Settings settings, final File moduleBaseDir,

} else if ((stylesheet != null) ||
((sources != null) && (sources.length > 0)) ||
((outputs != null) && (outputs.length > 0))) {
if (stylesheet == null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Think we need always all three. So one message would be sufficient?

Copy link
Author

Choose a reason for hiding this comment

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

We do need always all three, but I appreciate a tool, that reports to me exactly what's wrong. Otherwise you have to do some research first to find the bug.

public void execute(SensorContext context) {
try {
transformFiles();
} catch (Exception e) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Think try/catch is at the wrong place. If one transformation is failing no other is executed?
Would prefer: if one transformation is failing, should try the next one

Copy link
Author

Choose a reason for hiding this comment

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

Doing so would then result in a lot of errors if one transformation fails, because the source of the next transformation step would be missing. I know, that this would be more tolerant.

Its a design decision, which I would leave up to you. So if you want to go on transforming files, even there are errors, then I would implement it that way.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Up to now we have two modes: strict and tolerant

  • strict: break whole analysis after an error
  • tolerant: ignore and continue

This is hidden behind CxxUtils.validateRecovery.

In tolerant mode:

  • should continue if one of the XSLT transformation fails and there are more source files in the comma separated list
  • should continue with next XSLT transformation if one before was failing

Copy link
Author

Choose a reason for hiding this comment

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

So you suggest different behavior for both modes? ;-)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Reasons to catch not only on highest level:

  • Could be tool A needs transforming A and tool B needs transformation B. If A is failing B should nevertheless work (tolerant mode)
  • Same if more then one file has to be transformed. If transformation A handles more then one file it should continue if one transformation is failing.

So you suggest different behavior for both modes? ;-)

Yes behavior of all sensors is different depending on setting of 'sonar.cxx.errorRecoveryEnabled'. But all what you have to do is to call:
https://github.com/SonarOpenCommunity/sonar-cxx/blob/master/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/utils/CxxUtils.java#L88

@guwirth
Copy link
Collaborator

guwirth commented Mar 22, 2017

@stefanweiser thanks a lot for providing this solution. I started a review with some general questions.

@stefanweiser
Copy link
Author

I want to write a unit test for this, but I was not able get it to work. Seems, that I have to put more effort in this.

What do you mean with UI-integration? How do I get that?

@guwirth
Copy link
Collaborator

guwirth commented Mar 23, 2017

@guwirth
Copy link
Collaborator

guwirth commented Mar 23, 2017

What do you mean with UI-integration? How do I get that?

@stefanweiser on server side you can set the properties normally also in the UI <Administration/C++ (Community)>. These properties are defined here: https://github.com/SonarOpenCommunity/sonar-cxx/blob/master/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxPlugin.java#L79

Question is if XSLT would be a new tab: (6) XSLT Transformation?

@stefanweiser
Copy link
Author

OK, whether it is an own tab or not is a question of "Would it be an own sensor or is it part of a sensor", because in the first case the information is associated to the plugin and is of common nature. In the second case it belongs to the sensor and would be different for every sensor.

Currently I believe, that it should belong as a utility class to each sensor.

@guwirth
Copy link
Collaborator

guwirth commented Mar 26, 2017

@stefanweiser point should be changed before we merge it:

  • we keep it as part of other => change keys accordingly
  • support 'tolerant' mode in the right way
  • support wildcards
  • add an unit test

@jmecosta
Copy link
Member

@stefanweiser i would also recommend that the xslt in https://github.com/SonarOpenCommunity/sonar-cxx/blob/master/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/tests/xunit/CxxXunitSensor.java to be moved to a utility library. and be reused in both xunit and external sensor.

Copy link
Member

@jmecosta jmecosta left a comment

Choose a reason for hiding this comment

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

still in early stages to be merged, tests are missing and we have duplicated functionality in 2 places. so can be made a utility class.

*/
public class CxxExternalRulesSensor extends CxxReportSensor {
public static final Logger LOG = Loggers.get(CxxExternalRulesSensor.class);
public static final String REPORT_PATH_KEY = "sonar.cxx.other.reportPath";
public static final String SONAR_CXX_XSLT_KEY = "sonar.cxx.xslt.";
Copy link
Member

Choose a reason for hiding this comment

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

}
}

private void transformFile(File stylesheetFile, String source, String output) throws TransformerException {
Copy link
Member

Choose a reason for hiding this comment

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

transformation can be done in memory, as the xunit sensor. it should speed up the analysis

@stefanweiser
Copy link
Author

stefanweiser commented Apr 13, 2017

Sorry, for being quiet for a long time. I was a bit busy. I integrated most of the change requests and got stuck with testing now. How can I debug these tests (propably just with printf). I added some test files, but it seems that my test will not generate any output files in the test scenario.

@jmecosta
Copy link
Member

@stefanweiser try intarget\surefire-reports usually all test data ouput is found under those files

@stefanweiser
Copy link
Author

Thanks @jmecosta. This worked pretty well.

I've pushed all changes and I hope, that I forgot nothing.

  • The keys start now with: sonar.cxx.other.xslt.*
  • Added two unit tests (one for invalid files and one for successful transformation)
  • I use getReports now, so wildcards are supported on the inputs (on the outputs, there is no way, because it would not be possible to guess the output names)
  • Support for the tolerant and strict way

I hope, that you won't find some easter eggs in there.

@jmecosta
Copy link
Member

jmecosta commented Apr 13, 2017 via email

@stefanweiser
Copy link
Author

stefanweiser commented Apr 24, 2017

But if we would skip the temporaries and output just the last XMLs, you'd have much more to debug if one tranlation script in the midst is buggy. How realistic is the case, where multiple transformation steps are necessary?

@jmecosta
Copy link
Member

ok, but then the default behaviour should be without the outputs. in normal cases a end user would want to set only the xslt?

@stefanweiser
Copy link
Author

I think the usual way is to set the XSLT, provide one or more input XML(s) and go. The configuration scheme should also change into something like this, if we don't want the intermediate output:

sonar.cxx.xslt.stylesheets=MyStylesheet1.xslt,MyStylesheet2.xslt,MyStylesheet3.xslt sonar.cxx.xslt.source=tool1/reports/xxx-1.xml,tool1/reports/xxx-2.xml sonar.cxx.xslt.output=reports/other-tool1-1.xml,reports/other-tool1-2.xml

Then there is no need for the different blocks sonar.cxx.xslt.1, 2, 3...

The way it is at the moment, we will have to configure more and get more build artifacts but IMHO it is better for debugging and more straight forward.

@jmecosta
Copy link
Member

jmecosta commented Apr 24, 2017 via email

@stefanweiser
Copy link
Author

Now all checks are green.

@stefanweiser
Copy link
Author

I fixed an issue on key naming (sonar.cxx is getting now prefixed by CxxLanguage), that exists since I merged the upstream branch into my fork.

@guwirth
Copy link
Collaborator

guwirth commented Apr 25, 2017

@stefanweiser thanks for providing this. It's also ok from my side besides minor issues:

  • because source and output are lists now should be sources and outputs (with s)
sonar.cxx.xslt.1.sources=tool1/reports/xxx-1.xml
sonar.cxx.xslt.1.outputs=reports/other-tool1-1.xml
  • after seeing the solution wondering if we should not better rename sources to inputs? Think the pairs are source/destination and input/output?

@stefanweiser
Copy link
Author

ACK, renamed it in inputs and outputs.

Copy link
Collaborator

@guwirth guwirth left a comment

Choose a reason for hiding this comment

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

@stefanweiser Sorry, call me pedantic. But please add also variable and parameter names from <source(s)> to <input(s)>

public static final String KEY = "other";
public static final String OTHER_XSLT_KEY = KEY + ".xslt.";
public static final String STYLESHEET_KEY = ".stylesheet";
public static final String SOURCE_KEY = ".inputs";
Copy link
Collaborator

Choose a reason for hiding this comment

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

name should be INPUT_KEY

Boolean goOn = true;
for (int i = 1; (i < 10) && goOn; i++) {
String stylesheetKey = OTHER_XSLT_KEY + i + STYLESHEET_KEY;
String sourceKey = OTHER_XSLT_KEY + i + SOURCE_KEY;
Copy link
Collaborator

Choose a reason for hiding this comment

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

name should be inputKey

String outputKey = OTHER_XSLT_KEY + i + OUTPUT_KEY;

String stylesheet = resolveFilename(baseDir.getAbsolutePath(), cxxLanguage.getStringOption(stylesheetKey));
List<File> sources = getReports(cxxLanguage, baseDir, sourceKey);
Copy link
Collaborator

Choose a reason for hiding this comment

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

name should be inputs

}
}

private void transformFileList(final String baseDir, File stylesheetFile, List<File> sources, List<String> outputs) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

sources => inputs




public static void transformFile(Source stylesheetFile, File source, File output) throws TransformerException {
Copy link
Collaborator

Choose a reason for hiding this comment

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

source => input

@stefanweiser
Copy link
Author

Shame on me. I've just fixed that.

@guwirth
Copy link
Collaborator

guwirth commented Apr 27, 2017

Hi @stefanweiser thanks a lot. Maybe you can do a final rebase & squash before merge. AppVeyor problem seems to be a tool problem.

@stefanweiser
Copy link
Author

stefanweiser commented Apr 27, 2017

@guwirth: The branch is already rebased. Do you want me to squash all my commits into one?

@guwirth
Copy link
Collaborator

guwirth commented Apr 27, 2017

@stefanweiser yes if possible. This will trigger a new build.

@guwirth
Copy link
Collaborator

guwirth commented Apr 29, 2017

@jmecosta can you restart AppVeyor to see if everything is green please.

@jmecosta
Copy link
Member

jmecosta commented Apr 29, 2017 via email

@stefanweiser
Copy link
Author

Sorry for letting you wait. Squashed the feature into one commit.

@guwirth
Copy link
Collaborator

guwirth commented Apr 29, 2017

@stefanweiser thanks a lot for your contribution and the patience with us 😄.

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

Successfully merging this pull request may close these issues.

Add an XSLT pre-analyse step
3 participants