]> source.dussan.org Git - sonarqube.git/commitdiff
Component Viewer: source code, coverage
authorStas Vilchik <vilchiks@gmail.com>
Wed, 16 Apr 2014 09:42:16 +0000 (15:42 +0600)
committerStas Vilchik <vilchiks@gmail.com>
Wed, 16 Apr 2014 09:42:16 +0000 (15:42 +0600)
12 files changed:
sonar-server/Gruntfile.coffee
sonar-server/src/main/coffee/component-viewer/app.coffee [new file with mode: 0644]
sonar-server/src/main/coffee/component-viewer/main.coffee [new file with mode: 0644]
sonar-server/src/main/coffee/component-viewer/source.coffee [new file with mode: 0644]
sonar-server/src/main/hbs/component-viewer/layout.hbs [new file with mode: 0644]
sonar-server/src/main/hbs/component-viewer/source.hbs [new file with mode: 0644]
sonar-server/src/main/js/common/handlebars-extensions.js
sonar-server/src/main/less/component-viewer.less [new file with mode: 0644]
sonar-server/src/main/less/navigator/config.less
sonar-server/src/main/less/variables.less
sonar-server/src/main/webapp/WEB-INF/app/controllers/component_viewer_controller.rb [new file with mode: 0644]
sonar-server/src/main/webapp/WEB-INF/app/views/component_viewer/index.html.erb [new file with mode: 0644]

index 88c18c563699d80c566da2d6fb1b1de397f4cdff..5a5d14c69b5a428e923821db0b30ddeb48ad6909 100644 (file)
@@ -161,6 +161,10 @@ module.exports = (grunt) ->
         name: 'common/select-list'
         out: '<%= pkg.assets %>build/js/common/select-list.js'
 
+      componentViewer: options:
+        name: 'component-viewer/app'
+        out: '<%= pkg.assets %>build/js/component-viewer/app.js'
+
 
     handlebars:
       options:
@@ -184,6 +188,9 @@ module.exports = (grunt) ->
           '<%= pkg.assets %>js/templates/quality-gates.js': [
             '<%= pkg.sources %>hbs/quality-gates/**/*.hbs'
           ]
+          '<%= pkg.assets %>js/templates/component-viewer.js': [
+            '<%= pkg.sources %>hbs/component-viewer/**/*.hbs'
+          ]
 
 
     clean:
diff --git a/sonar-server/src/main/coffee/component-viewer/app.coffee b/sonar-server/src/main/coffee/component-viewer/app.coffee
new file mode 100644 (file)
index 0000000..85ec0f9
--- /dev/null
@@ -0,0 +1,32 @@
+requirejs.config
+  baseUrl: "#{baseUrl}/js"
+
+  paths:
+    'backbone': 'third-party/backbone'
+    'backbone.marionette': 'third-party/backbone.marionette'
+    'handlebars': 'third-party/handlebars'
+    'jquery.mockjax': 'third-party/jquery.mockjax'
+
+  shim:
+    'backbone.marionette':
+      deps: ['backbone']
+      exports: 'Marionette'
+    'backbone':
+      exports: 'Backbone'
+    'handlebars':
+      exports: 'Handlebars'
+
+
+requirejs [
+  'component-viewer/main',
+], (
+  ComponentViewer
+) ->
+
+  TEST_RESOURCE_KEY = 'org.codehaus.sonar:sonar-plugin-api:src/main/java/org/sonar/api/resources/ResourceTypeTree.java'
+
+
+  @componentViewer = new ComponentViewer()
+  @componentViewer.render().$el.appendTo '#body'
+
+  @componentViewer.open TEST_RESOURCE_KEY
\ No newline at end of file
diff --git a/sonar-server/src/main/coffee/component-viewer/main.coffee b/sonar-server/src/main/coffee/component-viewer/main.coffee
new file mode 100644 (file)
index 0000000..e89ff2a
--- /dev/null
@@ -0,0 +1,67 @@
+define [
+  'backbone'
+  'backbone.marionette'
+  'templates/component-viewer'
+  'component-viewer/source'
+], (
+  Backbone
+  Marionette
+  Templates
+  SourceView
+) ->
+
+  $ = jQuery
+  API_SOURCES = "#{baseUrl}/api/sources"
+  API_RESOURCES = "#{baseUrl}/api/resources"
+
+
+
+  class ComponentViewer extends Marionette.Layout
+    className: 'component-viewer'
+    template: Templates['layout']
+
+
+    regions:
+      sourceRegion: '.component-viewer-source'
+
+
+    initialize: ->
+      @source = new Backbone.Model()
+      @sourceView = new SourceView model: @source
+
+
+    onRender: ->
+      @sourceRegion.show @sourceView
+
+
+    requestSource: (key) ->
+      $.get API_SOURCES, resource: key, (data) =>
+        @source.set { source:  data[0] }, { silent: true }
+
+
+    requestCoverage: (key) ->
+      metrics = 'coverage_line_hits_data,covered_conditions_by_line,conditions_by_line'
+
+      toObj = (data) ->
+        q = {}
+        data.split(';').forEach (item) ->
+          tokens = item.split '='
+          q[tokens[0]] = tokens[1]
+        q
+
+
+      $.get API_RESOURCES, resource: key, metrics: metrics, (data) =>
+        msr = data[0].msr
+        coverage = toObj _.findWhere(msr, key: 'coverage_line_hits_data').data
+        coverageConditions = toObj _.findWhere(msr, key: 'covered_conditions_by_line').data
+        conditions = toObj _.findWhere(msr, key: 'conditions_by_line').data
+        @source.set {
+          coverage: coverage,
+          coverageConditions: coverageConditions
+          conditions: conditions
+        }, { silent: true }
+
+
+    open: (key) ->
+      $.when(@requestSource(key), @requestCoverage(key)).done =>
+        @sourceView.render()
\ No newline at end of file
diff --git a/sonar-server/src/main/coffee/component-viewer/source.coffee b/sonar-server/src/main/coffee/component-viewer/source.coffee
new file mode 100644 (file)
index 0000000..b6c25ba
--- /dev/null
@@ -0,0 +1,42 @@
+define [
+  'backbone.marionette'
+  'templates/component-viewer'
+  'common/handlebars-extensions'
+], (
+  Marionette
+  Templates
+) ->
+
+  class SourceView extends Marionette.ItemView
+    template: Templates['source']
+
+
+    modelEvents:
+      'change': 'render'
+
+
+    serializeData: ->
+      source = @model.get 'source'
+      coverage = @model.get 'coverage'
+      coverageConditions = @model.get 'coverageConditions'
+      conditions = @model.get 'conditions'
+      source = _.map source, (code, line) ->
+        lineCoverage = coverage? && coverage[line]? && coverage[line]
+        lineCoverageConditions = coverageConditions? && coverageConditions[line]? && coverageConditions[line]
+        lineConditions = conditions? && conditions[line]? && conditions[line]
+        lineCoverageStatus = lineCoverage? &&  if lineCoverage > 0 then 'green' else 'red'
+        lineCoverageConditionsStatus = null
+        if lineCoverageConditions? && conditions?
+          lineCoverageConditionsStatus = 'red' if lineCoverageConditions == 0
+          lineCoverageConditionsStatus = 'orange' if lineCoverageConditions > 0 && lineCoverageConditions < lineConditions
+          lineCoverageConditionsStatus = 'green' if lineCoverageConditions == lineConditions
+
+
+        lineNumber: line
+        code: code
+        coverage: lineCoverage
+        coverageStatus: lineCoverageStatus
+        coverageConditions: lineCoverageConditions
+        conditions: lineConditions
+        coverageConditionsStatus: lineCoverageConditionsStatus
+      source: source
\ No newline at end of file
diff --git a/sonar-server/src/main/hbs/component-viewer/layout.hbs b/sonar-server/src/main/hbs/component-viewer/layout.hbs
new file mode 100644 (file)
index 0000000..27a9082
--- /dev/null
@@ -0,0 +1 @@
+<div class="component-viewer-source"></div>
\ No newline at end of file
diff --git a/sonar-server/src/main/hbs/component-viewer/source.hbs b/sonar-server/src/main/hbs/component-viewer/source.hbs
new file mode 100644 (file)
index 0000000..c473d5a
--- /dev/null
@@ -0,0 +1,20 @@
+<table class="sources2 code" cellpadding="0" cellspacing="0">
+  {{#each source}}
+    <tr class="row">
+      <td class="coverage {{#if coverage}}coverage-{{coverageStatus}}{{/if}}">
+        {{#if coverage}}<span title="Line is covered by {{coverage}} tests">{{coverage}}</span>{{/if}}
+      </td>
+      <td class="coverage {{#if coverageConditions}}coverage-{{coverageConditionsStatus}}{{/if}}">
+          {{#if coverageConditions}}
+            {{#if conditions}}
+              <span title="{{coverageConditions}} branches are covered by tests">
+                {{coverageConditions}}/{{conditions}}
+              </span>
+            {{/if}}
+          {{/if}}
+      </td>
+      <td class="lid">{{lineNumber}}</td>
+      <td class="line"><pre>{{{code}}}</pre></td>
+    </tr>
+  {{/each}}
+</table>
\ No newline at end of file
index 47ff219f704463d01ea66568fb784f3ad7a5dd41..2a8f5747b5060308a17c779f9eaf22747868147f 100644 (file)
@@ -144,6 +144,11 @@ define(['handlebars'], function (Handlebars) {
   });
 
   Handlebars.registerHelper('sources', function(source, scm, options) {
+    if (options == null) {
+      options = scm;
+      scm = null;
+    }
+
     var sources = _.map(source, function(code, line) {
       return {
         lineNumber: line,
diff --git a/sonar-server/src/main/less/component-viewer.less b/sonar-server/src/main/less/component-viewer.less
new file mode 100644 (file)
index 0000000..7bfd425
--- /dev/null
@@ -0,0 +1,72 @@
+@import "variables";
+@import "mixins";
+
+
+.component-viewer {
+  width: 100%;
+  min-width: 600px;
+}
+
+
+.component-viewer-source {
+
+  .sources2 td.line {
+    padding: 1px 5px;
+
+    pre {
+      padding: 0;
+      font-family: 'inconsolata', monospace;
+      font-size: 13px;
+    }
+  }
+
+  .sources2 td.lid {
+    padding: 1px 5px;
+    border-color: @barBorderColor;
+    background-color: @barBackgroundColor;
+    color: #888;
+    font-size: 11px;
+  }
+
+  .sources2 td.coverage {
+    padding: 1px 5px;
+    background-color: @barBackgroundColor;
+    color: #fff;
+
+    &.coverage-green { background-color: @green;}
+    &.coverage-red { background-color: @red; }
+    &.coverage-orange { background-color: @orange; }
+  }
+
+  .sources2 .row:hover {
+    td.lid { background-color: darken(@barBackgroundColor, 5%); }
+    td.line { background-color: @barBackgroundColor; }
+    td.coverage { background-color: darken(@barBackgroundColor, 5%); }
+    td.coverage.coverage-green { background-color: darken(@green, 5%); }
+    td.coverage.coverage-red { background-color: darken(@red, 5%); }
+    td.coverage.coverage-orange { background-color: darken(@orange, 5%); }
+  }
+
+}
+
+
+@font-face {
+  font-family: 'inconsolata-bold';
+  src: url('../fonts/inconsolata-bold-webfont.woff') format('woff'),
+       url('../fonts/inconsolata-bold-webfont.svg#inconsolatabold') format('svg');
+  font-weight: normal;
+  font-style: normal;
+
+}
+
+
+
+
+@font-face {
+  font-family: 'inconsolata';
+  src: url('../fonts/inconsolata-regular-webfont.woff') format('woff'),
+       url('../fonts/inconsolata-regular-webfont.svg#inconsolataregular') format('svg');
+  font-weight: normal;
+  font-style: normal;
+
+}
\ No newline at end of file
index 4ad5424b817314f7ef5c9f22b2154127d0dcc69c..805359a554dc1e0e53eb923a667bcc1e974ff889 100644 (file)
@@ -18,9 +18,9 @@
 
 
 // Colors
-@navigatorBarBackground: #f3f3f3;
-@navigatorBorderColor: darken(@navigatorBarBackground, 5%);
-@navigatorBorderLightColor: @navigatorBorderColor;
+@navigatorBarBackground: @barBackgroundColor;
+@navigatorBorderColor: @barBorderColor;
+@navigatorBorderLightColor: @barBorderColor;
 
 @navigatorHeaderColor: darken(@blue, 10%);
 
index b1effcb941552e30e67d295856f0931fb387b9d1..659091e4ba45bee3d120bad9c42ed28a79f50b35 100644 (file)
 @contextBorder: lighten(@purple, 30%);
 
 
+@barBackgroundColor: #f3f3f3;
+@barBorderColor: darken(@barBackgroundColor, 5%);
+
+
 /*
  * Icons
  */
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/component_viewer_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/component_viewer_controller.rb
new file mode 100644 (file)
index 0000000..fdff4bf
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+class ComponentViewerController < ApplicationController
+
+  def index
+
+  end
+
+end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/component_viewer/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/component_viewer/index.html.erb
new file mode 100644 (file)
index 0000000..f5f2f09
--- /dev/null
@@ -0,0 +1,3 @@
+<% content_for :script do %>
+  <script data-main="<%= ApplicationController.root_context -%>/js/component-viewer/app" src="<%= ApplicationController.root_context -%>/js/require.js"></script>
+<% end %>
\ No newline at end of file