2014-09-15 10:58:14 +08:00
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU 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.
require 'SVG/Graph/Bar'
require 'SVG/Graph/BarHorizontal'
require 'digest/sha1'
require 'redmine/scm/adapters/abstract_adapter'
require 'tempfile'
2016-06-24 21:33:35 +08:00
require 'json'
require 'open-uri'
2014-09-15 10:58:14 +08:00
class ChangesetNotFound < Exception ; end
class InvalidRevisionParam < Exception ; end
class RepositoriesController < ApplicationController
2015-04-16 14:59:05 +08:00
include ApplicationHelper
2014-09-15 10:58:14 +08:00
menu_item :repository
menu_item :settings , :only = > [ :new , :create , :edit , :update , :destroy , :committers ]
default_search_scope :changesets
2015-10-19 14:03:08 +08:00
2016-06-22 11:25:59 +08:00
before_filter :find_project_by_project_id , :only = > [ :new , :create , :newrepo , :stats , :quality_analysis ]
2015-12-21 17:13:13 +08:00
before_filter :find_repository , :only = > [ :edit , :update , :destroy , :committers ]
2016-09-26 16:17:21 +08:00
before_filter :find_project_repository , :except = > [ :new , :create , :newcreate , :edit , :update , :destroy , :committers , :newrepo , :to_gitlab , :forked , :project_archive , :export_rep_static ]
2014-09-15 10:58:14 +08:00
before_filter :find_changeset , :only = > [ :revision , :add_related_issue , :remove_related_issue ]
2016-06-22 11:25:59 +08:00
before_filter :authorize , :except = > [ :newrepo , :newcreate , :fork , :to_gitlab , :forked , :commit_diff , :project_archive , :quality_analysis ]
2016-06-20 14:21:40 +08:00
# 链接gitlab
2016-07-18 11:25:45 +08:00
before_filter :connect_gitlab , :only = > [ :quality_analysis , :show , :commit_diff , :find_project_repository ]
2016-07-06 16:37:19 +08:00
# 版本库新增权限
before_filter :show_rep , :only = > [ :show ]
2014-09-15 10:58:14 +08:00
accept_rss_auth :revisions
# hidden repositories filter // 隐藏代码过滤器
before_filter :check_hidden_repo , :only = > [ :show , :stats , :revisions , :revision , :diff ]
helper :repositories
include RepositoriesHelper
helper :project_score
#@root_path = RepositoriesHelper::ROOT_PATH
2016-07-19 15:59:52 +08:00
# require 'net/ssh'
2014-09-15 10:58:14 +08:00
rescue_from Redmine :: Scm :: Adapters :: CommandFailed , :with = > :show_error_command_failed
def new
2015-10-14 17:37:22 +08:00
if @project . repositories . count == 0
scm = params [ :repository_scm ] || ( Redmine :: Scm :: Base . all & Setting . enabled_scm ) . first
@repository = Repository . factory ( scm )
@repository . is_default = @project . repository . nil?
@repository . project = @project
@course_tag = params [ :course ]
if @course_tag == 1
render :layout = > 'base_courses'
else
render :layout = > 'base_projects'
end
2014-09-15 10:58:14 +08:00
else
2015-10-14 17:37:22 +08:00
render_403
2014-09-15 10:58:14 +08:00
end
2015-10-14 17:37:22 +08:00
2014-09-15 10:58:14 +08:00
end
2015-10-19 14:03:08 +08:00
2016-09-26 16:17:21 +08:00
def export_rep_static
@project = Project . find ( params [ :id ] )
gpid = @project . gpid
rev = params [ :rev ]
cycle = params [ :cycle ]
respond_to do | format |
format . html
format . xls {
filename = " #{ @project . name . to_s } _ #{ l ( :label_issue_list_xls ) } _ #{ @rev } _ #{ l ( :label_rep_xls ) } .xls "
send_data ( export_rep_xls ( gpid , :rev = > rev , :cycle = > " 1 " ) , :type = > 'application/octet-stream' , :filename = > filename_for_content_disposition ( filename ) )
}
end
end
2015-11-13 17:30:14 +08:00
def forked
2015-12-21 17:13:13 +08:00
@project = Project . find ( params [ :id ] )
@repository = Repository . where ( " project_id =? and type =? " , @project . id , " Repository::Gitlab " )
2015-12-04 15:49:05 +08:00
# 如果当前用户已经fork过该项目, 不会新fork项目, 则跳至已fork的项
unless has_forked? ( @project , User . current )
project = project_from_current_project ( @project . id , User . current . id )
redirect_to project_path ( project )
2015-11-13 20:24:30 +08:00
else
2015-12-07 10:34:10 +08:00
# 自己不能fork自己的项目
if User . current . id == @project . user_id
flash [ :notice ] = l ( :project_gitlab_fork_own )
redirect_to repository_url ( @repository )
else
2015-12-04 15:49:05 +08:00
g = Gitlab . client
2015-12-08 09:46:29 +08:00
if User . current . gid . nil?
2015-12-21 17:13:13 +08:00
begin
g . sync_user ( User . current )
ensure
logger . error " Synv user failed ==> #{ User . current . id } "
end
2015-12-08 09:46:29 +08:00
end
2015-12-04 15:49:05 +08:00
gproject = g . fork ( @project . gpid , User . current . gid )
if gproject
copy_project ( @project , gproject )
forked_count = @project . forked_count . to_i + 1
@project . update_attributes ( :forked_count = > forked_count )
end
2015-12-07 10:34:10 +08:00
end
2015-11-13 17:30:14 +08:00
end
2015-12-04 15:49:05 +08:00
end
2016-05-11 13:44:15 +08:00
# 一键ZIP下载
def project_archive
g = Gitlab . client
g . get ( )
# g.project_archive(params[:gpid].to_i, params[:rev])
end
2015-12-04 15:49:05 +08:00
# 判断用户是否已经fork过该项目
def has_forked? ( project , user )
projects = Project . where ( " user_id =? " , user )
projects . map ( & :forked_from_project_id ) . detect { | s | s == @project . id } . nil? ? true : false
end
# 获取当前用户fork过的项目
def project_from_current_project ( project , user )
project = Project . where ( " user_id =? and forked_from_project_id =? " , user , project ) . first
2015-11-13 17:30:14 +08:00
end
# copy a project for fork
2015-12-04 15:49:05 +08:00
def copy_project ( tproject , gproject )
2015-11-13 17:30:14 +08:00
project = Project . new
2015-12-04 15:49:05 +08:00
project . name = tproject . name
project . is_public = tproject . is_public
project . status = tproject . status
project . description = tproject . description
project . hidden_repo = tproject . hidden_repo
2015-11-13 17:30:14 +08:00
project . user_id = User . current . id
project . project_type = 0
2015-12-04 15:49:05 +08:00
project . project_new_type = tproject . project_new_type
2015-11-13 17:30:14 +08:00
project . gpid = gproject . id
2015-12-04 15:49:05 +08:00
project . forked_from_project_id = tproject . id
2015-11-13 17:30:14 +08:00
if project . save
r = Role . givable . find_by_id ( Setting . new_project_user_role_id . to_i ) || Role . givable . first
m = Member . new ( :user = > User . current , :roles = > [ r ] )
2016-01-14 20:48:12 +08:00
if ProjectScore . where ( " project_id=? " , project . id ) . first . nil?
ProjectScore . create ( :project_id = > project . id , :score = > false )
2016-01-14 12:52:44 +08:00
end
2015-11-13 17:30:14 +08:00
project_info = ProjectInfo . new ( :user_id = > User . current . id , :project_id = > project . id )
user_grades = UserGrade . create ( :user_id = > User . current . id , :project_id = > project . id )
Rails . logger . debug " UserGrade created: #{ user_grades . to_json } "
project_status = ProjectStatus . create ( :project_id = > @project . id , :watchers_count = > 0 , :changesets_count = > 0 , :project_type = > @project . project_type , :grade = > 0 )
Rails . logger . debug " ProjectStatus created: #{ project_status . to_json } "
project . members << m
project . project_infos << project_info
copy_repository ( project , gproject )
respond_to do | format |
format . html {
flash [ :notice ] = l ( :notice_successful_create )
if params [ :continue ]
attrs = { :parent_id = > project . parent_id } . reject { | k , v | v . nil? }
redirect_to new_project_url ( attrs , :course = > '0' )
else
2016-03-09 13:17:37 +08:00
redirect_to project_path ( project )
2015-11-13 17:30:14 +08:00
end
}
format . api { render :action = > 'show' , :status = > :created , :location = > url_for ( :controller = > 'projects' , :action = > 'show' , :id = > project . id ) }
format . js
end
else
respond_to do | format |
format . html { render :action = > 'forked' , :layout = > 'base_projects' }
format . api { render_validation_errors ( @project ) }
end
end
end
def copy_repository ( project , gproject )
# 避免
2015-12-04 15:49:05 +08:00
# if is_sigle_identifier?(project.user_id, gproject.name)
2015-11-13 20:24:30 +08:00
repository = Repository . factory ( 'Git' )
repository . project_id = project . id
repository . type = 'Repository::Gitlab'
repository . url = gproject . name
repository . identifier = gproject . name
repository = repository . save
2015-12-04 15:49:05 +08:00
# else
# flash[:notice] = l(:project_gitlab_create_double_message)
# end
2015-11-13 17:30:14 +08:00
end
2015-10-19 14:03:08 +08:00
2014-09-15 10:58:14 +08:00
def newrepo
scm = params [ :repository_scm ] || ( Redmine :: Scm :: Base . all & Setting . enabled_scm ) . first
@repository = Repository . factory ( scm )
@repository . is_default = @project . repository . nil?
@repository . project = @project
@course_tag = params [ :course ]
if @course_tag == 1
render :layout = > 'base_courses'
else
render :layout = > 'base_projects'
end
end
2015-10-19 14:03:08 +08:00
2014-09-15 10:58:14 +08:00
def fork
@repository_url = params [ :repository_url ]
2015-10-19 14:03:08 +08:00
2014-09-15 10:58:14 +08:00
# @repository.url
# system "htpasswd -mb "+@root_path+"user.passwd "+params[:repository][:identifier]+" "+@upasswd
# system "echo -e '"+params[:project_id]+"-"+params[:repository][:identifier]+"-write:"+
2015-10-19 14:03:08 +08:00
# " "+params[:repository][:identifier]+"' >> "+@root_path+"group.passwd"
system " git clone --bare " + @repository_url
2014-09-15 10:58:14 +08:00
# system "mv "+@project_path+"/hooks/post-update{.sample,}"
# system "chmod a+x "+@project_path+"/hooks/post-update"
# system "."+@project_path+"/hooks/post-update"
# system "echo -e 'Allow from all \n Order Deny,Allow \n "+
2015-10-19 14:03:08 +08:00
# "<Limit PUT POST DELETE PROPPATCH MKCOL COPY MOVE LOCK UNLOCK> \n"+
# "Require group "+params[:project_id]+"-"+params[:repository][:identifier]+"-write \n "+
# "</Limit> \n ' >>"+
# @project_path+"/.htaccess"
2014-09-15 10:58:14 +08:00
flash [ :notice ] = l ( :label_notice_fork_successed )
@repositories = @project . repositories
render :action = > 'show' , :layout = > 'base_projects'
end
2015-03-18 11:22:05 +08:00
HOOK_TEMPLATE = %Q{ # !/bin/sh
2015-03-18 14:42:11 +08:00
exec sh - c '
function update ( )
{
CMD_PATH = ` dirname $0 ` ;
cd $CMD_PATH ;
PY_PATH = $PWD / .. / .. / git_refresh_changes . py ;
[ [ - s " $PY_PATH " ] ] && $ ( which python ) $PY_PATH $PWD ;
cd - ;
2015-03-18 11:22:05 +08:00
}
2015-03-18 14:42:11 +08:00
git update - server - info
update
'
}
2015-03-18 11:22:05 +08:00
2014-09-15 10:58:14 +08:00
def create
2015-11-13 20:24:30 +08:00
# 判断版本库创建者是否有同名版本库,避免版本库路径一致问题
unless is_sigle_identifier? ( @project . user_id , params [ :repository ] . first [ 1 ] )
flash [ :notice ] = l ( :project_gitlab_create_double_message )
2015-10-21 17:13:07 +08:00
redirect_to settings_project_url ( @project , :tab = > 'repositories' )
else
2015-11-13 20:24:30 +08:00
attrs = pickup_extra_info
@repository = Repository . factory ( 'Git' )
@repository . safe_attributes = params [ :repository ]
if attrs [ :attrs_extra ] . keys . any?
@repository . merge_extra_info ( attrs [ :attrs_extra ] )
end
@repository . project = @project
@repository . type = 'Repository::Gitlab'
@repository . url = @repository . identifier
if request . post? && @repository . save
s = Trustie :: Gitlab :: Sync . new
s . create_project ( @project , @repository )
redirect_to settings_project_url ( @project , :tab = > 'repositories' )
else
redirect_to settings_project_url ( @project , :tab = > 'repositories' , :repository_error_message = > @repository . errors . full_messages )
end
2014-09-15 10:58:14 +08:00
end
end
2015-10-19 14:03:08 +08:00
2014-09-15 10:58:14 +08:00
def edit
end
def update
attrs = pickup_extra_info
@repository . safe_attributes = attrs [ :attrs ]
if attrs [ :attrs_extra ] . keys . any?
@repository . merge_extra_info ( attrs [ :attrs_extra ] )
end
@repository . project = @project
if request . put? && @repository . save
2014-10-15 09:54:54 +08:00
redirect_to settings_project_url ( @project , :tab = > 'repositories' )
2014-09-15 10:58:14 +08:00
else
render :action = > 'edit'
end
end
def pickup_extra_info
p = { }
p_extra = { }
params [ :repository ] . each do | k , v |
if k =~ / ^extra_ /
p_extra [ k ] = v
else
p [ k ] = v
end
end
{ :attrs = > p , :attrs_extra = > p_extra }
end
private :pickup_extra_info
def committers
@committers = @repository . committers
@users = @project . users
additional_user_ids = @committers . collect ( & :last ) . collect ( & :to_i ) - @users . collect ( & :id )
@users += User . find_all_by_id ( additional_user_ids ) unless additional_user_ids . empty?
@users . compact!
@users . sort!
if request . post? && params [ :committers ] . is_a? ( Hash )
# Build a hash with repository usernames as keys and corresponding user ids as values
@repository . committer_ids = params [ :committers ] . values . inject ( { } ) { | h , c | h [ c . first ] = c . last ; h }
flash [ :notice ] = l ( :notice_successful_update )
2015-10-19 14:03:08 +08:00
respond_to do | format |
format . html {
render :layout = > " base_projects "
}
end
2015-10-23 16:28:17 +08:00
elsif request . get?
respond_to do | format |
format . html {
render :layout = > " base_projects "
}
end
2014-09-15 10:58:14 +08:00
end
end
2016-06-22 11:25:59 +08:00
def quality_analysis
2016-06-20 14:21:40 +08:00
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
2016-06-13 15:21:29 +08:00
respond_to do | format |
2016-06-20 14:21:40 +08:00
format . js
2016-06-14 09:57:29 +08:00
format . html {
render :layout = > " base_projects "
}
2016-06-13 15:21:29 +08:00
end
end
2014-09-15 10:58:14 +08:00
def destroy
2015-04-28 10:33:15 +08:00
DestroyRepositoryTask . new . destroy ( User . current . id , @repository . id )
@repository . hidden = true
@repository . save
2014-10-15 09:54:54 +08:00
redirect_to settings_project_url ( @project , :tab = > 'repositories' )
2014-09-15 10:58:14 +08:00
end
2015-10-18 21:04:04 +08:00
def to_gitlab
@project = Project . find ( params [ :project_id ] )
@repository = Repository . find ( params [ :id ] )
s = Trustie :: Gitlab :: Sync . new
s . sync_project ( @project , path : params [ :repo_name ] , import_url : @repository . url )
@repository . type = 'Repository::Gitlab'
@repository . save
redirect_to :controller = > 'repositories' , :action = > 'show' , :id = > @project . id , to : 'gitlab'
end
2014-09-15 10:58:14 +08:00
def show
## TODO: the below will move to filter, done.
2016-07-06 16:37:19 +08:00
2016-07-06 16:07:17 +08:00
# 获取版本库目录结构
2015-10-16 20:06:03 +08:00
@entries = @repository . entries ( @path , @rev )
2014-09-15 10:58:14 +08:00
if request . xhr?
@entries ? render ( :partial = > 'dir_list_content' ) : render ( :nothing = > true )
else
2016-07-05 17:35:56 +08:00
@changesets = @g . commits ( @project . gpid , :ref_name = > @rev )
2016-07-06 16:07:17 +08:00
# 最近一次提交
@changesets_latest_coimmit = @changesets [ 0 ]
2016-07-05 17:35:56 +08:00
g_project = @g . project ( @project . gpid )
2016-04-12 11:10:30 +08:00
# 总的提交数
2016-07-05 17:35:56 +08:00
@changesets_all_count = @g . user_static ( @project . gpid , :rev = > @rev ) . count
2016-07-06 16:07:17 +08:00
# 获取默认分支
2016-04-15 16:50:39 +08:00
@g_default_branch = g_project . default_branch . nil? ? " master " : g_project . default_branch
2016-07-06 16:07:17 +08:00
# 访问版本庫后更新project_score表数据; changeset_num为提交总数
project_score = @project . project_score
if project_score . nil?
2016-01-14 14:32:19 +08:00
ProjectScore . create ( :project_id = > @project . id , :score = > false )
2016-07-06 16:07:17 +08:00
else
project_score . update_column ( :changeset_num , @changesets_all_count )
2016-01-13 15:50:55 +08:00
end
2016-07-05 17:35:56 +08:00
2016-08-22 14:20:59 +08:00
unless @changesets_latest_coimmit . blank?
update_commits_date ( @project , @changesets_latest_coimmit )
end
2016-07-06 16:07:17 +08:00
@creator = @project . owner . to_s
2015-10-30 16:26:51 +08:00
gitlab_address = Redmine :: Configuration [ 'gitlab_address' ]
2016-07-06 16:07:17 +08:00
2016-05-20 15:28:09 +08:00
# REDO:需优化,仅测试用
2016-06-12 15:01:28 +08:00
@zip_path = Gitlab . endpoint . to_s + " /projects/ " + @project . gpid . to_s + " /repository/archive?&private_token= " + Gitlab . private_token
2016-07-06 16:07:17 +08:00
# 获取版本库路径, 主要分为两种, 一种随Gitlab类型, 另一种为Git类型, Git类型为无用数据, 最终需要删掉这种类型。
2015-11-02 16:41:15 +08:00
if @repository . type . to_s == " Repository::Gitlab "
2016-07-06 16:07:17 +08:00
@repos_url = gitlab_address . to_s + " / " + @creator + " / " + @repository . identifier + " . " + " git "
2015-10-22 13:44:35 +08:00
else
2015-11-02 17:36:45 +08:00
@repos_url = " http:// " + @repository . login . to_s + " _ " + @repository . identifier . to_s + " @ " + ip . to_s + @repository . url . slice ( project_path_cut , @repository . url . length ) . to_s
2015-10-22 13:44:35 +08:00
end
2016-04-12 11:10:30 +08:00
render :action = > 'show' , :layout = > 'base_projects'
2014-09-15 10:58:14 +08:00
end
end
alias_method :browse , :show
def changes
@entry = @repository . entry ( @path , @rev )
( show_error_not_found ; return ) unless @entry
2015-10-29 17:28:23 +08:00
g = Gitlab . client
2015-11-18 16:11:51 +08:00
limit = 20
2015-11-19 14:59:26 +08:00
#每次页面的换回值从1开始,但是gitlab的页面查询是从0开始,所以先改变page的类型减一在改回来
2016-04-13 14:44:57 +08:00
@commits = g . commits ( @project . gpid , page : ( params [ :page ] . to_i - 1 ) . to_s , ref_name : @rev )
2015-12-08 15:56:31 +08:00
#add by hx
2015-12-21 16:21:39 +08:00
#rep_count = commit_count(@project)
2015-12-08 15:56:31 +08:00
2015-11-19 14:59:26 +08:00
#页面传递必须要str类型,但是Paginator的初始化必须要num类型,需要类型转化
2015-12-21 16:21:39 +08:00
@commits_count = params [ :commit_count ] . to_i
2015-11-18 16:11:51 +08:00
@commits_pages = Redmine :: Pagination :: Paginator . new @commits_count , limit , params [ :page ]
2015-11-03 17:19:19 +08:00
@commit = g . commit ( @project . gpid , @rev )
# @changesets = g.get ("/projects/#{@project.gpid}/repository/commits?#{@rev}")
2015-10-29 17:28:23 +08:00
#@changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
2014-09-15 10:58:14 +08:00
@properties = @repository . properties ( @path , @rev )
@changeset = @repository . find_changeset_by_name ( @rev )
render :layout = > 'base_projects'
end
2015-11-19 14:59:26 +08:00
2014-09-15 10:58:14 +08:00
def revisions
@changeset_count = @repository . changesets . count
@changeset_pages = Paginator . new @changeset_count ,
per_page_option ,
params [ 'page' ]
@changesets = @repository . changesets .
2015-10-19 14:03:08 +08:00
limit ( @changeset_pages . per_page ) .
offset ( @changeset_pages . offset ) .
includes ( :user , :repository , :parents ) .
all
2014-09-15 10:58:14 +08:00
respond_to do | format |
format . html { render :layout = > 'base_projects' }
format . atom { render_feed ( @changesets , :title = > " #{ @project . name } : #{ l ( :label_revision_plural ) } " ) }
end
end
def raw
entry_and_raw ( true )
end
def entry
entry_and_raw ( false )
2016-03-09 11:30:28 +08:00
@content = @repository . cat ( @path , @rev )
if is_entry_text_data? ( @content , @path )
render :layout = > 'base_projects'
end
2014-09-15 10:58:14 +08:00
end
def entry_and_raw ( is_raw )
@entry = @repository . entry ( @path , @rev )
( show_error_not_found ; return ) unless @entry
# If the entry is a dir, show the browser
( show ; return ) if @entry . is_dir?
@content = @repository . cat ( @path , @rev )
( show_error_not_found ; return ) unless @content
2016-03-09 11:30:28 +08:00
if is_raw || ( @content . size && @content . size > Setting . file_max_size_displayed . to_i . kilobyte ) || ! is_entry_text_data? ( @content , @path )
2014-09-15 10:58:14 +08:00
# Force the download
send_opt = { :filename = > filename_for_content_disposition ( @path . split ( '/' ) . last ) }
send_type = Redmine :: MimeType . of ( @path )
send_opt [ :type ] = send_type . to_s if send_type
send_opt [ :disposition ] = ( Redmine :: MimeType . is_type? ( 'image' , @path ) && ! is_raw ? 'inline' : 'attachment' )
send_data @content , send_opt
else
# Prevent empty lines when displaying a file with Windows style eol
# TODO: UTF-16
# Is this needs? AttachmentsController reads file simply.
@content . gsub! ( " \r \n " , " \n " )
@changeset = @repository . find_changeset_by_name ( @rev )
end
end
private :entry_and_raw
def is_entry_text_data? ( ent , path )
# UTF-16 contains "\x00".
# It is very strict that file contains less than 30% of ascii symbols
# in non Western Europe.
return true if Redmine :: MimeType . is_type? ( 'text' , path )
# Ruby 1.8.6 has a bug of integer divisions.
# http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
return false if ent . is_binary_data?
true
end
private :is_entry_text_data?
def annotate
@entry = @repository . entry ( @path , @rev )
( show_error_not_found ; return ) unless @entry
@annotate = @repository . scm . annotate ( @path , @rev )
if @annotate . nil? || @annotate . empty?
( render_error l ( :error_scm_annotate ) ; return )
end
ann_buf_size = 0
@annotate . lines . each do | buf |
ann_buf_size += buf . size
end
if ann_buf_size > Setting . file_max_size_displayed . to_i . kilobyte
( render_error l ( :error_scm_annotate_big_text_file ) ; return )
end
@changeset = @repository . find_changeset_by_name ( @rev )
end
def revision
respond_to do | format |
2015-06-19 14:10:08 +08:00
format . html { render :layout = > 'base_projects' }
2014-09-15 10:58:14 +08:00
format . js { render :layout = > false }
end
end
# Adds a related issue to a changeset
# POST /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues
def add_related_issue
@issue = @changeset . find_referenced_issue_by_id ( params [ :issue_id ] )
if @issue && ( ! @issue . visible? || @changeset . issues . include? ( @issue ) )
@issue = nil
end
if @issue
@changeset . issues << @issue
end
end
# Removes a related issue from a changeset
# DELETE /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues/:issue_id
def remove_related_issue
@issue = Issue . visible . find_by_id ( params [ :issue_id ] )
if @issue
@changeset . issues . delete ( @issue )
end
end
2016-02-25 11:06:10 +08:00
# 每次提交对应的文件差异
2016-02-23 15:09:15 +08:00
def commit_diff
2016-07-18 11:25:45 +08:00
@commit_diff = @g . commit_diff ( @project . gpid , params [ :changeset ] )
@commit_details = @g . commit ( @project . gpid , params [ :changeset ] )
2016-02-25 11:06:10 +08:00
render :layout = > 'base_projects'
2016-02-23 15:09:15 +08:00
end
2014-09-15 10:58:14 +08:00
def diff
if params [ :format ] == 'diff'
@diff = @repository . diff ( @path , @rev , @rev_to )
( show_error_not_found ; return ) unless @diff
filename = " changeset_r #{ @rev } "
filename << " _r #{ @rev_to } " if @rev_to
send_data @diff . join , :filename = > " #{ filename } .diff " ,
2015-10-19 14:03:08 +08:00
:type = > 'text/x-patch' ,
:disposition = > 'attachment'
2014-09-15 10:58:14 +08:00
else
@diff_type = params [ :type ] || User . current . pref [ :diff_type ] || 'inline'
@diff_type = 'inline' unless %w( inline sbs ) . include? ( @diff_type )
# Save diff type as user preference
if User . current . logged? && @diff_type != User . current . pref [ :diff_type ]
User . current . pref [ :diff_type ] = @diff_type
User . current . preference . save
end
@cache_key = " repositories/diff/ #{ @repository . id } / " +
2015-10-19 14:03:08 +08:00
Digest :: MD5 . hexdigest ( " #{ @path } - #{ @rev } - #{ @rev_to } - #{ @diff_type } - #{ current_language } " )
2014-09-15 10:58:14 +08:00
unless read_fragment ( @cache_key )
@diff = @repository . diff ( @path , @rev , @rev_to )
unless @diff
show_error_not_found
return
end
end
@changeset = @repository . find_changeset_by_name ( @rev )
@changeset_to = @rev_to ? @repository . find_changeset_by_name ( @rev_to ) : nil
@diff_format_revisions = @repository . diff_format_revisions ( @changeset , @changeset_to )
end
render :layout = > 'base_projects'
end
def stats
2016-04-13 14:36:43 +08:00
if @project . gpid . nil?
render 404
return
end
project_id = @project . gpid
2016-04-13 20:39:20 +08:00
# @repository_id = @repository.identifier
# creator = params[:creator]
2016-04-13 14:36:43 +08:00
rev = params [ :rev ]
g = Gitlab . client
begin
2016-04-13 20:39:20 +08:00
@static_total_per_user = g . rep_stats ( project_id , :rev = > rev )
2016-04-15 12:24:54 +08:00
# 更新rep_statics统计数
@static_total_per_user . each do | static |
rep_static = RepStatics . where ( " project_id =? and email =? " , @project . id , static . email . to_s ) . first
if rep_static . nil?
RepStatics . create ( :project_id = > @project . id , :uname = > static . uname , :commits_num = > static . commits_num , :email = > static . email , :add = > static . add , :del = > static . del , :changeset = > static . changes )
else
2016-04-15 16:50:39 +08:00
if @rev == params [ :default_branch ]
rep_static . update_attributes ( :uname = > static . uname , :commits_num = > static . commits_num , :email = > static . email , :add = > static . add , :del = > static . del , :changeset = > static . changes )
end
2016-04-15 12:24:54 +08:00
end
end
2016-04-13 14:36:43 +08:00
rescue
render_404
return
end
2014-09-15 10:58:14 +08:00
render :layout = > 'base_projects'
end
def graph
data = nil
case params [ :graph ]
2015-10-19 14:03:08 +08:00
when " commits_per_month "
data = graph_commits_per_month ( @repository )
when " commits_per_author "
data = graph_commits_per_author ( @repository )
when " author_commits_per_month "
data = graph_author_commits_per_month ( @repository )
when " author_commits_six_month "
data = author_commits_six_month ( @repository )
when " author_code_six_months "
data = author_code_six_month ( @repository )
2014-09-15 10:58:14 +08:00
end
if data
headers [ " Content-Type " ] = " image/svg+xml "
send_data ( data , :type = > " image/svg+xml " , :disposition = > " inline " )
else
render_404
end
end
private
2016-01-13 15:50:55 +08:00
# 更新项目统计数
def update_commits_count project , count
2016-01-14 14:32:19 +08:00
project . project_score . update_attribute ( :changeset_num , count )
2016-01-13 15:50:55 +08:00
end
2014-09-15 10:58:14 +08:00
2016-01-22 18:00:01 +08:00
# 更新项目提交次数时间
def update_commits_date project , date
project . project_score . update_attribute ( :commit_time , date . created_at )
end
2016-06-20 14:21:40 +08:00
# 链接gitlab
def connect_gitlab
2016-07-06 16:37:19 +08:00
begin
@g = Gitlab . client
unless @project . gpid . nil?
@g_project = @g . project ( @project . gpid )
end
rescue = > e
logger . error ( " failed to connect gitlab ==> #{ e } " )
end
end
def show_rep
if ! User . current . member_of? ( @project ) && @project . hidden_repo
render_403
return
2016-06-20 14:21:40 +08:00
end
end
2014-09-15 10:58:14 +08:00
def find_repository
@repository = Repository . find ( params [ :id ] )
@project = @repository . project
2015-11-14 10:54:46 +08:00
rescue ActiveRecord :: RecordNotFound
render_404
2014-09-15 10:58:14 +08:00
end
REV_PARAM_RE = %r{ \ A[a-f0-9]* \ Z }i
def find_project_repository
@project = Project . find ( params [ :id ] )
if params [ :repository_id ] . present?
@repository = @project . repositories . find_by_identifier_param ( params [ :repository_id ] )
else
2015-07-22 16:38:52 +08:00
# 多版本库,如果一个版本库为空则去下一个
rep_count = @project . repositories . count
if @project . repository . nil?
for i in 0 .. rep_count
unless @project . repositories [ i ] . nil?
@repository = @project . repositories [ i ]
break
end
end
else
@repository = @project . repository
end
2014-09-15 10:58:14 +08:00
end
( render_404 ; return false ) unless @repository
@path = params [ :path ] . is_a? ( Array ) ? params [ :path ] . join ( '/' ) : params [ :path ] . to_s
2016-02-26 15:37:59 +08:00
# gitlab端获取默认分支
2016-07-18 11:25:45 +08:00
g = Gitlab . client
gitlab_branchs = g . project ( @project . gpid ) . default_branch
2016-02-26 15:37:59 +08:00
@project . gpid . nil? ? ( @rev = params [ :rev ] . blank? ? @repository . default_branch : params [ :rev ] . to_s . strip ) : ( @rev = params [ :rev ] . blank? ? gitlab_branchs : params [ :rev ] . to_s . strip )
2014-09-15 10:58:14 +08:00
@rev_to = params [ :rev_to ]
unless @rev . to_s . match ( REV_PARAM_RE ) && @rev_to . to_s . match ( REV_PARAM_RE )
if @repository . branches . blank?
raise InvalidRevisionParam
end
end
rescue ActiveRecord :: RecordNotFound
render_404
rescue InvalidRevisionParam
show_error_not_found
end
def find_changeset
if @rev . present?
@changeset = @repository . find_changeset_by_name ( @rev )
end
show_error_not_found unless @changeset
end
def show_error_not_found
render_error :message = > l ( :error_scm_not_found ) , :status = > 404
end
def show_error_forbidden
render_error :status = > 403
end
# Handler for Redmine::Scm::Adapters::CommandFailed exception
def show_error_command_failed ( exception )
render_error l ( :error_scm_command_failed , exception . message )
end
def graph_commits_per_month ( repository )
@date_to = Date . today
@date_from = @date_to << 11
@date_from = Date . civil ( @date_from . year , @date_from . month , 1 )
commits_by_day = Changeset . count (
2015-10-19 14:03:08 +08:00
:all , :group = > :commit_date ,
:conditions = > [ " repository_id = ? AND commit_date BETWEEN ? AND ? " , repository . id , @date_from , @date_to ] )
2014-09-15 10:58:14 +08:00
commits_by_month = [ 0 ] * 12
commits_by_day . each { | c | commits_by_month [ ( @date_to . month - c . first . to_date . month ) % 12 ] += c . last }
changes_by_day = Change . count (
2015-10-19 14:03:08 +08:00
:all , :group = > :commit_date , :include = > :changeset ,
:conditions = > [ " #{ Changeset . table_name } .repository_id = ? AND #{ Changeset . table_name } .commit_date BETWEEN ? AND ? " , repository . id , @date_from , @date_to ] )
2014-09-15 10:58:14 +08:00
changes_by_month = [ 0 ] * 12
changes_by_day . each { | c | changes_by_month [ ( @date_to . month - c . first . to_date . month ) % 12 ] += c . last }
fields = [ ]
12 . times { | m | fields << month_name ( ( ( Date . today . month - 1 - m ) % 12 ) + 1 ) }
graph = SVG :: Graph :: Bar . new (
2015-10-19 14:03:08 +08:00
:height = > 300 ,
:width = > 600 ,
:fields = > fields . reverse ,
:stack = > :side ,
:scale_integers = > true ,
:step_x_labels = > 2 ,
:show_data_values = > true ,
:graph_title = > l ( :label_commits_per_month ) ,
:show_graph_title = > true
2014-09-15 10:58:14 +08:00
)
2015-07-18 13:02:28 +08:00
# 具状图
2014-09-15 10:58:14 +08:00
graph . add_data (
2015-10-19 14:03:08 +08:00
:data = > commits_by_month [ 0 .. 11 ] . reverse ,
:title = > l ( :label_revision_plural )
2014-09-15 10:58:14 +08:00
)
graph . add_data (
2015-10-19 14:03:08 +08:00
:data = > changes_by_month [ 0 .. 11 ] . reverse ,
:title = > l ( :label_change_plural )
2014-09-15 10:58:14 +08:00
)
graph . burn
end
def graph_commits_per_author ( repository )
commits_by_author = Changeset . count ( :all , :group = > :committer , :conditions = > [ " repository_id = ? " , repository . id ] )
2015-07-18 13:02:28 +08:00
commits_by_author = commits_by_author . to_a . sort! { | x , y | x . last < = > y . last } . last ( 25 )
2014-09-15 10:58:14 +08:00
changes_by_author = Change . count ( :all , :group = > :committer , :include = > :changeset , :conditions = > [ " #{ Changeset . table_name } .repository_id = ? " , repository . id ] )
h = changes_by_author . inject ( { } ) { | o , i | o [ i . first ] = i . last ; o }
fields = commits_by_author . collect { | r | r . first }
commits_data = commits_by_author . collect { | r | r . last }
changes_data = commits_by_author . collect { | r | h [ r . first ] || 0 }
fields = fields + [ " " ] * ( 10 - fields . length ) if fields . length < 10
commits_data = commits_data + [ 0 ] * ( 10 - commits_data . length ) if commits_data . length < 10
changes_data = changes_data + [ 0 ] * ( 10 - changes_data . length ) if changes_data . length < 10
# Remove email adress in usernames
fields = fields . collect { | c | c . gsub ( %r{ <.+@.+> } , '' ) }
graph = SVG :: Graph :: BarHorizontal . new (
2015-10-19 14:03:08 +08:00
:height = > 400 ,
:width = > 600 ,
:fields = > fields ,
:stack = > :side ,
:scale_integers = > true ,
:show_data_values = > true ,
:rotate_y_labels = > false ,
:graph_title = > l ( :label_commits_per_author ) ,
:show_graph_title = > true
2014-09-15 10:58:14 +08:00
)
graph . add_data (
2015-10-19 14:03:08 +08:00
:data = > commits_data ,
:title = > l ( :label_revision_plural )
2014-09-15 10:58:14 +08:00
)
graph . add_data (
2015-10-19 14:03:08 +08:00
:data = > changes_data ,
:title = > l ( :label_change_plural )
2014-09-15 10:58:14 +08:00
)
graph . burn
end
2015-07-23 17:32:48 +08:00
2015-07-26 13:43:56 +08:00
# 用户最近一年的提交次数
2015-07-23 17:32:48 +08:00
def graph_author_commits_per_month ( repository )
2015-07-24 09:18:34 +08:00
@date_to = Date . today
2015-07-26 13:43:56 +08:00
@date_from = @date_to << 12
2015-07-24 09:47:28 +08:00
@date_from = Date . civil ( @date_from . year , @date_from . month , @date_from . day )
2015-07-24 09:18:34 +08:00
commits_by_author = Changeset . count ( :all , :group = > :committer ,
2015-10-19 14:03:08 +08:00
:conditions = > [ " #{ Changeset . table_name } .repository_id = ? AND #{ Changeset . table_name } .commit_date BETWEEN ? AND ? " , repository . id , @date_from , @date_to ] )
2015-07-26 13:43:56 +08:00
commits_by_author = commits_by_author . to_a . sort! { | x , y | x . last < = > y . last } . last ( 25 )
2015-07-24 09:18:34 +08:00
2015-07-23 17:32:48 +08:00
fields = commits_by_author . collect { | r | r . first }
commits_data = commits_by_author . collect { | r | r . last }
fields = fields + [ " " ] * ( 10 - fields . length ) if fields . length < 10
commits_data = commits_data + [ 0 ] * ( 10 - commits_data . length ) if commits_data . length < 10
# Remove email adress in usernames
fields = fields . collect { | c | c . gsub ( %r{ <.+@.+> } , '' ) }
graph = SVG :: Graph :: BarHorizontal . new (
:height = > 400 ,
:width = > 600 ,
:fields = > fields ,
:stack = > :side ,
:scale_integers = > true ,
:show_data_values = > true ,
:rotate_y_labels = > false ,
2015-07-26 13:43:56 +08:00
:graph_title = > l ( :label_author_commits_year ) ,
:show_graph_title = > true ,
:no_css = > true
2015-07-23 17:32:48 +08:00
)
graph . add_data (
:data = > commits_data ,
2015-07-26 14:35:41 +08:00
:title = > l ( :label_revision_commit_count )
2015-07-23 17:32:48 +08:00
)
graph . burn
end
2015-07-24 09:19:43 +08:00
# 用户最近六个月的提交次数
def author_commits_six_month ( repository )
@date_to = Date . today
@date_from = @date_to << 6
2015-07-24 09:47:28 +08:00
@date_from = Date . civil ( @date_from . year , @date_from . month , @date_from . day )
2015-07-24 09:19:43 +08:00
commits_by_author = Changeset . count ( :all , :group = > :committer ,
:conditions = > [ " #{ Changeset . table_name } .repository_id = ? AND #{ Changeset . table_name } .commit_date BETWEEN ? AND ? " , repository . id , @date_from , @date_to ] )
2015-07-26 14:12:26 +08:00
commits_by_author = commits_by_author . to_a . sort! { | x , y | x . last < = > y . last } . last ( 25 )
2015-07-24 09:19:43 +08:00
fields = commits_by_author . collect { | r | r . first }
commits_data = commits_by_author . collect { | r | r . last }
2015-07-24 17:40:43 +08:00
fields = fields + [ " " ] * ( 10 - fields . length ) if fields . length < 10
commits_data = commits_data + [ 0 ] * ( 10 - commits_data . length ) if commits_data . length < 10
# Remove email adress in usernames
fields = fields . collect { | c | c . gsub ( %r{ <.+@.+> } , '' ) }
graph = SVG :: Graph :: BarHorizontal . new (
:height = > 400 ,
:width = > 600 ,
:fields = > fields ,
:stack = > :side ,
:scale_integers = > true ,
:show_data_values = > true ,
:rotate_y_labels = > false ,
:graph_title = > l ( :label_author_commits_six_month ) ,
:show_graph_title = > true
)
graph . add_data (
:data = > commits_data ,
2015-07-26 14:35:41 +08:00
:title = > l ( :label_revision_commit_count )
2015-07-24 17:40:43 +08:00
)
graph . burn
end
# 最近六个月代码量统计
def author_code_six_month ( repository )
@date_to = Date . today
@date_from = @date_to << 6
@date_from = Date . civil ( @date_from . year , @date_from . month , @date_from . day )
commits_by_author = Changeset . count ( :group = > :committer , :conditions = > [ " #{ Changeset . table_name } .repository_id = ? AND #{ Changeset . table_name } .commit_date BETWEEN ? AND ? " , repository . id , @date_from , @date_to ] )
2015-07-26 14:15:25 +08:00
commits_by_author = commits_by_author . to_a . sort! { | x , y | x . last < = > y . last } . last ( 40 )
2015-07-24 17:40:43 +08:00
all_author = [ ]
commits_by_author . each do | cba |
all_author << cba . first
end
2015-07-25 00:24:59 +08:00
# all_author = all_author.collect {|c| c.gsub(%r{/ /<.+@.+>}, '') }
all_author = all_author . collect { | c | c . split . first }
2015-07-25 12:04:20 +08:00
commits_by_author = repository . commits ( all_author , " #{ @date_from } " , " #{ @date_to } " , repository . id == 150 ? " szzh " : 'master' )
2015-07-24 17:40:43 +08:00
fields = commits_by_author . collect { | r | r . first }
commits_data = commits_by_author . collect { | r | r . last }
2015-07-24 09:19:43 +08:00
fields = fields + [ " " ] * ( 10 - fields . length ) if fields . length < 10
commits_data = commits_data + [ 0 ] * ( 10 - commits_data . length ) if commits_data . length < 10
# Remove email adress in usernames
2015-07-24 23:36:24 +08:00
fields = fields . collect { | c | c . gsub ( %r{ <.+@.+> } , '' ) }
2015-07-24 09:19:43 +08:00
graph = SVG :: Graph :: BarHorizontal . new (
:height = > 400 ,
:width = > 600 ,
:fields = > fields ,
:stack = > :side ,
:scale_integers = > true ,
:show_data_values = > true ,
:rotate_y_labels = > false ,
2015-07-24 23:09:28 +08:00
:graph_title = > l ( :label_author_code_six_month ) ,
2015-07-24 09:19:43 +08:00
:show_graph_title = > true
)
graph . add_data (
:data = > commits_data ,
2015-07-26 13:43:56 +08:00
:title = > l ( :lable_revision_code_count )
2015-07-24 09:19:43 +08:00
)
graph . burn
end
2015-07-23 17:32:48 +08:00
2014-09-15 10:58:14 +08:00
def check_hidden_repo
project = Project . find ( params [ :id ] )
if ! User . current . member_of? ( project )
if project . hidden_repo
#render_403
end
end
rescue ActiveRecord :: RecordNotFound
render_404
end
end