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'
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
2014-09-15 10:58:14 +08:00
before_filter :find_project_by_project_id , :only = > [ :new , :create , :newrepo ]
before_filter :find_repository , :only = > [ :edit , :update , :destroy , :committers ]
2015-10-18 21:04:04 +08:00
before_filter :find_project_repository , :except = > [ :new , :create , :newcreate , :edit , :update , :destroy , :committers , :newrepo , :to_gitlab ]
2014-09-15 10:58:14 +08:00
before_filter :find_changeset , :only = > [ :revision , :add_related_issue , :remove_related_issue ]
2015-11-13 17:30:14 +08:00
before_filter :authorize , :except = > [ :newrepo , :newcreate , :fork , :to_gitlab , :forked ]
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
2015-11-23 16:51:12 +08:00
$g = Gitlab . client
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
2015-11-13 17:30:14 +08:00
def forked
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-04 15:49:05 +08:00
# 单个用户只能拥有一个名字一样的版本库, 否则不能fork
# if is_sigle_identifier?(User.current, @repository.identifier)
# REDO: 那些人有权限forked项目
g = Gitlab . client
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
# else
# flash[:notice] = l(:project_gitlab_fork_double_message)
# redirect_to settings_project_url(@project, :tab => 'repositories')
# end
2015-11-13 17:30:14 +08:00
end
2015-12-04 15:49:05 +08:00
end
# 判断用户是否已经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 ] )
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
redirect_to settings_project_url ( project )
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
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.
2015-05-13 11:46:19 +08:00
if ! User . current . member_of? ( @project )
if @project . hidden_repo
render_403
return - 1
end
end
2015-06-30 22:12:34 +08:00
2015-11-02 17:36:45 +08:00
# unless @repository.gitlab?
# # redirect_to to_gitlab_project_repository_path(@project, @repository)
# render :to_gitlab
# return
# end
2015-10-18 21:04:04 +08:00
2014-09-15 10:58:14 +08:00
#if( !User.current.member_of?(@project) || @project.hidden_repo)
@repository . fetch_changesets if Setting . autofetch_changesets? && @path . empty?
2015-08-01 18:48:55 +08:00
# :name, :path, :kind, :size, :lastrev, :changeset
2015-10-16 20:06:03 +08:00
@entries = @repository . entries ( @path , @rev )
2015-10-24 11:51:02 +08:00
# @trees = g.trees(project, @path)
2015-10-27 11:41:25 +08:00
@changeset = @repository . find_changeset_by_name ( @rev )
2014-09-15 10:58:14 +08:00
#@project_path_cut = RepositoriesHelper::PROJECT_PATH_CUT
#@ip = RepositoriesHelper::REPO_IP_ADDRESS
if request . xhr?
@entries ? render ( :partial = > 'dir_list_content' ) : render ( :nothing = > true )
else
#Modified by young
2015-10-19 14:03:08 +08:00
# (show_error_not_found; return) unless @entries
2015-10-29 14:20:23 +08:00
g = Gitlab . client
2015-11-24 10:12:21 +08:00
2015-11-23 21:07:43 +08:00
# count = 0
# (0..100).each do |page|
# if g.commits(@project.gpid,:page => page).count == 0
# break
# else
# count = count + g.commits(@project.gpid,:page => page).count
# end
# end
#add by hx
2015-11-23 19:48:20 +08:00
if g . commits ( @project . gpid , :page = > 25 ) . count == 0
count = count_commits ( @project . gpid , 0 , 25 )
elsif g . commits ( @project . gpid , :page = > 50 ) . count == 0
count = count_commits ( @project . gpid , 25 , 50 ) + 25 * 20
elsif g . commits ( @project . gpid , :page = > 75 ) . count == 0
count = count_commits ( @project . gpid , 50 , 75 ) + 50 * 20
elsif g . commits ( @project . gpid , :page = > 100 ) . count == 0
count = count_commits ( @project . gpid , 75 , 100 ) + 75 * 20
2015-11-23 21:07:43 +08:00
elsif g . commits ( @project . gpid , :page = > 125 ) . count == 0
2015-11-23 19:48:20 +08:00
count = count_commits ( @project . gpid , 100 , 125 ) + 100 * 20
2015-11-23 21:07:43 +08:00
elsif g . commits ( @project . gpid , :page = > 150 ) . count == 0
count = count_commits ( @project . gpid , 125 , 150 ) + 125 * 20
else
count = count_commits ( @project . gpid , 150 , 200 ) + 150 * 20
2015-11-23 19:48:20 +08:00
end
2015-11-23 16:51:12 +08:00
2015-11-03 10:52:32 +08:00
@changesets = g . commits ( @project . gpid )
2015-10-29 14:20:23 +08:00
# @changesets = @repository.latest_changesets(@path, @rev)
2015-10-29 15:56:41 +08:00
# @changesets_count = @repository.latest_changesets(@path, @rev).count
2015-11-03 17:19:19 +08:00
@changesets_all_count = count
2015-10-29 15:56:41 +08:00
@changesets_latest_coimmit = @changesets [ 0 ]
2014-09-15 10:58:14 +08:00
@properties = @repository . properties ( @path , @rev )
@repositories = @project . repositories
@course_tag = params [ :course ]
project_path_cut = RepositoriesHelper :: PROJECT_PATH_CUT
ip = RepositoriesHelper :: REPO_IP_ADDRESS
2015-10-30 16:26:51 +08:00
gitlab_address = Redmine :: Configuration [ 'gitlab_address' ]
2015-11-02 16:41:15 +08:00
if @repository . type . to_s == " Repository::Gitlab "
2015-10-30 17:45:44 +08:00
@repos_url = gitlab_address . to_s + " / " + @project . owner . to_s + " / " + @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
2014-09-15 10:58:14 +08:00
if @course_tag == 1
render :action = > 'show' , :layout = > 'base_courses'
else
render :action = > 'show' , :layout = > 'base_projects'
end
end
end
alias_method :browse , :show
2015-11-23 21:07:43 +08:00
#add by hx
2015-11-23 19:48:20 +08:00
def count_commits ( project_id , left , right )
count = 0
( left .. right ) . each do | page |
if $g . commits ( project_id , :page = > page ) . count == 0
break
else
count = count + $g . commits ( project_id , :page = > page ) . count
end
2015-11-23 16:51:12 +08:00
end
2015-11-23 19:48:20 +08:00
return count
2015-11-23 16:51:12 +08:00
end
2014-09-15 10:58:14 +08:00
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的类型减一在改回来
2015-11-18 16:11:51 +08:00
@commits = g . commits ( @project . gpid , page : ( params [ :page ] . to_i - 1 ) . to_s )
2015-11-19 14:59:26 +08:00
#页面传递必须要str类型,但是Paginator的初始化必须要num类型,需要类型转化
2015-11-19 14:42:37 +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 )
2015-10-24 11:51:02 +08:00
render :layout = > 'base_projects'
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
if is_raw ||
2015-10-19 14:03:08 +08:00
( @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
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
@project_id = params [ :id ]
@repository_id = @repository . identifier
2015-07-27 15:21:31 +08:00
# 提交次数统计
@status_commit_count = Changeset . count ( :conditions = > [ " #{ Changeset . table_name } .repository_id = ? " , @repository . id ] )
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
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
@rev = params [ :rev ] . blank? ? @repository . default_branch : params [ :rev ] . to_s . strip
@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