]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2382 Complete review web service
authorsimonbrandhof <simon.brandhof@gmail.com>
Tue, 26 Apr 2011 13:24:57 +0000 (15:24 +0200)
committersimonbrandhof <simon.brandhof@gmail.com>
Tue, 26 Apr 2011 13:25:08 +0000 (15:25 +0200)
12 files changed:
sonar-server/src/main/webapp/WEB-INF/app/controllers/api/reviews_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/controllers/api/violations_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/helpers/markdown_helper.rb
sonar-server/src/main/webapp/WEB-INF/app/models/review.rb
sonar-server/src/main/webapp/WEB-INF/app/models/rule_failure.rb
sonar-server/src/main/webapp/WEB-INF/app/models/user.rb
sonar-ws-client/src/main/java/org/sonar/wsclient/services/Violation.java
sonar-ws-client/src/main/java/org/sonar/wsclient/unmarshallers/ViolationUnmarshaller.java
sonar-ws-client/src/test/java/org/sonar/wsclient/unmarshallers/ViolationUnmarshallerTest.java
sonar-ws-client/src/test/resources/violations/false-positive.json [new file with mode: 0644]
sonar-ws-client/src/test/resources/violations/violation-without-optional-fields.json
sonar-ws-client/src/test/resources/violations/violations.json

index d3d329a8afb8f56e13c867c0ebe72bad9756f022..a8f050e6dfa997371d248af0f00db3342a9f3501 100644 (file)
@@ -22,42 +22,72 @@ require "json"
 
 class Api::ReviewsController < Api::ApiController
 
+  include MarkdownHelper
+
   def index
-    @reviews = []
-    @reviews << Review.find ( params[:id] )
+    convert_markdown=(params[:html]=='true')
+    reviews=Review.search(params)
     
     respond_to do |format|
-      format.json { render :json => jsonp(to_json) }
-      format.xml {render :xml => to_xml}
+      format.json { render :json => jsonp(to_json(reviews, convert_markdown)) }
+      format.xml {render :xml => to_xml(reviews, convert_markdown)}
       format.text { render :text => text_not_supported }
     end
   end
-  
-  def to_xml
+
+
+  private
+
+  def to_xml(reviews, convert_markdown)
     xml = Builder::XmlMarkup.new(:indent => 0)
     xml.instruct!
     
     xml.reviews do
-      @reviews.each do |review|
+      reviews.each do |review|
         xml.review do
-          xml.id(review.id)
-          xml.updatedAt(review.updated_at)
+          xml.id(review.id.to_i)
+          xml.updatedAt(format_datetime(review.updated_at))
           xml.user(review.user.login)
           xml.assignee(review.assignee.login)
           xml.title(review.title)
           xml.type(review.review_type)
           xml.status(review.status)
           xml.severity(review.severity)
-          xml.resourceLine(review.resource_line)
+          xml.resource(review.resource.kee)  if review.resource
+          xml.line(review.resource_line) if review.resource_line
           
-          # Continue here with resource + violation + comments
+          # Continue here with resource + comments
         end
       end
     end
   end
   
-  def to_json
-    JSON(@reviews.collect{|review| review.to_hash_json(true)})
+  def to_json(reviews, convert_markdown=false)
+    JSON(reviews.collect{|review| review_to_json(review, convert_markdown)})
   end
-    
+
+  def review_to_json(review, html=false)
+    json = {}
+    json['id'] = review.id.to_i
+    json['updatedAt'] = review.updated_at
+    json['author'] = review.user.login
+    json['assignee'] = review.assignee.login if review.assignee
+    json['title'] = review.title if review.title
+    json['type'] = review.review_type
+    json['status'] = review.status
+    json['severity'] = review.severity
+    comments = []
+    review.review_comments.each do |comment|
+      comments << {
+        'author' => comment.user.login,
+        'updatedAt' => format_datetime(comment.updated_at),
+        'comment' => (html ? markdown_to_html(comment.review_text): comment.review_text)
+      }
+    end
+    json['comments'] = comments
+    json['line'] = review.resource_line if review.resource_line
+    json['resource'] = review.resource.kee if review.resource
+    json
+  end
+
 end
\ No newline at end of file
index 01d521b251c48de8c603a69db9645842bb76bbc8..679d68dc3d0c24a1c24deb0d1c1f6bbc9c27e07a 100644 (file)
@@ -74,7 +74,7 @@ class Api::ViolationsController < Api::ResourceRestController
       end.compact
     end
     
-    if params[:switched_off] && params[:switched_off] == "true"
+    if params[:switched_off] == "true"
       conditions << 'switched_off=:switched_off'
       values[:switched_off] = true
     else
@@ -85,7 +85,7 @@ class Api::ViolationsController < Api::ResourceRestController
     limit = (params[:limit] ? [params[:limit].to_i,5000].min : 5000) 
     violations = RuleFailure.find(:all,
       :conditions => [ conditions.join(' AND '), values],
-      :include => [:snapshot, {:snapshot => :project}, :rule],
+      :include => [:snapshot, {:snapshot => :project}, :rule, :review],
       :order => 'rule_failures.failure_level DESC',
       :limit => limit)
     rest_render(violations)
index bd4f648188529caa1bc4b58ae90960d4865f0808..0c6aedf79bbb1a7e5b2f3812e8a3d28a33ed0b48 100644 (file)
@@ -20,7 +20,7 @@
 module MarkdownHelper
 
   def markdown_to_html(input)
-    input ? Java::OrgSonarServerUi::JRubyFacade.markdownToHtml(h(input)) : ''
+    input ? Java::OrgSonarServerUi::JRubyFacade.markdownToHtml(ERB::Util.html_escape(input)) : ''
   end
 
 end
\ No newline at end of file
index b05498c097fd35841960b9c3822383e14b7ed37e..f6d7bdc0939f9062439218a5019a48000b67c048 100644 (file)
@@ -48,6 +48,46 @@ class Review < ActiveRecord::Base
         rule_failure ? rule_failure.rule : nil
       end
   end
+
+  def self.search(options={})
+    conditions=['review_type<>:not_type']
+    values={:not_type => Review::TYPE_FALSE_POSITIVE}
+
+    ids=options['ids']
+    if options[:id]
+      conditions << "id=:id"
+      values[:id]=options[:id].to_i
+    elsif ids && ids.size>0 && !ids[0].blank?
+      conditions << "id in (:ids)"
+      values[:ids]=ids.map{|id| id.to_i}
+    end
+
+    statuses=options['statuses']
+    if statuses && statuses.size>0 && !statuses[0].blank?
+      conditions << "status in (:statuses)"
+      values[:statuses]=statuses
+    end
+
+    severities=options['severities']
+    if severities && severities.size>0 && !severities[0].blank?
+      conditions << "severity in (:severities)"
+      values[:severities]=severities
+    end
+
+    authors=options['authors']
+    if authors && authors.size>0 && !authors[0].blank?
+      conditions << "user_id in (:authors)"
+      values[:authors]=User.logins_to_ids(authors)
+    end
+
+    assignees=options['assignees']
+    if assignees && assignees.size>0 && !assignees[0].blank?
+      conditions << "assignee_id in (:assignees)"
+      values[:assignees]=User.logins_to_ids(assignees)
+    end
+
+    Review.find(:all, :order => "created_at DESC", :conditions => [conditions.join(" AND "), values], :limit => 200)
+  end
   
   private
   
@@ -56,31 +96,5 @@ class Review < ActiveRecord::Base
       self.project=self.resource.project
     end
   end
-
-  def to_hash_json ( extended )
-    json = {}
-    json['id'] = id
-    json['updatedAt'] = updated_at
-    json['author'] = user.login
-    json['assignee'] = assignee.login if assignee
-    json['title'] = title
-    json['type'] = review_type
-    json['status'] = status
-    json['severity'] = severity
-    comments = []
-    review_comments.each do |comment|
-      comments << {
-        'author' => comment.user.login,
-        'updatedAt' => comment.updated_at,
-        'comment' => comment.review_text
-      }
-    end
-    json['comments'] = comments
-    if ( extended )
-      json['line'] = resource_line if resource_line
-      json['resource'] = resource.kee if resource
-    end
-    json
-  end
   
 end
index 890c4e7dd90746d9a2fa9ff41c3e0ebb8561abbc..0d66db2da288d7e3da8019c4ea65aa8118a775eb 100644 (file)
@@ -46,7 +46,7 @@ class RuleFailure < ActiveRecord::Base
     json['message'] = message
     json['line'] = line if line
     json['priority'] = Sonar::RulePriority.to_s(failure_level).upcase
-    json['switchedOff'] = switched_off ? true : false
+    json['falsePositive']=true if false_positive?
     if created_at
       json['createdAt'] = format_datetime(created_at)
     end
@@ -61,7 +61,7 @@ class RuleFailure < ActiveRecord::Base
       :qualifier => snapshot.project.qualifier,
       :language => snapshot.project.language
     }
-    json['review'] = review.to_hash_json(false) if review
+    json['review']=review.id if review
     json
   end
 
@@ -70,7 +70,7 @@ class RuleFailure < ActiveRecord::Base
       xml.message(message)
       xml.line(line) if line
       xml.priority(Sonar::RulePriority.to_s(failure_level))
-      xml.switchedOff(switched_off ? true : false)
+      xml.falsePositive(true) if false_positive?
       if created_at
         xml.createdAt(format_datetime(created_at))
       end
@@ -85,6 +85,7 @@ class RuleFailure < ActiveRecord::Base
         xml.qualifier(snapshot.project.qualifier)
         xml.language(snapshot.project.language)
       end
+      xml.review(review.id) if review
     end
   end
 
index abf3a00c846aaaf815b1dc0690126f29df7f8303..9176f859763ca23813686803b14b88576b4eb319 100644 (file)
@@ -117,6 +117,14 @@ class User < ActiveRecord::Base
       properties.delete(prop)
     end
   end
+
+  def self.logins_to_ids(logins=[])
+    if logins.size>0
+      User.find(:all, :select => 'id', :conditions => ['login in (?)', logins]).map{|user| user.id}
+    else
+      []
+    end
+  end
   
   #---------------------------------------------------------------------
   # FAVOURITES
index e29c37396ba19ae08c2f5f80f9394ba66b713a8b..0d5b816425fb3e35edcc6874ec973bed6cdd6ded 100644 (file)
@@ -33,7 +33,8 @@ public class Violation extends Model {
   private String resourceScope = null;
   private String resourceQualifier = null;
   private Date createdAt = null;
-  private boolean switchedOff;
+  private boolean falsePositive;
+  private Long reviewId = null;
 
   public String getMessage() {
     return message;
@@ -159,16 +160,24 @@ public class Violation extends Model {
   /**
    * @since 2.8
    */
-  public Violation setSwitchedOff(boolean switchedOff) {
-    this.switchedOff = switchedOff;
+  public Violation setFalsePositive(Boolean b) {
+    this.falsePositive = (b != null && b);
     return this;
   }
 
   /**
    * @since 2.8
    */
-  public boolean isSwitchedOff() {
-    return switchedOff;
+  public boolean isFalsePositive() {
+    return falsePositive;
   }
 
+  public Long getReviewId() {
+    return reviewId;
+  }
+
+  public Violation setReviewId(Long l) {
+    this.reviewId = l;
+    return this;
+  }
 }
index df62e5c0e16dbda439ea3e6483a0a2d2c78d4a80..45f692b582c6f5bec613aed36e40e96f9f8e8c94 100644 (file)
@@ -33,7 +33,8 @@ public class ViolationUnmarshaller extends AbstractUnmarshaller<Violation> {
     violation.setLine(utils.getInteger(json, "line"));
     violation.setSeverity(utils.getString(json, "priority"));
     violation.setCreatedAt(utils.getDateTime(json, "createdAt"));
-    violation.setSwitchedOff(utils.getBoolean(json, "switchedOff"));
+    violation.setFalsePositive(utils.getBoolean(json, "falsePositive"));
+    violation.setReviewId(utils.getLong(json, "review"));
 
     Object rule = utils.getField(json, "rule");
     if (rule != null) {
index 3f3da0e81fc88b540664a57c3a41d3996e3af432..dc9a8c4cc2d5c082cdb6b27c278dc2a5c9e6f60a 100644 (file)
  */
 package org.sonar.wsclient.unmarshallers;
 
+import org.junit.Test;
+import org.sonar.wsclient.services.Violation;
+
+import java.util.List;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.core.IsNot.not;
 import static org.junit.Assert.assertThat;
 
-import java.util.List;
-
-import org.junit.Test;
-import org.sonar.wsclient.services.Violation;
-
 public class ViolationUnmarshallerTest extends UnmarshallerTestCase {
 
   @Test
-  public void toModels() {
+  public void testToModels() {
     Violation violation = new ViolationUnmarshaller().toModel("[]");
     assertThat(violation, nullValue());
 
@@ -52,15 +52,22 @@ public class ViolationUnmarshallerTest extends UnmarshallerTestCase {
     assertThat(violation.getResourceName(), is("TraceableResourceLimitingPool"));
     assertThat(violation.getResourceQualifier(), is("CLA"));
     assertThat(violation.getResourceScope(), is("FIL"));
-    assertThat(violation.isSwitchedOff(), is(true));
+    assertThat(violation.isFalsePositive(), is(false));
+    assertThat(violation.getReviewId(), nullValue());
   }
 
   @Test
-  public void violationWithoutLineNumber() {
+  public void testViolationWithoutLineNumber() {
     Violation violation = new ViolationUnmarshaller().toModel(loadFile("/violations/violation-without-optional-fields.json"));
     assertThat(violation.getMessage(), not(nullValue()));
     assertThat(violation.getLine(), nullValue());
     assertThat(violation.getCreatedAt(), nullValue());
   }
 
+  @Test
+  public void testFalsePositive() {
+    Violation violation = new ViolationUnmarshaller().toModel(loadFile("/violations/false-positive.json"));
+    assertThat(violation.isFalsePositive(), is(true));
+    assertThat(violation.getReviewId(), is(123L));
+  }
 }
diff --git a/sonar-ws-client/src/test/resources/violations/false-positive.json b/sonar-ws-client/src/test/resources/violations/false-positive.json
new file mode 100644 (file)
index 0000000..d84cb15
--- /dev/null
@@ -0,0 +1,3 @@
+[
+  {"message":"throw java.lang.Exception","falsePositive": true, "review": 123, "priority":"MAJOR","rule":{"key":"pmd:SignatureDeclareThrowsException","name":"Signature Declare Throws Exception","category":"Maintainability"},"resource":{"key":"org.apache.excalibur.components:excalibur-pool-instrumented:org.apache.avalon.excalibur.pool.TraceableResourceLimitingPool","name":"TraceableResourceLimitingPool","scope":"FIL","qualifier":"CLA","language":"java"}}
+]
\ No newline at end of file
index 7c8aa24b70ad601c0b10121e835a7cd25619b136..7923febf306f40dce9904965970194523ca2d036 100644 (file)
@@ -1,3 +1,3 @@
 [
-  {"message":"throw java.lang.Exception","priority":"MAJOR","switchedOff":true,"rule":{"key":"pmd:SignatureDeclareThrowsException","name":"Signature Declare Throws Exception","category":"Maintainability"},"resource":{"key":"org.apache.excalibur.components:excalibur-pool-instrumented:org.apache.avalon.excalibur.pool.TraceableResourceLimitingPool","name":"TraceableResourceLimitingPool","scope":"FIL","qualifier":"CLA","language":"java"}},
+  {"message":"throw java.lang.Exception","priority":"MAJOR","rule":{"key":"pmd:SignatureDeclareThrowsException","name":"Signature Declare Throws Exception","category":"Maintainability"},"resource":{"key":"org.apache.excalibur.components:excalibur-pool-instrumented:org.apache.avalon.excalibur.pool.TraceableResourceLimitingPool","name":"TraceableResourceLimitingPool","scope":"FIL","qualifier":"CLA","language":"java"}}
 ]
\ No newline at end of file
index 1dbad54bb6ec9846db22eb0a9c2d0ee88d0c18a3..92c98b332f088fb2328ff226516ff393c4bf252f 100644 (file)
@@ -1,4 +1,4 @@
 [
-  {"message":"throw java.lang.Exception","line":97,"createdAt":"2010-12-01T13:55:22+0300","priority":"MAJOR","switchedOff":true,"rule":{"key":"pmd:SignatureDeclareThrowsException","name":"Signature Declare Throws Exception","category":"Maintainability"},"resource":{"key":"org.apache.excalibur.components:excalibur-pool-instrumented:org.apache.avalon.excalibur.pool.TraceableResourceLimitingPool","name":"TraceableResourceLimitingPool","scope":"FIL","qualifier":"CLA","language":"java"}},
-  {"message":"The user-supplied array 'threads' is stored directly.","line":242,"createdAt":"2010-12-01T13:55:22+0300","priority":"MAJOR","switchedOff":false,"rule":{"key":"pmd:ArrayIsStoredDirectly","name":"Security - Array is stored directly","category":"Reliability"},"resource":{"key":"org.apache.excalibur.components:excalibur-pool-instrumented:org.apache.avalon.excalibur.pool.TraceableResourceLimitingPool","name":"TraceableResourceLimitingPool","scope":"FIL","qualifier":"CLA","language":"java"}}
+  {"message":"throw java.lang.Exception","line":97,"createdAt":"2010-12-01T13:55:22+0300","priority":"MAJOR","rule":{"key":"pmd:SignatureDeclareThrowsException","name":"Signature Declare Throws Exception","category":"Maintainability"},"resource":{"key":"org.apache.excalibur.components:excalibur-pool-instrumented:org.apache.avalon.excalibur.pool.TraceableResourceLimitingPool","name":"TraceableResourceLimitingPool","scope":"FIL","qualifier":"CLA","language":"java"}},
+  {"message":"The user-supplied array 'threads' is stored directly.","line":242,"createdAt":"2010-12-01T13:55:22+0300","priority":"MAJOR","rule":{"key":"pmd:ArrayIsStoredDirectly","name":"Security - Array is stored directly","category":"Reliability"},"resource":{"key":"org.apache.excalibur.components:excalibur-pool-instrumented:org.apache.avalon.excalibur.pool.TraceableResourceLimitingPool","name":"TraceableResourceLimitingPool","scope":"FIL","qualifier":"CLA","language":"java"}}
 ]
\ No newline at end of file