diff --git a/Gemfile b/Gemfile
index a8131fb3f..e0f9ed2d1 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,7 +6,11 @@ unless RUBY_PLATFORM =~ /w32/
gem 'iconv'
end
-gem 'certified'
+gem 'net-ssh'
+gem 'jenkins_api_client'
+gem 'nokogiri'
+
+# gem 'certified'
gem 'wechat',path: 'lib/wechat'
gem 'grack', path:'lib/grack'
diff --git a/app/assets/javascripts/quality_analyses.js.coffee b/app/assets/javascripts/quality_analyses.js.coffee
new file mode 100644
index 000000000..761567942
--- /dev/null
+++ b/app/assets/javascripts/quality_analyses.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
diff --git a/app/assets/stylesheets/quality_analyses.css.scss b/app/assets/stylesheets/quality_analyses.css.scss
new file mode 100644
index 000000000..9404eb70f
--- /dev/null
+++ b/app/assets/stylesheets/quality_analyses.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the QualityAnalyses controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index c8b272480..c216491b1 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -393,7 +393,7 @@ class ProjectsController < ApplicationController
unless @project.gpid.nil?
g = Gitlab.client
@gitlab_branches = g.branches(@project.gpid)
- @branch_names = g.branches(@project.gpid).map{|b| b.name}
+ @branch_names = @gitlab_branches.map{|b| b.name}
@gitlab_default_branch = g.project(@project.gpid).default_branch
end
end
@@ -645,7 +645,7 @@ class ProjectsController < ApplicationController
params[:project][:is_public] ? @project.is_public = 1 : @project.is_public = 0
params[:project][:hidden_repo] ? @project.hidden_repo = 1 : @project.hidden_repo = 0
# 更新公开私有时同步gitlab公开私有
- unless @project.gpid.nil?
+ if !@project.gpid.nil? && @project.is_public != (params[:project][:is_public] == "on" ? true : false)
g = Gitlab.client
params[:project][:is_public] ? g.edit_project(@project.gpid, 20, params[:branch]) : g.edit_project(@project.gpid, 0, params[:branch])
end
diff --git a/app/controllers/quality_analysis_controller.rb b/app/controllers/quality_analysis_controller.rb
new file mode 100644
index 000000000..83e5960b9
--- /dev/null
+++ b/app/controllers/quality_analysis_controller.rb
@@ -0,0 +1,99 @@
+class QualityAnalysisController < ApplicationController
+ before_filter :find_project_by_project_id#, :except => [:getattachtype]
+ before_filter :authorize
+ layout "base_projects"
+ include ApplicationHelper
+ require 'jenkins_api_client'
+ require 'nokogiri'
+ require 'json'
+ require 'open-uri'
+
+ def show
+
+ end
+
+ def create
+ gitlab_address = Redmine::Configuration['gitlab_address']
+ jenkins_address = Redmine::Configuration['jenkins_address']
+ @client = JenkinsApi::Client.new(:server_url => jenkins_address,
+ :username => "temp",
+ :password => '123123')
+ #@client.exists?(job_name)
+ @g = Gitlab.client
+ user_name = User.find(params[:user_id]).try(:login)
+ branch = params[:branch].nil? ? "master" : params[:branch]
+ language = params[:language]
+ path = params[:path]
+ identifier = params[:identifier]
+ qa = QualityAnalysis.where(:project_id => @project.id, :author_login => user_name).first
+ version = qa.nil? ? 1 : qa.sonar_version + 1
+ properties = "sonar.projectKey=#{user_name}:#{identifier}
+ sonar.projectName=#{user_name}:#{identifier}
+ sonar.projectVersion=#{version}
+ sonar.sources=#{path}
+ sonar.language=#{language.downcase}
+ sonar.sourceEncoding=utf-8"
+ git_url = gitlab_address.to_s+"/"+@project.owner.to_s+"/"+ identifier + "."+"git"
+
+ # # # modify config
+ @doc = Nokogiri::XML(File.open(File.join(Rails.root, 'tmp', 'config.xml')))
+ @doc.at_xpath("//hudson.plugins.git.UserRemoteConfig/url").content = git_url
+ @doc.at_xpath("//hudson.plugins.git.BranchSpec/name").content = "*/#{branch}"
+ @doc.at_xpath("//hudson.plugins.sonar.SonarRunnerBuilder/properties").content = properties #sonar-properties
+ #
+ # replace config.xml of jenkins
+ @client = @client.job.create("#{user_name}_#{identifier}", @doc.to_xml)
+ # relace gitlab hook
+ # genkins address
+ @g.add_project_hook(@project.gpid, jenkins_address + "/project/#{user_name}_#{identifier}")
+ if qa.nil?
+ QualityAnalysis.create(:project_id => @project.id, :author_login => user_name, :rep_identifier => identifier, :sonar_version => version, :path => path, :branch => branch, :language => language)
+
+ else
+ qa.update_attribute(:sonar_version, version)
+ end
+ end
+
+ def index
+ @sonar_address = Redmine::Configuration['sonar_address']
+ # if params[:resource_id].nil?
+ # @name_flag = true
+ # @quality_analyses = QualityAnalysis.where(:project_id => @project.id)
+ # # @quality_analyses.map {|qa| qa.}
+ # # if @quality_analyses.count > 0
+ # # @quality_analyses.each do |qa|
+ # # ["Hjqreturn:cc_rep", "Hjqreturn:putong", "Hjqreturn:sonar_rep2", "shitou:sonar_rep"]
+ # #
+ # # end
+ # # end
+ # # projects_date = open(@sonar_address + "/api/projects/index").read
+ # # arr = JSON.parse(projects_date).map {|m| m["nm"]}
+ # # arr.map
+ # else
+ qa = QualityAnalysis.where(:project_id => @project.id).first
+ @resource_id = qa.author_login+":"+qa.rep_identifier
+ @name_flag = false
+ complexity_date = open(@sonar_address + "/api/resources/index?resource=#{@resource_id}&depth=0&metrics=sqale_rating,function_complexity,duplicated_lines_density,comment_lines_density,sqale_index,lines,file_line,files,functions,classes,directories").read
+ @complexity =JSON.parse(complexity_date).first
+ issue_date = open(@sonar_address + "/api/resources/index?resource=#{@resource_id}&depth=0&metrics=blocker_violations,critical_violations,major_violations,minor_violations,info_violations,violations").read
+ @sonar_issues = JSON.parse(issue_date).first
+ # end
+ end
+
+ # Find project of id params[:project_id]
+ def find_project_by_project_id
+ @project = Project.find(params[:project_id])
+ rescue ActiveRecord::RecordNotFound
+ render_404
+ end
+
+ # Authorize the user for the requested action
+ def authorize(ctrl = params[:controller], action = params[:action], global = false)
+ unless @project.archived? && @project.gpid.nil?
+ true
+ else
+ render_403 :message => :notice_not_authorized_archived_project
+ end
+ end
+
+end
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index 9e785c562..cbb5b2f69 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -30,11 +30,13 @@ class RepositoriesController < ApplicationController
menu_item :settings, :only => [:new, :create, :edit, :update, :destroy, :committers]
default_search_scope :changesets
- before_filter :find_project_by_project_id, :only => [:new, :create, :newrepo, :stats]
+ before_filter :find_project_by_project_id, :only => [:new, :create, :newrepo, :stats, :quality_analysis]
before_filter :find_repository, :only => [:edit, :update, :destroy, :committers]
before_filter :find_project_repository, :except => [:new, :create, :newcreate, :edit, :update, :destroy, :committers, :newrepo, :to_gitlab, :forked, :project_archive]
before_filter :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue]
- before_filter :authorize , :except => [:newrepo,:newcreate,:fork, :to_gitlab, :forked, :commit_diff, :project_archive]
+ before_filter :authorize , :except => [:newrepo,:newcreate,:fork, :to_gitlab, :forked, :commit_diff, :project_archive, :quality_analysis]
+ # 链接gitlab
+ before_filter :connect_gitlab, :only => [:quality_analysis]
accept_rss_auth :revisions
# hidden repositories filter // 隐藏代码过滤器
before_filter :check_hidden_repo, :only => [:show, :stats, :revisions, :revision, :diff ]
@@ -43,6 +45,7 @@ class RepositoriesController < ApplicationController
helper :project_score
#@root_path = RepositoriesHelper::ROOT_PATH
$g=Gitlab.client
+ require 'net/ssh'
rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
def new
@@ -306,6 +309,37 @@ update
end
end
+ def quality_analysis
+ gitlab_branches = @g.branches(@project.gpid)
+ @branch_names = gitlab_branches.map{|b| b.name}
+ @gitlab_default_branch = @g.project(@project.gpid).default_branch
+ # language = params[:language]
+ # branch = params[:branch]
+ # path = params[:path]
+ # user_name = User.find(@project.user_id).try(:login)
+ # rep_name = params[:repository_id]
+ # host = "192.168.0.200"
+ # port = "1125"
+ # username = "git"
+ # password = "123123"
+ # server_cmd1 = "sh gitclone.sh" + " " + user_name + " " + rep_name
+ # # 连接到远程主机 foobar
+ # ssh = Net::SSH.start(host, username, :port => port, :password => password) do |ssh|
+ # result = ssh.exec!(server_cmd1)
+ # path = "/home/git/repo/" + user_name + "/" + rep_name
+ # # sonar 分析
+ # # server_cmd2
+ # # 删除clone的版本库
+ # # server_cmd3
+ # end
+ respond_to do |format|
+ format.js
+ format.html{
+ render :layout => "base_projects"
+ }
+ end
+ end
+
def destroy
DestroyRepositoryTask.new.destroy(User.current.id, @repository.id)
@repository.hidden = true
@@ -615,6 +649,14 @@ update
project.project_score.update_attribute(:commit_time, date.created_at)
end
+ # 链接gitlab
+ def connect_gitlab
+ @g = Gitlab.client
+ unless @project.gpid.nil?
+ @g_project = @g.project(@project.gpid)
+ end
+ end
+
def find_repository
@repository = Repository.find(params[:id])
@project = @repository.project
diff --git a/app/helpers/quality_analysis_helper.rb b/app/helpers/quality_analysis_helper.rb
new file mode 100644
index 000000000..e13882f6f
--- /dev/null
+++ b/app/helpers/quality_analysis_helper.rb
@@ -0,0 +1,96 @@
+module QualityAnalysisHelper
+
+ def sqale_rating_status val
+ arr = []
+ if val.to_i > 0 && val.to_i < 5
+ arr << "很好"
+ arr << "b_green2"
+ elsif val.to_i > 5 && val.to_i < 10
+ arr << "较好"
+ arr << "b_slow_yellow"
+ elsif val.to_i > 10 && val.to_i < 20
+ arr << "中等"
+ arr << "b_yellow"
+ elsif val.to_i > 20 && val.to_i < 50
+ arr << "较差"
+ arr << "b_slow_red"
+ elsif val.to_i > 20
+ arr << "很差"
+ arr << "b_red"
+ end
+ end
+
+ def complexity_status val
+ arr = []
+ if val.to_i < 10
+ arr << "良好"
+ arr << "b_green2"
+ elsif val.to_i > 10 && val.to_i < 15
+ arr << "较高"
+ arr << "b_yellow"
+ elsif val.to_i > 15
+ arr << "很高"
+ arr << "b_red"
+ end
+ end
+
+ def duplicated_lines_density_status val
+ arr = []
+ if val.to_i < 30
+ arr << "良好"
+ arr << "b_green2"
+ elsif val.to_i > 30 && val.to_i < 50
+ arr << "较高"
+ arr << "b_yellow"
+ elsif val.to_i > 50
+ arr << "很高"
+ arr << "b_red"
+ end
+ end
+
+ def comment_lines_density_status val
+ arr = []
+ if val.to_i < 20
+ arr << "较低"
+ arr << "b_yellow"
+ elsif val.to_i > 20 && val.to_i < 50
+ arr << "正常"
+ arr << "b_green2"
+ elsif val.to_i > 50
+ arr << "较高"
+ arr << "b_red"
+ end
+ end
+
+ def score_sqale_rating val
+ if val.to_i > 0 && val.to_i < 5
+ "5"
+ elsif val.to_i > 5 && val.to_i < 10
+ "4"
+ elsif val.to_i > 10 && val.to_i < 20
+ "3"
+ elsif val.to_i > 20 && val.to_i < 50
+ "2"
+ elsif val.to_i > 20
+ "1"
+ end
+ end
+
+ def lines_scale val
+ if val.to_i < 5000
+ "小型"
+ elsif val.to_i >5000 && val.to_i < 50000
+ "中型"
+ else
+ "大型"
+ end
+ end
+
+ #统计答题百分比,统计结果保留两位小数
+ def statistics_result_percentage(e, t)
+ e = e.to_f
+ t = t.to_f
+ t == 0 ? 0 : format("%.2f", e*100/t)
+ end
+
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index ceec0e182..d1da50469 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -155,9 +155,9 @@ class Project < ActiveRecord::Base
#ActiveModel::Dirty 这里有一个changed方法。对任何对象都可以用
after_save :update_inherited_members, :if => Proc.new {|project| project.inherit_members_changed?}
# 创建project之后默认创建一个board,之后的board去掉了board的概念
- after_create :create_board_sync,:acts_as_forge_activities,:create_project_ealasticsearch_index
+ after_create :create_board_sync,:acts_as_forge_activities
before_destroy :delete_all_members,:delete_project_ealasticsearch_index
- after_update :update_project_ealasticsearch_index
+ # after_update :update_project_ealasticsearch_index
def remove_references_before_destroy
return if self.id.nil?
Watcher.delete_all ['watchable_id = ?', id]
diff --git a/app/models/quality_analysis.rb b/app/models/quality_analysis.rb
new file mode 100644
index 000000000..229be9826
--- /dev/null
+++ b/app/models/quality_analysis.rb
@@ -0,0 +1,7 @@
+class QualityAnalysis < ActiveRecord::Base
+ attr_accessible :author_login, :project_id, :rep_identifier, :sonar_version, :branch, :path, :rep_identifier, :language
+
+ def user_rep_name
+ self.author_login+":"+self.rep_identifier
+ end
+end
diff --git a/app/models/sonar_analysis.rb b/app/models/sonar_analysis.rb
new file mode 100644
index 000000000..0bb2089de
--- /dev/null
+++ b/app/models/sonar_analysis.rb
@@ -0,0 +1,3 @@
+class SonarAnalysis < ActiveRecord::Base
+ attr_accessible :author_login, :project_id, :rep_identifier
+end
diff --git a/app/views/quality_analysis/_hightchars.html.erb b/app/views/quality_analysis/_hightchars.html.erb
new file mode 100644
index 000000000..fb60eaed3
--- /dev/null
+++ b/app/views/quality_analysis/_hightchars.html.erb
@@ -0,0 +1,483 @@
+
\ No newline at end of file
diff --git a/app/views/quality_analysis/_result_list.html.erb b/app/views/quality_analysis/_result_list.html.erb
new file mode 100644
index 000000000..507ded0fe
--- /dev/null
+++ b/app/views/quality_analysis/_result_list.html.erb
@@ -0,0 +1,25 @@
+
+
分析结果
+
+
+ - 名称
+ - 版本
+ - 分支
+ - 语言
+ - 时间
+
+
+<% if @quality_analyses.count >0 %>
+ <% @quality_analyses.each do |qa| %>
+
+ - <%=link_to "#{qa.author_login}:#{qa.rep_identifier}", project_quality_analysis_path(:resource_id => qa.author_login+":"+qa.rep_identifier, :branch => qa.branch.nil? ? "master" : qa.branch), :class => "analysis-result-name fl fontBlue2" %>
+ - 1.0
+ - <%= qa.branch %>
+ - <%= qa.language %>
+ - <%= format_time(qa.created_at) %>
+
+
+ <% end %>
+<% end %>
+
+
diff --git a/app/views/quality_analysis/_show.html.erb b/app/views/quality_analysis/_show.html.erb
new file mode 100644
index 000000000..8f1cb8443
--- /dev/null
+++ b/app/views/quality_analysis/_show.html.erb
@@ -0,0 +1,114 @@
+<%= javascript_include_tag 'highcharts','highcharts-more' %>
+ <%= render :partial => "hightchars" %>
+
+
质量分析
+
+当前分支:<%= params[:branch] %>
+
+ 项目代码质量分析报告
+ 概要信息
+
+
+
+
+
质量等级
+
<%= @complexity["msr"][9]["frmt_val"] %> borderRadius"><%= sqale_rating_status(@complexity["msr"][9]["val"])[0] %>
+
+
+
+
复杂度
+
<%= @complexity["msr"][6]["val"] %> borderRadius"><%= complexity_status(@complexity["msr"][6]["val"])[0] %>
+
+
+
+
+
+
代码重复度
+
<%= @complexity["msr"][7]["frmt_val"] %> borderRadius"><%= duplicated_lines_density_status(@complexity["msr"][7]["val"])[0] %>
+
+
+
+
注释率
+
<%= @complexity["msr"][5]["frmt_val"] %>
+
+
+
+ 质量等级<%= score_sqale_rating(@complexity["msr"][9]["val"]) %>/5分可定性评价为:质量<%= sqale_rating_status(@complexity["msr"][9]["val"])[0] %>
+
+
技术债务<%= @complexity["msr"][8]["frmt_val"] %>查看详情
+
+
+
阻断<%= @sonar_issues["msr"][1]["frmt_val"] %>%;">
+
严重<%= @sonar_issues["msr"][2]["frmt_val"] %>%;">
+
主要<%= @sonar_issues["msr"][3]["frmt_val"] %>%;">
+
次要<%= @sonar_issues["msr"][4]["frmt_val"] %>%;">
+
信息<%= @sonar_issues["msr"][5]["frmt_val"] %>%;">
+
+
+ 代码规模可定性评价为:<%= lines_scale(@complexity["msr"][0]["frmt_val"]) %>
+
+
+
代码行数
+
<%= @complexity["msr"][0]["frmt_val"] %>
+
+
+
文件
+
<%= @complexity["msr"][2]["frmt_val"] %>
+
+
+
目录
+
<%= @complexity["msr"][3]["frmt_val"] %>
+
+
+
类
+
<%= @complexity["msr"][1]["frmt_val"] %>
+
+
+
方法
+
<%= @complexity["msr"][4]["frmt_val"] %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/views/quality_analysis/index.html.erb b/app/views/quality_analysis/index.html.erb
new file mode 100644
index 000000000..9b06e6483
--- /dev/null
+++ b/app/views/quality_analysis/index.html.erb
@@ -0,0 +1,6 @@
+<% if @name_flag %>
+ <%= render :partial => "result_list" %>
+<% else %>
+ <%= render "show" %>
+<% end %>
+
diff --git a/app/views/quality_analysis/show.html.erb b/app/views/quality_analysis/show.html.erb
new file mode 100644
index 000000000..e69de29bb
diff --git a/app/views/repositories/_quality_analysis.html.erb b/app/views/repositories/_quality_analysis.html.erb
new file mode 100644
index 000000000..f9726fb9b
--- /dev/null
+++ b/app/views/repositories/_quality_analysis.html.erb
@@ -0,0 +1,23 @@
+代码质量分析
+
+ <%= form_tag( url_for(:controller => 'quality_analysis', :action => 'create', :project_id => @project.id, :user_id => User.current.id, :identifier => @repository.identifier), :remote => true, :id => 'quality_analyses_form') do %>
+
+ <% end %>
+
diff --git a/app/views/repositories/quality_analyses.html.erb b/app/views/repositories/quality_analyses.html.erb
new file mode 100644
index 000000000..69dae2629
--- /dev/null
+++ b/app/views/repositories/quality_analyses.html.erb
@@ -0,0 +1,76 @@
+<%= javascript_include_tag 'highcharts','highcharts-more' %>
+
+
<%= l(:label_quality_analyses) %>
+
+
+
+ <%#= render :partial => 'navigation' %>
+
+
+
+
+
+
+
+
+
+
+<%= link_to l(:button_back), :action => 'show', :id => @project %>
+<% html_title(l(:label_repository), l(:label_statistics)) -%>
\ No newline at end of file
diff --git a/app/views/repositories/quality_analysis.js.erb b/app/views/repositories/quality_analysis.js.erb
new file mode 100644
index 000000000..bafe28cdf
--- /dev/null
+++ b/app/views/repositories/quality_analysis.js.erb
@@ -0,0 +1,8 @@
+$('#ajax-modal').html('<%= escape_javascript( render :partial => 'repositories/quality_analysis', :locals => {}) %>');
+showModal('ajax-modal', '615px');
+$('#ajax-modal').siblings().remove();
+$('#ajax-modal').before("");
+$('#ajax-modal').parent().css("top","20%").css("left","32%").css("border","3px solid #269ac9");
+$('#ajax-modal').parent().addClass("popbox_polls");
+
+
diff --git a/app/views/repositories/show.html.erb b/app/views/repositories/show.html.erb
index 43be57760..124e3ef4d 100644
--- a/app/views/repositories/show.html.erb
+++ b/app/views/repositories/show.html.erb
@@ -2,7 +2,13 @@
<%= render :partial => 'breadcrumbs', :locals => {:path => @path, :kind => 'dir', :revision => @rev} %>
ZIP下载
-
+ <% if is_project_manager?(User.current, @project.id) && QualityAnalysis.where(:project_id => @project.id).first.nil? %>
+ <%# if User.current.member_of?(@project) %>
+ <%= link_to "质量分析", quality_analysis_path(:id => @project.id), :remote => true, :class => "btn_zipdown fr" %>
+ <%# end %>
+ <% else %>
+ <%= link_to "质量分析", project_quality_analysis_path(:project_id => @project.id, :resource_id => @proje), :class => "btn_zipdown fr" %>
+ <% end %>
<% if @entries.nil? %>
@@ -45,7 +51,7 @@
<%= @changesets_latest_coimmit.message %>
<% else %>
-
<%=@changesets_latest_coimmit.author_email %>
+ <%=@changesets_latest_coimmit.author_email %>
提交于<%= time_tag(@changesets_latest_coimmit.created_at) %>:
<%= @changesets_latest_coimmit.message %>
@@ -57,7 +63,6 @@
<%=link_to @changesets_all_count, {:action => 'changes', :path => to_path_param(@path), :id => @project, :repository_id => @repository.identifier_param, :rev => @rev,:page=>1 ,:commit_count =>"#{@changesets_all_count}"} %> 提交
-
<% end %>
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 033f12ad2..98d02cdb6 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -602,6 +602,7 @@ en:
label_time_tracking: Time tracking
label_change_plural: Changes
label_statistics: Statistics
+ label_quality_analyses: Quality Analyses
label_commits_per_month: Commits per month
label_commits_per_author: Commits per author
label_diff: diff
diff --git a/config/locales/zh.yml b/config/locales/zh.yml
index 5d9b3c2a1..3dbd2e8ef 100644
--- a/config/locales/zh.yml
+++ b/config/locales/zh.yml
@@ -732,6 +732,7 @@ zh:
label_time_tracking: 时间跟踪
label_change_plural: 变更
label_statistics: 统计
+ label_quality_analyses: 质量分析
label_commits_per_month: 每月提交次数
label_commits_per_author: 每用户提交次数
diff --git a/config/routes.rb b/config/routes.rb
index bc2be6a30..a0ab9b783 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -785,6 +785,13 @@ RedmineApp::Application.routes.draw do
end
end
+ resources :quality_analysis, :only => [:index, :new, :create] do
+ collection do
+ end
+ member do
+
+ end
+ end
# resources :files, :only => [:index, :new, :create] do
# member do
# match "quote_resource_show_project",:via => [:get]
@@ -905,6 +912,7 @@ RedmineApp::Application.routes.draw do
# repositories routes
get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats', :as => "stats_repository_project"
+ get 'projects/:id/repository/:repository_id/quality_analysis', :to => 'repositories#quality_analysis', :as => "quality_analysis"
get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph'
get 'projects/:id/repository/:repository_id/changes(/*path(.:ext))', :to => 'repositories#changes'
@@ -923,6 +931,7 @@ RedmineApp::Application.routes.draw do
}
get 'projects/:id/repository/statistics', :to => 'repositories#stats'
+
get 'projects/:id/repository/graph', :to => 'repositories#graph'
get 'projects/:id/repository/changes(/*path(.:ext))', :to => 'repositories#changes'
diff --git a/db/migrate/20160622033322_create_quality_analyses.rb b/db/migrate/20160622033322_create_quality_analyses.rb
new file mode 100644
index 000000000..6316d5764
--- /dev/null
+++ b/db/migrate/20160622033322_create_quality_analyses.rb
@@ -0,0 +1,11 @@
+class CreateQualityAnalyses < ActiveRecord::Migration
+ def change
+ create_table :quality_analyses do |t|
+ t.integer :project_id
+ t.string :author_login
+ t.string :rep_identifier
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20160622074138_add_jk_version_to_quality_analysis.rb b/db/migrate/20160622074138_add_jk_version_to_quality_analysis.rb
new file mode 100644
index 000000000..838d6d896
--- /dev/null
+++ b/db/migrate/20160622074138_add_jk_version_to_quality_analysis.rb
@@ -0,0 +1,5 @@
+class AddJkVersionToQualityAnalysis < ActiveRecord::Migration
+ def change
+ add_column :quality_analyses, :sonar_version, :integer, :default => false
+ end
+end
diff --git a/db/migrate/20160624054614_add_column_to_quality_analyses.rb b/db/migrate/20160624054614_add_column_to_quality_analyses.rb
new file mode 100644
index 000000000..ed3e6b137
--- /dev/null
+++ b/db/migrate/20160624054614_add_column_to_quality_analyses.rb
@@ -0,0 +1,6 @@
+class AddColumnToQualityAnalyses < ActiveRecord::Migration
+ def change
+ add_column :quality_analyses, :path, :string
+ add_column :quality_analyses, :branch, :string
+ end
+end
diff --git a/db/migrate/20160624055127_add_languae_to_quality_analyses.rb b/db/migrate/20160624055127_add_languae_to_quality_analyses.rb
new file mode 100644
index 000000000..de531b1db
--- /dev/null
+++ b/db/migrate/20160624055127_add_languae_to_quality_analyses.rb
@@ -0,0 +1,5 @@
+class AddLanguaeToQualityAnalyses < ActiveRecord::Migration
+ def change
+ add_column :quality_analyses, :language, :string
+ end
+end
diff --git a/db/migrate/20160624103411_add_name_to_quality_analyses.rb b/db/migrate/20160624103411_add_name_to_quality_analyses.rb
new file mode 100644
index 000000000..bf61fd5ac
--- /dev/null
+++ b/db/migrate/20160624103411_add_name_to_quality_analyses.rb
@@ -0,0 +1,5 @@
+class AddNameToQualityAnalyses < ActiveRecord::Migration
+ def change
+ add_column :quality_analyses, :language, :string
+ end
+end
diff --git a/public/images/code-analysis-icon.png b/public/images/code-analysis-icon.png
new file mode 100644
index 000000000..18869da0e
Binary files /dev/null and b/public/images/code-analysis-icon.png differ
diff --git a/public/stylesheets/project.css b/public/stylesheets/project.css
index d8b8cc74a..bde560613 100644
--- a/public/stylesheets/project.css
+++ b/public/stylesheets/project.css
@@ -1247,6 +1247,39 @@ a.pages-big{ width:50px;}
.red-cir-btn{ background:#e74c3c; padding:1px 5px; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; color:#fff; font-weight:normal;font-size:12px;}
.green-cir-btn{ background:#28be6c; padding:1px 5px; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; color:#fff; font-weight:normal;font-size:12px;}
+/*20160622质量分析*/
+.analysis-tag-wrap {width:100%; color:#000; height:20px; line-height:20px; vertical-align:middle;}
+.analysis-tag {width:10px; height:20px; background-color:#777;}
+.analysis-block {padding:15px; border:1px solid #d9d9d9;}
+.flex {display:flex;}
+.analysis-genral {flex:1; display:block; text-align:center;}
+.analysis-block-icon {background:url(../images/code-analysis-icon.png) -2px -8px no-repeat; width:14px; height:14px; display:inline-block; vertical-align:middle;}
+.analysis-serious-icon {background:url(../images/code-analysis-icon.png) -2px -34px no-repeat; width:14px; height:14px; display:inline-block; vertical-align:middle;}
+.analysis-main-icon {background:url(../images/code-analysis-icon.png) -2px -59px no-repeat; width:14px; height:14px; display:inline-block; vertical-align:middle;}
+.analysis-secondary-icon {background:url(../images/code-analysis-icon.png) -2px -85px no-repeat; width:14px; height:14px; display:inline-block; vertical-align:middle;}
+.analysis-info-icon {background:url(../images/code-analysis-icon.png) -2px -111px no-repeat; width:14px; height:14px; display:inline-block; vertical-align:middle;}
+.quality-percentage {width:320px; height:14px; display:inline-block;}
+.quality-percentage-rate {width:50%; height:14px; background-color:#0a6c99; display:inline-block;}
+.image-cir {border-radius:50%;}
+.analysis-genral-icon {position:absolute; padding:1px 5px; display:inline-block; top:5px;}
+.contribute-list-avatar {width:80px; vertical-align:middle; text-align:center;}
+.contribute-list-code {width:160px; vertical-align:middle; text-align:center;}
+.contribute-list-problem {width:170px; vertical-align:middle; text-align:center;}
+.contribute-list-rate {width:228px; vertical-align:middle; text-align:center;}
+.contribute-list-height {height:80px;}
+.contribute-list-line-height {line-height:80px;}
+
+/*20160623分析结果*/
+.analysis-result-list {padding:5px;}
+.analysis-result-list:nth-of-type(odd){background:#fff;}/*奇数行*/
+.analysis-result-list:nth-of-type(even){background:#f5f5f5;}/*偶数行*/
+.analysis-result-name {width:200px; cursor:pointer;}
+.analysis-result-version {width:90px; text-align:right; cursor:pointer;}
+.analysis-result-loc {width:60px; text-align:right; cursor:pointer;}
+.analysis-result-debt {width:160px; text-align:right; cursor:pointer;}
+.analysis-result-time {width:150px; text-align:right; cursor:pointer;}
+.analysis-name-icon {background:url(../images/code-analysis-icon.png) -2px -148px no-repeat; width:16px; height:16px; display:inline-block; vertical-align:middle;}
+
/*未登录回复提示*/
.visitor-box {width:620px; height:33px; line-height:33px; text-align:center; vertical-align: middle; border:1px solid #ccc; background-color: #fff;}
@@ -1254,4 +1287,4 @@ a.pages-big{ width:50px;}
.H60 {height:60px !important;}
.W420 {width:420px;}
.W300 {width:300px !important;}
-.W600{ width:600px;}
\ No newline at end of file
+.W600{ width:600px;}
diff --git a/public/stylesheets/public.css b/public/stylesheets/public.css
index 74cbff5dd..500923519 100644
--- a/public/stylesheets/public.css
+++ b/public/stylesheets/public.css
@@ -27,6 +27,7 @@ a.btn_message_free{ background:#ff5722; display:block; text-align:center; color
h2{ font-size:18px; }
h3{ font-size:14px; }
h4{ font-size:14px; }
+.f8 {font-size:8px;}
.f12{font-size:12px; font-weight:normal;}
.f14{font-size:14px;}
.f16{font-size:16px;}
@@ -130,6 +131,7 @@ h4{ font-size:14px; }
.mt12 { margin-top:12px !important;}
.mt15 {margin-top:15px;}
.mt19 {margin-top:19px !important;}
+.mt35 {margin-top:35px;}
.ml70{margin-left: 70px;}
.mb0 {margin-bottom: 0px !important;}
.mb4{ margin-bottom:4px;}
@@ -137,6 +139,8 @@ h4{ font-size:14px; }
.mb8 {margin-bottom:8px;}
.mb10{ margin-bottom:10px !important;}
.mb20{ margin-bottom:20px;}
+.mb30 {margin-bottom:30px;}
+.mb40 {margin-bottom:40px;}
.pl10 {padding-left:10px;}
.pl15{ padding-left:15px;}
.pl5{ padding-left:5px;}
@@ -228,6 +232,7 @@ a.c_green{ color:#28be6c;}
.b_grey{ background: #F5F5F5;}
.b_dgrey{ background: #CCC;}
+.c_white {color:#fff;}
.c_orange{color:#e8770d;}
.c_dark{ color:#2d2d2d;}
.c_lorange{ color:#ff9900;}
@@ -239,6 +244,11 @@ a.c_green{ color:#28be6c;}
.c_dblue{ color:#09658c;}
.b_blue{background:#64bdd9;}
.b_green{background:#28be6c;}
+.b_slow_yellow{background:#adde18;}
+.b_yellow{background:#DDDF0D;}
+.b_slow_red{background:#df8538;}
+.b_green2 {background:#63c360;}
+.b_red {background:#d60308;}
.b_w{ background:#fff !important;}
/*add by Tim*/
@@ -341,6 +351,8 @@ a:hover.bgreen_n_btn{background:#08a384;}
.orange_btn_cir{ background:#e67e22; padding:1px 10px; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; color:#fff; font-weight:normal; font-size:12px;white-space:nowrap;}
.bgreen_btn_cir{ background:#1abc9c; padding:1px 10px; -moz-border-radius:2px; -webkit-border-radius:2px; border-radius:2px; color:#fff; font-weight:normal; font-size:12px;white-space:nowrap;}
.grey_border{border:1px solid #dddddd !important;}
+.borderRadius {border-radius:5px;}
+.tac {text-align:center;}
/* commonpic */
.pic_date{ display:block; background:url(../images/new_project/public_icon.png) -31px 0 no-repeat; width:16px; height:15px; float:left;}
.pic_add{ display:block; background:url(../images/new_project/public_icon.png) -31px -273px no-repeat; width:16px; height:15px; float:left;}
@@ -1167,4 +1179,7 @@ a.shadowbox_news_all{ display:block; width:305px; height:40px; line-height:40px;
/*未登录回复提示*/
.visitor-box {width:620px; height:33px; line-height:33px; text-align:center; vertical-align: middle; border:1px solid #ccc; background-color: #fff;}
-.reply_iconup{ position:absolute; top:21px; left:13px; color:#d4d4d4; font-size:16px; background:#f1f1f1; line-height:13px;}
\ No newline at end of file
+.reply_iconup{ position:absolute; top:21px; left:13px; color:#d4d4d4; font-size:16px; background:#f1f1f1; line-height:13px;}
+
+/*20160622代码分析弹窗*/
+.analysis-option-box {width:100%; border:1px solid #ccc; padding:3px 5px;}
\ No newline at end of file
diff --git a/spec/controllers/quality_analysis_controller_spec.rb b/spec/controllers/quality_analysis_controller_spec.rb
new file mode 100644
index 000000000..d25575a85
--- /dev/null
+++ b/spec/controllers/quality_analysis_controller_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe QualityAnalysisController, :type => :controller do
+
+end
diff --git a/spec/factories/quality_analyses.rb b/spec/factories/quality_analyses.rb
new file mode 100644
index 000000000..a48e6e33f
--- /dev/null
+++ b/spec/factories/quality_analyses.rb
@@ -0,0 +1,7 @@
+FactoryGirl.define do
+ factory :quality_analyasis, class: 'QualityAnalysis' do
+ project_id 1
+ author_login "MyString"
+ rep_identifier "MyString"
+ end
+end
diff --git a/spec/models/quality_analysis_spec.rb b/spec/models/quality_analysis_spec.rb
new file mode 100644
index 000000000..d18ede452
--- /dev/null
+++ b/spec/models/quality_analysis_spec.rb
@@ -0,0 +1,5 @@
+require 'rails_helper'
+
+RSpec.describe QualityAnalysis, :type => :model do
+ pending "add some examples to (or delete) #{__FILE__}"
+end