timurstrekalov / saga

Better code coverage tool for JavaScript.
http://timurstrekalov.github.com/saga/
Other
87 stars 25 forks source link

Maven plugin: generating relative paths in reports #88

Open mickaeltr opened 11 years ago

mickaeltr commented 11 years ago

AFAIK, Sonar requires relative paths in the report for calculating the coverage (see https://github.com/timurstrekalov/saga/issues/58). So I think it would be nice if the Saga Maven plugin would somehow enable relative paths in the report.

For now, I am using an ANT task in my Maven POM that transforms absolute paths into relative paths. Not very nice but it does the trick with Sonar.

<replaceregexp
    file="target/jstestdriver/jsTestDriver.conf-coverage.dat"
    match="SF:http:\/\/localhost:${jasmine.serverPort}\/src\/(.*)"
    replace="SF:\1"
    byline="true" />
loesak commented 11 years ago

+1 ... I believe this is my problem as well. The paths in the dat file that JSTD generate are the path to the file in the workspace and the paths in the dat file that Saga output is the URL at which it was found. My Sonar is reading the dat file properly but is reporting 0% coverage on all my files. Hopefully I'm not missing something here.

JSTD:

SF:/aim/builds/jenkins/workspace/...redact.../js/app/application.js DA:1,0 DA:8,0 ...clip... DA:35,0 DA:39,0 end_of_record SF:/aim/builds/jenkins/workspace/...redact.../js/app/collections/collection.js DA:1,1 DA:8,1 ...clip...

Saga:

SF:http://localhost:62453/src/js/app/application.js DA:1,0 DA:8,0 ...clip... DA:35,0 DA:39,0 end_of_record SF:http://localhost:62453/src/js/core/utils/notify-util.js DA:1,1 DA:8,1 ...clip...

timurstrekalov commented 11 years ago

You're most welcome to take a stab at it. I'm currently working on #86, but I'm afraid that after that I will stop actively working on tickets since I just can't find the time these days.

timurstrekalov commented 11 years ago

Should now generate paths relative to baseDir in the LCOV reports. Could someone try this out before it is released or should I just cross my fingers and release this? :smile_cat:

loesak commented 11 years ago

I can try and test it tomorrow. Will let you know.

loesak commented 11 years ago

So I completely forgot to try this out. I will do so tomorrow at work. I've put it in my calendar. My apologies for the delay.

loesak commented 11 years ago

So I did a quick test of this and I still don't believe it is quite right. It seems like you're building the path in the LCOV file based on the path relative to the specified baseDir and the URL at which the file is found. This means file located at http://host:port/src/js/some/path/to/js/file.js will come out as src/some/path/to/js/file given the baseDir is specified at http://host:port. This will not resolve as a valid relative file on the file system as Jasmine is adding the src to the path and that path does not exist on the file system.

Given the following project structure:

project
|- js
  |- some
    |- path
      |- to
        |- js
          |- file.js

The URL path to this file through jasmine will be

http://host:port/src/js/some/path/to/js/file.js

However Sonar wants

path/to/project/js/some/path/to/js/file.js

I am unsure if project relative paths are accepted, e.g.

js/some/path/to/js/file.js

So if you could remove the src directory, I can try the relative path option, but I would think it best if you could provide the absolute path of the file as it exists on the file system if at all possible.

timurstrekalov commented 11 years ago

Thanks for testing this, and sorry it took me so long to come back to you.

The thing is, it's impossible for me to know the real filesystem path if the URL is not a file URL. I cannot assume that an HTTP URL points to a local server, so I have to either put the full or a relative URL, and if that doesn't resolve on the filesystem based on the CWD (or whatever Sonar is using to resolve it), then there's not much I can do, is there?

Do you have any idea what directory Sonar uses as the base directory when trying to resolve those paths?

loesak commented 11 years ago

I'm not sure about the gradle or cli but with maven couldn't you calculate the absolute file path like this?

file.absolutePath =
    maven.project.baseDir + ( 
        file.absoluteUrl - ( 
            jasmine.url + "/src" 
        ) 
    )

for example:

"/path/to/project/js/path/to/file.js" = 
    "/path/to/project" + ( 
        "http://localhost:8234/src/js/path/to/file.js" - ( 
            "http://localhost:8234" + "/src" 
        ) 
    )
dbrin commented 11 years ago

I was experiencing similar symptoms using Maven+Jasmine+Saga and trying to push to Sonar for analysis and display. We are using Sonar v.2.1.2 with Sonar Javascript Plugin 0.4-snapshot.
Here is what I had to do to make Sonar display Coverage and Tests statistics:

  1. POM file
        <!--Javascript testing plugins -->
            <plugin>
                <groupId>com.github.searls</groupId>
                <artifactId>jasmine-maven-plugin</artifactId>
                <version>1.3.1.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <keepServerAlive>true</keepServerAlive>
                        </configuration>
                    </execution>
                </executions>
                <configuration>
                    <keepServerAlive>true</keepServerAlive>
                    <jsSrcDir>${project.basedir}/web-app/js</jsSrcDir>
                    <jsTestSrcDir>${project.basedir}/test/javascript</jsTestSrcDir>
                    <preloadSources>
                        <source>${project.basedir}/web-app/js/lib/backbone.marionette/jquery.js</source>
                        <source>${project.basedir}/web-app/js/lib/backbone.marionette/underscore.js</source>
                        <source>${project.basedir}/web-app/js/lib/backbone.marionette/backbone.js</source>
                        <source>${project.basedir}/web-app/js/lib/backbone.marionette/backbone.marionette.js</source>
                    </preloadSources>
                    <sourceIncludes>
                        <include>application.js</include>
                        <include>models/build.model.js</include>
                        <include>**/*.js</include>
                    </sourceIncludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.github.timurstrekalov</groupId>
                <artifactId>saga-maven-plugin</artifactId>
                <version>1.4.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>coverage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <baseDir>http://localhost:${jasmine.serverPort}</baseDir>
                    <outputDir>${project.build.directory}/coverage</outputDir>
                    <noInstrumentPatterns>
                        <pattern>.*/spec/.*</pattern>
                        <!-- Don't instrument specs -->
                        <pattern>.+/web-app\/js\/lib/.*</pattern>
                        <!-- Don't instrument libs -->
                    </noInstrumentPatterns>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.github.goldin</groupId>
                <artifactId>copy-maven-plugin</artifactId>
                <version>0.2.5</version>
                <configuration>      <!-- use copy:copy to run-->
                    <failIfNotFound>false</failIfNotFound>
                    <resource>
                        <targetPath>${project.build.directory}/jasmine</targetPath>
                        <file>${project.build.directory}/coverage/total-coverage.dat</file>
                        <destFileName>jsTestDriver.conf-coverage.dat</destFileName>
                        <replaces>
                            <replace>
                                <from>http.*src/</from>
                                <!-- Regex to replace localhost:port -->
                                <to>${project.basedir}/web-app/js/</to>
                                <!-- Replacement String to my JS src files -->
                            </replace>
                        </replaces>
                    </resource>
                </configuration>
            </plugin>
            <!--End of Javascript testing plugins -->

....

       <profile>
            <id>sonar-js</id>
            <properties>
                <sonar.language>js</sonar.language>
                <sonar.branch>javascript</sonar.branch>
                <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
                <sonar.javascript.jstestdriver.reportsfolder>target/jasmine</sonar.javascript.jstestdriver.reportsfolder>
                <sonar.javascript.lslint.predef>Backbone,console,JQuery</sonar.javascript.lslint.predef>
            </properties>
        </profile>
  1. Execution on Bamboo (or any other) CI server:
    • Task 1: checkout source from repo.
    • Task 2: mvn clean jasmine:test saga:coverage copy:copy (that copy task is to manipulate coverage.dat file to fit JSTestDriver format and naming convention)
    • Task 3: sonar:sonar -Psonar-js

Done.

Postmortem: There were several issues I had to overcome.

  1. Sonar plugin for JS was really built for JSTestDriver in mind and assumes test reports are in /jstestdriver and the file name for the coverage data (jsTestDriver.conf-coverage.dat) is hardcoded in the plugin. (at least in my version)
    • To solve this issue I set "sonar.javascript.jstestdriver.reportsfolder" property to point to jasmine test reports folder. And had to use copy-maven-plugin to create jsTestDriver.conf-coverage.dat with the content from the Saga total-coverage.dat file.
  2. The other tricky issue was that the same Sonar plugin parses the coverage file matching up filenames with the filesystem. Since Saga is using a URL for baseDir property I had to replace localhost token with a real file path that was obtained from mavens ${project.basedir} token. The replace operation was conveniently handled by the same copy-maven-plugin .

Hope this helps someone. Dmitry.