class QualityAnalysisController < ApplicationController before_filter :find_project_by_project_id#, :except => [:getattachtype] before_filter :find_quality_analysis, :only => [:edit, :update_jenkins_job] before_filter :authorize before_filter :connect_jenkins, :only => [:create, :edit, :update_jenkins_job, :index] layout "base_projects" include ApplicationHelper include QualityAnalysisHelper require 'jenkins_api_client' require 'nokogiri' require 'json' require 'open-uri' def show end # params 说明:{identifier:版本库名} def create begin user_name = User.find(params[:user_id]).try(:login) identifier = params[:identifier] rep_id = params[:rep_id] # job_name and sonar_name 前者为job名字,后者为jenkins配置名 job_name = "#{user_name}-#{rep_id}" sonar_name = "#{user_name}:#{rep_id}" # Checks if the given job exists in Jenkins. unless @client.job.exists?(job_name) @g = Gitlab.client branch = params[:branch] language = swith_language_type(params[:language]) path = params[:path].blank? ? "./" : params[:path] qa = QualityAnalysis.where(:project_id => @project.id, :author_login => user_name).first version = qa.nil? ? 1 : qa.sonar_version + 1 properties = "sonar.projectKey=#{sonar_name} sonar.projectName=#{sonar_name} 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" # 替换配置文件 @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 # jenkins job创建 jenkins_job = @client.job.create("#{job_name}", @doc.to_xml) logger.info("Jenkins status of create ==> #{jenkins_job}") # 将地址作为hook值添加到gitlab @g.add_project_hook(@project.gpid, @jenkins_address + "/project/#{job_name}") # job创建完成后自动运行job,如果运行成功则返回‘200’ code = @client.job.build("#{job_name}") logger.error("build result ==> #{code}") # 判断调用sonar分析是否成功 # 等待启动时间处理, 最长时间为30分钟 for i in 0..60 do sleep(60) @current_build_status = @client.job.get_current_build_status("#{job_name}") if (@current_build_status != "not_run" || @current_build_status != "running") break if i == 60 @build_console_result = false break end end end @console_build = @client.job.get_console_output("#{job_name}", build_num = 0, start = 0, mode = 'text') logger.info("@current_build_status is ==> #{@current_build_status}") logger.info("@console_build is ==> #{@console_build}") d = @client.job.delete("#{job_name}") if jenkins_job == '200' && code != '201' logger.error("delete result ==> #{code}") if qa.blank? && @current_build_status == "success" QualityAnalysis.create(:project_id => @project.id, :author_login => user_name, :rep_identifier => identifier, :sonar_version => version, :path => path, :branch => branch, :language => language, :sonar_name => "#{user_name}:#{rep_id}") else qa.update_attribute(:sonar_version, version) end end rescue => e puts e end respond_to do |format| format.html{redirect_to project_quality_analysis_path(:project_id => @project.id, :resource_id => sonar_name, :branch => branch, :current_build_status => @current_build_status, :job_name => job_name)} # format.js{redirect_to project_quality_analysis_path(:project_id => @project.id, :resource_id => sonar_name, :branch => branch)} end end # get language type def swith_language_type language if language == "c#" "cs" elsif language == "python" "py" elsif language == "c" "c++" else language end end def edit @g = Gitlab.client gitlab_branches = @g.branches(@project.gpid) @branch_names = gitlab_branches.map{|b| b.name} @gitlab_default_branch = @g.project(@project.gpid).default_branch end # 更新Jenkins job,主要包括相关配置文件参数的更新,Trustie平台数据的更新 def update_jenkins_job begin rep_id = Repository.where(:project_id => @project.id).first.try(:id) logger.error("#############################===>666") sonar_name = @quality_analysis.sonar_name job_name = "#{@quality_analysis.author_login}-#{rep_id}" version = @quality_analysis.sonar_version path = params[:path].blank? ? "./" : params[:path] language = swith_language_type(params[:language]) branch = params[:branch] identifier = @quality_analysis.rep_identifier properties = "sonar.projectKey=#{sonar_name} sonar.projectName=#{sonar_name} 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.yml @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 # update成功则返回 ‘200’ jenkins_job = @client.job.update("#{job_name}", @doc.to_xml) get_current_build_status = @client.job.get_current_build_status("Hjqreturn-1280") logger.error("Failed to update job: ==> #{jenkins_job}") unless jenkins_job == '200' # 数据更新到Trustie数据库 if jenkins_job == '200' logger.info("quality_ananlysis will be updated: ==> #{jenkins_job}") @quality_analysis.path = path @quality_analysis.language = language @quality_analysis.branch = branch @quality_analysis.save end rescue Exception => e logger.error("Update jenkins job: #{e}") end respond_to do |format| format.html{redirect_to project_quality_analysis_path(:project_id => @project.id)} format.js end end # resource_id: login + @repository.id def index begin @branch = params[:branch] @resource_id = params[:resource_id] @sonar_address = Redmine::Configuration['sonar_address'] @jenkins_address = Redmine::Configuration['jenkins_address'] if params[:resource_id].nil? @name_flag = true projects_date = open(@sonar_address + "/api/projects/index").read arr = JSON.parse(projects_date).map {|m| m["nm"]} # eg: ["Hjqreturn:cc_rep", "Hjqreturn:putong", "Hjqreturn:sonar_rep2", "shitou:sonar_rep"] @quality_analyses = QualityAnalysis.where(:project_id => @project.id).select{|qa| arr.include?(qa.sonar_name)} else if params[:current_build_status] == "failure" job_name = params[:job_name] @console_build = @client.job.get_console_output("#{job_name}", build_num = 0, start = 0, mode = 'text')["output"] end 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 rescue => e puts e 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 def find_quality_analysis begin @quality_analysis = QualityAnalysis.find(params[:id]) rescue render_404 end 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 def connect_jenkins @gitlab_address = Redmine::Configuration['gitlab_address'] @jenkins_address = Redmine::Configuration['jenkins_address'] # connect jenkins @client = JenkinsApi::Client.new(:server_url => @jenkins_address, :username => "temp", :password => '123123') rescue => e logger.error("failed to connect Jenkins ==> #{e}") end end