@@ -16,7 +16,7 @@ | |||
<td></td> | |||
</tr> | |||
<tr> | |||
<td>assertElementPresent</td> | |||
<td>waitForElementPresent</td> | |||
<td>timeline-chart-1</td> | |||
<td></td> | |||
</tr> |
@@ -8,7 +8,7 @@ | |||
if metric | |||
metric_ids << metric.id | |||
row=Sonar::TimemachineRow.new(metric) | |||
rows_by_metric_id[metric.id]=row | |||
rows_by_metric_id[metric.id] = row | |||
end | |||
end | |||
if metric_ids.empty? | |||
@@ -24,29 +24,26 @@ | |||
if from_date | |||
options[:from] = from_date | |||
end | |||
snapshots=Snapshot.for_timemachine_widget(@resource, number_of_columns, options) | |||
sids = snapshots.collect { |s| s.id }.uniq | |||
measures=ProjectMeasure.find(:all, | |||
analyses = Snapshot.for_timemachine_widget(@resource, number_of_columns, options) | |||
analysis_uuids = analyses.collect { |a| a.uuid }.uniq | |||
measures = ProjectMeasure.find(:all, | |||
:conditions => | |||
["snapshot_id IN (:snapshot_id) AND metric_id IN (:metric_id) AND person_id IS NULL", | |||
{:snapshot_id => sids, :metric_id => metric_ids} | |||
["analysis_uuid IN (:analysis_uuids) AND component_uuid = :component_uuid and metric_id IN (:metric_id) AND person_id IS NULL", | |||
{:analysis_uuids => analysis_uuids, :component_uuid => @resource.uuid, :metric_id => metric_ids} | |||
] | |||
) | |||
# Prepare the rows to display | |||
snapshot_by_id={} | |||
snapshots.each do |s| | |||
snapshot_by_id[s.id]=s | |||
analyses_by_uuid = {} | |||
analyses.each do |a| | |||
analyses_by_uuid[a.uuid] = a | |||
end | |||
measures.each do |measure| | |||
next unless measure.metric | |||
if measure.metric.timemachine? && (measure.value || measure.text_value) | |||
row=rows_by_metric_id[measure.metric_id] | |||
#optimization : avoid eager loading of snapshots | |||
measure.snapshot=snapshot_by_id[measure.snapshot_id] | |||
row = rows_by_metric_id[measure.metric_id] | |||
row.add_measure(measure) | |||
end | |||
end | |||
@@ -64,7 +61,7 @@ | |||
sparklines_by_row = {} | |||
if widget_properties["displaySparkLine"] | |||
rows.each do |row| | |||
sparkline = row.sparkline | |||
sparkline = row.sparkline(analyses) | |||
sparklines_by_row[row] = sparkline if sparkline | |||
end | |||
end | |||
@@ -84,11 +81,11 @@ | |||
<tr> | |||
<th></th> | |||
<% | |||
snapshots.each do |snapshot| | |||
event = snapshot.event('Version') | |||
analyses.each do |analysis| | |||
event = analysis.event('Version') | |||
%> | |||
<th nowrap="nowrap" style="vertical-align:top;text-align: right;font-size: 10px"> | |||
<%= l snapshot.created_at.to_date -%> | |||
<%= l analysis.created_at.to_date -%> | |||
<br/> | |||
<%= event.name unless event==nil -%> | |||
</th> | |||
@@ -108,8 +105,8 @@ | |||
<%= row.metric.short_name %> | |||
</td> | |||
<% | |||
snapshots.each do |snapshot| | |||
measure=row.measure(snapshot) | |||
analyses.each do |analysis| | |||
measure = row.measure(analysis) | |||
%> | |||
<td width="1%" nowrap="nowrap" class="right"><%= format_measure(measure, :skip_span_id => true) %></td> | |||
<% end %> |
@@ -32,45 +32,45 @@ | |||
options[:from] = from_date | |||
end | |||
# Variables used if undefinedToZero is set to true | |||
previous_snapshot_id = nil | |||
previous_analysis_uuid = nil | |||
previous_created_at = nil | |||
first_trend_item = true | |||
metric_previous_snapshot_id = {} | |||
metric_count_per_snapshot_id = {} | |||
metric_previous_analysis_uuid = {} | |||
metric_count_per_analysis_uuid = {} | |||
total_number_of_metrics = metric_map.keys.size() | |||
TrendsChart.time_machine_measures(@resource, metric_data_map.keys, options).each() do |trend_item| | |||
sid = trend_item["sid"] | |||
analysis_uuid = trend_item["analysis_uuid"] | |||
if undefinedToZero | |||
if first_trend_item | |||
first_trend_item = false | |||
previous_snapshot_id = sid | |||
previous_analysis_uuid = analysis_uuid | |||
previous_created_at = Time.at(trend_item["created_at"].to_i/1000) | |||
end | |||
if previous_snapshot_id != sid | |||
if metric_count_per_snapshot_id[previous_snapshot_id] != total_number_of_metrics | |||
if previous_analysis_uuid != analysis_uuid | |||
if metric_count_per_analysis_uuid[previous_analysis_uuid] != total_number_of_metrics | |||
metric_map.keys.each do |metric_id| | |||
unless metric_previous_snapshot_id.include?(metric_id) | |||
metric_data_map[metric_id] << {:date => previous_created_at, :value => 0.00, :sid => previous_snapshot_id} | |||
if metric_count_per_snapshot_id[previous_snapshot_id] | |||
metric_count_per_snapshot_id[previous_snapshot_id] += 1 | |||
unless metric_previous_analysis_uuid.include?(metric_id) | |||
metric_data_map[metric_id] << {:date => previous_created_at, :value => 0.00, :analysis_uuid => previous_analysis_uuid} | |||
if metric_count_per_analysis_uuid[previous_analysis_uuid] | |||
metric_count_per_analysis_uuid[previous_analysis_uuid] += 1 | |||
else | |||
metric_count_per_snapshot_id[previous_snapshot_id] = 1 | |||
metric_count_per_analysis_uuid[previous_analysis_uuid] = 1 | |||
end | |||
end | |||
end | |||
end | |||
previous_snapshot_id = sid | |||
previous_analysis_uuid = analysis_uuid | |||
previous_created_at = Time.at(trend_item["created_at"].to_i/1000) | |||
metric_previous_snapshot_id = {} | |||
metric_previous_analysis_uuid = {} | |||
end | |||
metric_previous_snapshot_id[trend_item["metric_id"].to_i] = 1 | |||
metric_previous_analysis_uuid[trend_item["metric_id"].to_i] = 1 | |||
end | |||
if metric_count_per_snapshot_id[sid] | |||
metric_count_per_snapshot_id[sid] += 1 | |||
if metric_count_per_analysis_uuid[analysis_uuid] | |||
metric_count_per_analysis_uuid[analysis_uuid] += 1 | |||
else | |||
metric_count_per_snapshot_id[sid] = 1 | |||
metric_count_per_analysis_uuid[analysis_uuid] = 1 | |||
end | |||
metric_data_map[trend_item["metric_id"].to_i] << {:date => Time.at(trend_item["created_at"].to_i/1000), :value => trend_item["value"], :sid => trend_item["sid"]} | |||
metric_data_map[trend_item["metric_id"].to_i] << {:date => Time.at(trend_item["created_at"].to_i/1000), :value => trend_item["value"], :analysis_uuid => trend_item["analysis_uuid"]} | |||
end | |||
# Create JS structures to print out in the HTML page | |||
@@ -83,7 +83,7 @@ | |||
js_data += "[" | |||
metric_data_map[metric_id].each() do |metric_data| | |||
# for every metric value, we need to check that the corresponding snapshot has values for each metric | |||
if metric_count_per_snapshot_id[metric_data[:sid]]==total_number_of_metrics | |||
if metric_count_per_analysis_uuid[metric_data[:analysis_uuid]]==total_number_of_metrics | |||
m_date = metric_data[:date] | |||
m_value = sprintf("%0.02f", metric_data[:value]) | |||
m_value_localized = ProjectMeasure.new(:metric => metric_map[metric_id]).format_numeric_value(metric_data[:value], {}) | |||
@@ -107,9 +107,9 @@ | |||
js_data += "\"}," | |||
if index == 0 | |||
# we fill the js_snapshots array (no need to do this more than once) | |||
js_snapshots += "{sid:" | |||
js_snapshots += metric_data[:sid].to_s | |||
js_snapshots += ",d:\"" | |||
js_snapshots += "{sid:\"" | |||
js_snapshots += metric_data[:analysis_uuid] | |||
js_snapshots += "\",d:\"" | |||
js_snapshots += human_short_date m_date | |||
js_snapshots += "\"}," | |||
end | |||
@@ -143,9 +143,9 @@ | |||
js_events = "[" | |||
events.keys().sort.each() do |e_date| | |||
e_details = events[e_date] | |||
js_events += "{sid:" | |||
js_events += e_details[0].snapshot.id.to_s | |||
js_events += ",d:d(" | |||
js_events += "{sid:\"" | |||
js_events += e_details[0].analysis_uuid | |||
js_events += "\",d:d(" | |||
js_events += e_date.year.to_s | |||
js_events += "," | |||
# Need to decrease by 1 the month as the JS Date object start months at 0 (= January) |
@@ -488,10 +488,6 @@ public class MeasureFilterExecutorTest { | |||
public void escape_percent_and_underscore_when_filter_by_component_name_or_key() throws SQLException { | |||
db.prepareDbUnit(getClass(), "escape_percent_and_underscore_when_filter_by_component_name_or_key.xml"); | |||
// assertThat(executor.execute( | |||
// new MeasureFilter().setResourceQualifiers(newArrayList("FIL")).setResourceKey("java_"), | |||
// new MeasureFilterContext())).hasSize(2); | |||
assertThat(executor.execute( | |||
new MeasureFilter().setResourceQualifiers(newArrayList("FIL")).setResourceName("java%"), | |||
new MeasureFilterContext())).hasSize(2); |
@@ -137,7 +137,7 @@ class Api::EventsController < Api::ApiController | |||
end | |||
raise "A version already exists on this resource." if params[:category]==EventCategory::KEY_VERSION && root_snapshot.event(EventCategory::KEY_VERSION) | |||
raise "An event '#{params[:name]}' (category '#{params[:category]}') already exists on this resource." if Event.already_exists(@resource.last_snapshot.id, params[:name], params[:category]) | |||
raise "An event '#{params[:name]}' (category '#{params[:category]}') already exists on this resource." if Event.already_exists(@resource.last_analysis.id, params[:name], params[:category]) | |||
# Create events for the root project and every submodule | |||
event_to_return = nil |
@@ -104,7 +104,7 @@ class Api::ResourcesController < Api::ApiController | |||
resource_id=params[:resource] | |||
if resource_id | |||
@resource=Project.by_key(resource_id) | |||
@analysis=(@resource && @resource.last_snapshot) | |||
@analysis=(@resource && @resource.last_analysis) | |||
raise ApiException.new(404, "Resource [#{resource_id}] not found") if @analysis.nil? | |||
raise ApiException.new(401, "Unauthorized") unless has_role?(:user, @resource) | |||
else | |||
@@ -195,7 +195,7 @@ class Api::ResourcesController < Api::ApiController | |||
# ---------- LOAD COMPONENTS | |||
# H2 does not support empty lists, so short-breaking if no measures | |||
if load_measures && measures_by_component_uuid.empty? | |||
if measures_limit && measures_by_component_uuid.empty? | |||
components = [] | |||
else | |||
components = Project.all( | |||
@@ -284,7 +284,7 @@ class Api::ResourcesController < Api::ApiController | |||
xml.resources do | |||
components.each do |component| | |||
measures = measures_by_component_uuid[component.uuid] | |||
resource_to_xml(xml, component, measures, params) | |||
component_to_xml(xml, component, measures, params) | |||
end | |||
end | |||
end | |||
@@ -310,26 +310,26 @@ class Api::ResourcesController < Api::ApiController | |||
json['version']= component.last_analysis.version if component.last_analysis && component.last_analysis.version | |||
json['branch']=component.branch if component.branch | |||
json['description']=component.description if component.description | |||
if include_trends && component.last_snapshot | |||
json[:p1]=component.last_snapshot.period1_mode if component.last_snapshot.period1_mode | |||
json[:p1p]=component.last_snapshot.period1_param if component.last_snapshot.period1_param | |||
json[:p1d]=Api::Utils.format_datetime(component.last_snapshot.period1_date) if component.last_snapshot.period1_date | |||
json[:p2]=component.last_snapshot.period2_mode if component.last_snapshot.period2_mode | |||
json[:p2p]=component.last_snapshot.period2_param if component.last_snapshot.period2_param | |||
json[:p2d]=Api::Utils.format_datetime(component.last_snapshot.period2_date) if component.last_snapshot.period2_date | |||
json[:p3]=component.last_snapshot.period3_mode if component.last_snapshot.period3_mode | |||
json[:p3p]=component.last_snapshot.period3_param if component.last_snapshot.period3_param | |||
json[:p3d]=Api::Utils.format_datetime(component.last_snapshot.period3_date) if component.last_snapshot.period3_date | |||
json[:p4]=component.last_snapshot.period4_mode if component.last_snapshot.period4_mode | |||
json[:p4p]=component.last_snapshot.period4_param if component.last_snapshot.period4_param | |||
json[:p4d]=Api::Utils.format_datetime(component.last_snapshot.period4_date) if component.last_snapshot.period4_date | |||
json[:p5]=component.last_snapshot.period5_mode if component.last_snapshot.period5_mode | |||
json[:p5p]=component.last_snapshot.period5_param if component.last_snapshot.period5_param | |||
json[:p5d]=Api::Utils.format_datetime(component.last_snapshot.period5_date) if component.last_snapshot.period5_date | |||
if include_trends && component.last_analysis | |||
json[:p1]=component.last_snapshot.period1_mode if component.last_analysis.period1_mode | |||
json[:p1p]=component.last_analysis.period1_param if component.last_analysis.period1_param | |||
json[:p1d]=Api::Utils.format_datetime(component.last_analysis.period1_date) if component.last_analysis.period1_date | |||
json[:p2]=component.last_analysis.period2_mode if component.last_analysis.period2_mode | |||
json[:p2p]=component.last_analysis.period2_param if component.last_analysis.period2_param | |||
json[:p2d]=Api::Utils.format_datetime(component.last_analysis.period2_date) if component.last_analysis.period2_date | |||
json[:p3]=component.last_analysis.period3_mode if component.last_analysis.period3_mode | |||
json[:p3p]=component.last_analysis.period3_param if component.last_analysis.period3_param | |||
json[:p3d]=Api::Utils.format_datetime(component.last_analysis.period3_date) if component.last_analysis.period3_date | |||
json[:p4]=component.last_analysis.period4_mode if component.last_analysis.period4_mode | |||
json[:p4p]=component.last_analysis.period4_param if component.last_analysis.period4_param | |||
json[:p4d]=Api::Utils.format_datetime(component.last_analysis.period4_date) if component.last_analysis.period4_date | |||
json[:p5]=component.last_analysis.period5_mode if component.last_analysis.period5_mode | |||
json[:p5p]=component.last_analysis.period5_param if component.last_analysis.period5_param | |||
json[:p5d]=Api::Utils.format_datetime(component.last_analysis.period5_date) if component.last_analysis.period5_date | |||
end | |||
if measures | |||
json_measures=[] | |||
@@ -365,7 +365,7 @@ class Api::ResourcesController < Api::ApiController | |||
json | |||
end | |||
def resource_to_xml(xml, component, measures, options={}) | |||
def component_to_xml(xml, component, measures, options={}) | |||
verbose=(options[:verbose]=='true') | |||
include_alerts=(options[:includealerts]=='true') | |||
include_trends=(options[:includetrends]=='true') | |||
@@ -380,31 +380,31 @@ class Api::ResourcesController < Api::ApiController | |||
xml.scope(component.scope) | |||
xml.qualifier(component.qualifier) | |||
xml.lang(component.language) if component.language | |||
xml.version(snapshot.version) if snapshot.version | |||
xml.date(Api::Utils.format_datetime(snapshot.created_at)) | |||
xml.creationDate(Api::Utils.format_datetime(resource.created_at)) | |||
xml.description(resource.description) if include_descriptions && resource.description | |||
if include_trends && component.last_snapshot | |||
xml.period1(component.last_snapshot.period1_mode) if component.last_snapshot.period1_mode | |||
xml.period1_param(component.last_snapshot.period1_param) if component.last_snapshot.period1_param | |||
xml.period1_date(Api::Utils.format_datetime(component.last_snapshot.period1_date)) if component.last_snapshot.period1_date | |||
xml.period2(component.last_snapshot.period2_mode) if component.last_snapshot.period2_mode | |||
xml.period2_param(component.last_snapshot.period2_param) if component.last_snapshot.period2_param | |||
xml.period2_date(Api::Utils.format_datetime(component.last_snapshot.period2_date)) if component.last_snapshot.period2_date | |||
xml.period3(component.last_snapshot.period3_mode) if component.last_snapshot.period3_mode | |||
xml.period3_param(component.last_snapshot.period3_param) if component.last_snapshot.period3_param | |||
xml.period3_date(Api::Utils.format_datetime(component.last_snapshot.period3_date)) if component.last_snapshot.period3_date | |||
xml.period4(component.last_snapshot.period4_mode) if component.last_snapshot.period4_mode | |||
xml.period4_param(component.last_snapshot.period4_param) if component.last_snapshot.period4_param | |||
xml.period4_date(Api::Utils.format_datetime(component.last_snapshot.period4_date)) if component.last_snapshot.period4_date | |||
xml.period5(component.last_snapshot.period5_mode) if component.last_snapshot.period5_mode | |||
xml.period5_param(component.last_snapshot.period5_param) if component.last_snapshot.period5_param | |||
xml.period5_date(Api::Utils.format_datetime(component.last_snapshot.period5_date)) if component.last_snapshot.period5_date | |||
xml.version(component.last_analysis.version) if component.last_analysis && component.last_analysis.version | |||
xml.date(Api::Utils.format_datetime(component.last_analysis.created_at)) if component.last_analysis | |||
xml.creationDate(Api::Utils.format_datetime(component.created_at)) | |||
xml.description(component.description) if include_descriptions && component.description | |||
if include_trends && component.last_analysis | |||
xml.period1(component.last_analysis.period1_mode) if component.last_analysis.period1_mode | |||
xml.period1_param(component.last_analysis.period1_param) if component.last_analysis.period1_param | |||
xml.period1_date(Api::Utils.format_datetime(component.last_analysis.period1_date)) if component.last_analysis.period1_date | |||
xml.period2(component.last_analysis.period2_mode) if component.last_analysis.period2_mode | |||
xml.period2_param(component.last_analysis.period2_param) if component.last_analysis.period2_param | |||
xml.period2_date(Api::Utils.format_datetime(component.last_analysis.period2_date)) if component.last_analysis.period2_date | |||
xml.period3(component.last_analysis.period3_mode) if component.last_analysis.period3_mode | |||
xml.period3_param(component.last_analysis.period3_param) if component.last_analysis.period3_param | |||
xml.period3_date(Api::Utils.format_datetime(component.last_analysis.period3_date)) if component.last_analysis.period3_date | |||
xml.period4(component.last_analysis.period4_mode) if component.last_analysis.period4_mode | |||
xml.period4_param(component.last_analysis.period4_param) if component.last_analysis.period4_param | |||
xml.period4_date(Api::Utils.format_datetime(component.last_analysis.period4_date)) if component.last_analysis.period4_date | |||
xml.period5(component.last_analysis.period5_mode) if component.last_analysis.period5_mode | |||
xml.period5_param(component.last_analysis.period5_param) if component.last_analysis.period5_param | |||
xml.period5_date(Api::Utils.format_datetime(component.last_analysis.period5_date)) if component.last_analysis.period5_date | |||
end | |||
if measures |
@@ -30,9 +30,9 @@ class ComparisonController < ApplicationController | |||
project = Project.by_key(resource_key) | |||
return render_not_found('Project not found') unless project | |||
snapshots = project.events.select { |event| !event.snapshot.nil? && event.category==EventCategory::KEY_VERSION }[0..5].reverse.map {|e| e.snapshot} | |||
snapshots = project.events.select { |event| event.snapshot && event.category==EventCategory::KEY_VERSION }[0..5].reverse.map {|e| e.snapshot} | |||
# if last snapshot is not in the list, add it at the end (=> might be the case for views or developers which do not have events) | |||
last_snapshot = project.last_snapshot | |||
last_snapshot = project.last_analysis | |||
unless snapshots.last == last_snapshot | |||
snapshots.shift | |||
snapshots.push(last_snapshot) | |||
@@ -79,7 +79,7 @@ class ComparisonController < ApplicationController | |||
@versions = project.events.select { |event| event.category==EventCategory::KEY_VERSION && !suuids.include?(event.analysis_uuid.to_s) } | |||
# check if the latest snapshot if suggested or not (and if not, suggest it as "LATEST" => this is used for views or developers which do not have events) | |||
latest_snapshot_uuid = project.last_snapshot.uuid | |||
latest_snapshot_uuid = project.last_analysis.uuid | |||
current_and_suggested_suuids = suuids + @versions.map {|e| e.analysis_uuid.to_s} | |||
unless current_and_suggested_suuids.include?(latest_snapshot_uuid.to_s) | |||
@versions.unshift Event.new(:name => Api::Utils.message('comparison.version.latest'), :analysis_uuid => latest_snapshot_uuid) |
@@ -218,7 +218,7 @@ class ProjectController < ApplicationController | |||
redirect_to :action => 'index', :id => params[:id] | |||
end | |||
@snapshot = @project.last_snapshot | |||
@snapshot = @project.last_analysis | |||
@analyses = Snapshot.all(:conditions => ["status='P' AND component_uuid=?", @project.uuid], | |||
:include => 'events', :order => 'snapshots.created_at DESC') | |||
end |
@@ -1,28 +0,0 @@ | |||
# | |||
# 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 | |||
# License along with {library}; if not, write to the Free Software | |||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
# | |||
class ChartMeasure | |||
attr_accessor :time, :value | |||
def initialize(time, value) | |||
@time = time | |||
@value = value | |||
end | |||
end |
@@ -1,22 +0,0 @@ | |||
# | |||
# 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 LoadedTemplate < ActiveRecord::Base | |||
end |
@@ -286,7 +286,7 @@ class MeasureFilter < ActiveRecord::Base | |||
rows_by_component_uuid[component.uuid].set_analysis(analysis) if analysis | |||
end | |||
# @rows must be in the same order than the component uuids | |||
# @rows must be in the same order as the component uuids | |||
component_uuids.each do |uuid| | |||
@rows << rows_by_component_uuid[uuid] | |||
end |
@@ -32,7 +32,7 @@ class Project < ActiveRecord::Base | |||
has_many :authors, :foreign_key => 'person_id', :dependent => :delete_all | |||
has_one :index, :class_name => 'ResourceIndex', :foreign_key => 'component_uuid', :primary_key => 'uuid', :conditions => 'position=0', :select => 'kee' | |||
has_many :resource_index, :foreign_key => 'resource_id' | |||
has_one :last_analysis, :class_name => 'Snapshot', :foreign_key => 'component_uuid', :primary_key => 'uuid', :conditions => ['snapshots.islast=?', true] | |||
has_one :last_analysis, :class_name => 'Snapshot', :foreign_key => 'component_uuid', :primary_key => 'project_uuid', :conditions => ['snapshots.islast=?', true] | |||
def self.by_key(k) | |||
begin | |||
@@ -68,6 +68,10 @@ class Project < ActiveRecord::Base | |||
root||self | |||
end | |||
def root? | |||
project_uuid == uuid | |||
end | |||
def root_project | |||
@root_project ||= | |||
begin | |||
@@ -141,17 +145,6 @@ class Project < ActiveRecord::Base | |||
links.reject { |l| l.custom? } | |||
end | |||
def chart_measures(metric_id) | |||
sql = Project.send(:sanitize_sql, ['select s.created_at as created_at, m.value as value ' + | |||
' from project_measures m, snapshots s ' + | |||
' where s.id=m.snapshot_id and ' + | |||
" s.status='%s' and " + | |||
' s.component_uuid=%s and m.metric_id=%s ', 'P', self.uuid, metric_id]) + | |||
' and m.person_id IS NULL' + | |||
' order by s.created_at' | |||
create_chart_measures(Project.connection.select_all(sql), 'created_at', 'value') | |||
end | |||
def <=>(other) | |||
kee <=> other.kee | |||
end | |||
@@ -184,25 +177,6 @@ class Project < ActiveRecord::Base | |||
private | |||
def create_chart_measures(results, date_column_name, value_column_name) | |||
chart_measures = [] | |||
if results and results.first != nil | |||
# :sanitize_sql is protected so its behaviour cannot be predicted exactly, | |||
# the jdbc active record impl adapter returns a db typed objects array | |||
# when regular active record impl return string typed objects | |||
if results.first[date_column_name].class == Time | |||
results.each do |hash| | |||
chart_measures << ChartMeasure.new(hash[date_column_name], hash[value_column_name]) | |||
end | |||
else | |||
results.each do |hash| | |||
chart_measures << ChartMeasure.new(Time.parse(hash[date_column_name]), hash[value_column_name].to_d) | |||
end | |||
end | |||
end | |||
chart_measures | |||
end | |||
def parent_module(current_module) | |||
current_module.root.uuid = current_module.uuid ? current_module : parent_module(current_module.root) | |||
end |
@@ -65,29 +65,6 @@ class Snapshot < ActiveRecord::Base | |||
Time.at(date_in_long/1000) if date_in_long | |||
end | |||
def self.for_timemachine_matrix(resource) | |||
# http://jira.sonarsource.com/browse/SONAR-1850 | |||
# Conditions on scope and qualifier are required to exclude library snapshots. | |||
# Use-case : | |||
# 1. project A 2.0 is analyzed -> new snapshot A with qualifier TRK | |||
# 2. project B, which depends on A 1.0, is analyzed -> new snapshot A 1.0 with qualifier LIB. | |||
# 3. project A has 2 snapshots : the first one with qualifier=TRK has measures, the second one with qualifier LIB has no measures. Its version must not be used in time machine | |||
# That's why the 2 following SQL requests check the qualifiers (and optionally scopes, just to be sure) | |||
snapshots=Snapshot.find(:all, :conditions => ["snapshots.component_uuid=? AND events.analysis_uuid=snapshots.uuid AND snapshots.status=? AND snapshots.scope=? AND snapshots.qualifier=?", resource.uuid, STATUS_PROCESSED, resource.scope, resource.qualifier], | |||
:include => 'events', | |||
:order => 'snapshots.created_at ASC') | |||
snapshots<<resource.last_snapshot if snapshots.empty? | |||
snapshots=snapshots[-5, 5] if snapshots.size>=5 | |||
snapshots.insert(0, Snapshot.find(:first, | |||
:conditions => ["component_uuid=? AND status=? AND scope=? AND qualifier=?", resource.uuid, STATUS_PROCESSED, resource.scope, resource.qualifier], | |||
:include => 'project', :order => 'snapshots.created_at ASC', :limit => 1)) | |||
snapshots.compact.uniq | |||
end | |||
def self.for_timemachine_widget(resource, number_of_columns, options={}) | |||
if number_of_columns == 1 | |||
# Display only the latest snapshot | |||
@@ -95,13 +72,13 @@ class Snapshot < ActiveRecord::Base | |||
end | |||
# Get 1rst & latests snapshots of the period | |||
snapshot_conditions = ["snapshots.component_uuid=? AND snapshots.status=? AND snapshots.scope=? AND snapshots.qualifier=?", resource.uuid, STATUS_PROCESSED, resource.scope, resource.qualifier] | |||
snapshot_conditions = ["snapshots.component_uuid=? AND snapshots.status=?", resource.project_uuid, STATUS_PROCESSED] | |||
if options[:from] | |||
snapshot_conditions[0] += " AND snapshots.created_at>=?" | |||
snapshot_conditions << options[:from].to_i * 1000 | |||
end | |||
first_snapshot=Snapshot.find(:first, :conditions => snapshot_conditions, :order => 'snapshots.created_at ASC') | |||
last_snapshot=resource.last_snapshot | |||
first_snapshot = Snapshot.find(:first, :conditions => snapshot_conditions, :order => 'snapshots.created_at ASC') | |||
last_snapshot = resource.last_analysis | |||
if first_snapshot==last_snapshot | |||
return [last_snapshot] |
@@ -22,15 +22,15 @@ class Sonar::TimemachineRow | |||
def initialize(metric) | |||
@metric=metric | |||
@measure_by_sid={} | |||
@measures_by_analysis_uuid = {} | |||
end | |||
def add_measure(measure) | |||
@measure_by_sid[measure.snapshot_id]=measure | |||
@measures_by_analysis_uuid[measure.analysis_uuid] = measure | |||
end | |||
def measure(snapshot) | |||
@measure_by_sid[snapshot.id] | |||
def measure(analysis) | |||
@measures_by_analysis_uuid[analysis.uuid] | |||
end | |||
def domain | |||
@@ -41,14 +41,17 @@ class Sonar::TimemachineRow | |||
(self.domain <=> other.domain).nonzero? || (self.metric.short_name <=> other.metric.short_name) | |||
end | |||
def sparkline | |||
if metric.numeric? && @measure_by_sid.size > 1 | |||
def sparkline(analyses) | |||
if metric.numeric? && @measures_by_analysis_uuid.size > 1 | |||
x = [] | |||
y = [] | |||
@measure_by_sid.values.each do |measure| | |||
# date.to_f does not works under oracle | |||
x << measure.snapshot.created_at.to_s(:number) | |||
y << (measure.value.nil? ? 0 : measure.value) | |||
analyses.each do |analysis| | |||
m = measure(analysis) | |||
if m | |||
# date.to_f does not works under oracle | |||
x << analysis.created_at.to_s(:number) | |||
y << (m.value.nil? ? 0 : m.value) | |||
end | |||
end | |||
[x, y] | |||
else |
@@ -19,12 +19,12 @@ | |||
# | |||
class TrendsChart | |||
def self.time_machine_measures(resource, metric_ids, options={}) | |||
def self.time_machine_measures(component, metric_ids, options={}) | |||
unless metric_ids.empty? | |||
sql= "select s.created_at as created_at, m.value as value, m.metric_id as metric_id, s.id as sid " + | |||
" from project_measures m LEFT OUTER JOIN snapshots s ON s.id=m.snapshot_id " + | |||
sql= "select s.created_at as created_at, m.value as value, m.metric_id as metric_id, s.uuid as analysis_uuid " + | |||
" from project_measures m LEFT OUTER JOIN snapshots s ON s.uuid = m.analysis_uuid " + | |||
" where s.status=? " + | |||
" and s.component_uuid=? " + | |||
" and m.component_uuid=? " + | |||
" and m.metric_id in (?) " + | |||
" and m.person_id is null" | |||
if (options[:from]) | |||
@@ -34,7 +34,7 @@ class TrendsChart | |||
sql += ' and s.created_at<=?' | |||
end | |||
sql += ' order by s.created_at ASC' | |||
conditions=[sql, Snapshot::STATUS_PROCESSED, resource.uuid, metric_ids] | |||
conditions=[sql, Snapshot::STATUS_PROCESSED, component.uuid, metric_ids] | |||
if (options[:from]) | |||
conditions<<options[:from].to_i*1000 | |||
end |
@@ -1,6 +1,6 @@ | |||
<div id="body" class="page"> | |||
<% if @snapshot %> | |||
<div class="print"><h2><%= h @snapshot.project.name(true) %></h2></div> | |||
<% if @resource %> | |||
<div class="print"><h2><%= h @resource.name(true) %></h2></div> | |||
<% end %> | |||
<div class="hidden" id="messages-panel"> | |||
<div class="alert alert-danger hidden" id="error"> |
@@ -1,6 +1,6 @@ | |||
<div class="page"> | |||
<% | |||
if !@snapshot || @snapshot.root? | |||
if !@snapshot || @project.root? | |||
resource_qualifier = message('qualifier.' + @project.qualifier) | |||
delete_resource_message = message('project_deletion.page', :params => resource_qualifier) | |||
%> |
@@ -15,7 +15,7 @@ | |||
<code><%= h @project.key -%></code> | |||
</div> | |||
<% elsif @snapshot.root? %> | |||
<% elsif @project.root? %> | |||
<table id="project-history" class="data" style="width:1%"> | |||
<thead> |
@@ -21,9 +21,9 @@ | |||
# | |||
# SonarQube 6.0 | |||
# | |||
class FixProjectUuidOfDevelopers < ActiveRecord::Migration | |||
class FixProjectUuidOfDeveloperProjects < ActiveRecord::Migration | |||
def self.up | |||
execute_java_migration('org.sonar.db.version.v60.FixProjectUuidOfDevelopers') | |||
execute_java_migration('org.sonar.db.version.v60.FixProjectUuidOfDeveloperProjects') | |||
end | |||
end |
@@ -45,9 +45,9 @@ public class MeasureQuery { | |||
} | |||
private MeasureQuery(List<String> componentUuids, | |||
@Nullable Collection<Integer> metricIds, | |||
@Nullable Collection<String> metricKeys, | |||
@Nullable Long personId) { | |||
@Nullable Collection<Integer> metricIds, | |||
@Nullable Collection<String> metricKeys, | |||
@Nullable Long personId) { | |||
checkState(componentUuids != null, "Component UUIDs must be set"); | |||
checkState(metricIds == null || metricKeys == null, "Metric IDs and keys must not be set both"); | |||
this.componentUuids = componentUuids; | |||
@@ -96,6 +96,7 @@ public class MeasureQuery { | |||
private Long personId; | |||
private Builder() { | |||
// see MeasureQuery#builder() | |||
} | |||
public Builder setComponentUuids(List<String> componentUuids) { |
@@ -39,7 +39,7 @@ public class PastMeasureDto { | |||
return value; | |||
} | |||
public PastMeasureDto setValue(@Nullable Double value) { | |||
PastMeasureDto setValue(@Nullable Double value) { | |||
this.value = value; | |||
return this; | |||
} | |||
@@ -52,7 +52,7 @@ public class PastMeasureDto { | |||
return metricId; | |||
} | |||
public PastMeasureDto setMetricId(int i) { | |||
PastMeasureDto setMetricId(int i) { | |||
this.metricId = i; | |||
return this; | |||
} | |||
@@ -62,7 +62,7 @@ public class PastMeasureDto { | |||
return personId; | |||
} | |||
public PastMeasureDto setPersonId(@Nullable Long l) { | |||
PastMeasureDto setPersonId(@Nullable Long l) { | |||
this.personId = l; | |||
return this; | |||
} |
@@ -115,7 +115,7 @@ import org.sonar.db.version.v60.DropSnapshotIdColumnFromCeActivity; | |||
import org.sonar.db.version.v60.DropSnapshotIdColumnFromEvents; | |||
import org.sonar.db.version.v60.DropSnapshotIdColumnsFromDuplicationsIndex; | |||
import org.sonar.db.version.v60.DropUnusedMeasuresColumns; | |||
import org.sonar.db.version.v60.FixProjectUuidOfDevelopers; | |||
import org.sonar.db.version.v60.FixProjectUuidOfDeveloperProjects; | |||
import org.sonar.db.version.v60.MakeAnalysisUuidNotNullOnDuplicationsIndex; | |||
import org.sonar.db.version.v60.MakeAnalysisUuidNotNullOnEvents; | |||
import org.sonar.db.version.v60.MakeAnalysisUuidNotNullOnMeasures; | |||
@@ -288,7 +288,7 @@ public class MigrationStepModule extends Module { | |||
MakeAnalysisUuidNotNullOnEvents.class, | |||
DropSnapshotIdColumnFromEvents.class, | |||
FixProjectUuidOfDevelopers.class, | |||
FixProjectUuidOfDeveloperProjects.class, | |||
// PROJECTS.UUID_PATH | |||
AddUuidPathColumnToProjects.class, | |||
PopulateUuidPathColumnOnProjects.class, |
@@ -26,22 +26,22 @@ import org.sonar.db.version.MassUpdate; | |||
import org.sonar.db.version.Select; | |||
import org.sonar.db.version.SqlStatement; | |||
public class FixProjectUuidOfDevelopers extends BaseDataChange { | |||
public class FixProjectUuidOfDeveloperProjects extends BaseDataChange { | |||
public FixProjectUuidOfDevelopers(Database db) { | |||
public FixProjectUuidOfDeveloperProjects(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select("select distinct developer_uuid from projects where qualifier = 'DEV_PRJ'"); | |||
massUpdate.update("update projects set project_uuid = developer_uuid where developer_uuid = ? and qualifier = 'DEV_PRJ'"); | |||
massUpdate.select("select distinct developer_uuid from projects where qualifier = 'DEV_PRJ' and project_uuid != developer_uuid"); | |||
massUpdate.update("update projects set project_uuid = developer_uuid where developer_uuid = ? and qualifier = 'DEV_PRJ' and project_uuid != developer_uuid"); | |||
massUpdate.rowPluralName("developers in project"); | |||
massUpdate.execute((row, update) -> handleComponent(row, update)); | |||
massUpdate.execute(FixProjectUuidOfDeveloperProjects::handleComponent); | |||
} | |||
private boolean handleComponent(Select.Row row, SqlStatement update) throws SQLException { | |||
private static boolean handleComponent(Select.Row row, SqlStatement update) throws SQLException { | |||
String developerUuid = row.getString(1); | |||
update.setString(1, developerUuid); | |||
@@ -29,7 +29,7 @@ import org.sonar.db.DbTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class FixProjectUuidOfDevelopersTest { | |||
public class FixProjectUuidOfDeveloperProjectsTest { | |||
private static final String TABLE_PROJECTS = "projects"; | |||
private static final String PROJECT_UUID = "U1"; | |||
@@ -39,10 +39,10 @@ public class FixProjectUuidOfDevelopersTest { | |||
private static final String DEV2_IN_PROJECT_UUID = "U5"; | |||
@Rule | |||
public DbTester db = DbTester.createForSchema(System2.INSTANCE, FixProjectUuidOfDevelopersTest.class, | |||
public DbTester db = DbTester.createForSchema(System2.INSTANCE, FixProjectUuidOfDeveloperProjectsTest.class, | |||
"in_progress_projects.sql"); | |||
private FixProjectUuidOfDevelopers underTest = new FixProjectUuidOfDevelopers(db.database()); | |||
private FixProjectUuidOfDeveloperProjects underTest = new FixProjectUuidOfDeveloperProjects(db.database()); | |||
@Test | |||
public void migration_has_no_effect_on_empty_tables() throws SQLException { |