Elimina el plugin Redmine Git Hosting
Finalmente se descarta por los problemas de configuración y potencial brecha de seguridad al requerir acceso global al puerto ssh.
This commit is contained in:
parent
bdd66d941f
commit
0edadcfed8
494 changed files with 0 additions and 36768 deletions
|
@ -1,13 +0,0 @@
|
|||
module Gitolitable
|
||||
extend ActiveSupport::Concern
|
||||
include Gitolitable::Authorizations
|
||||
include Gitolitable::Cache
|
||||
include Gitolitable::Config
|
||||
include Gitolitable::Features
|
||||
include Gitolitable::Notifications
|
||||
include Gitolitable::Paths
|
||||
include Gitolitable::Permissions
|
||||
include Gitolitable::Urls
|
||||
include Gitolitable::Users
|
||||
include Gitolitable::Validations
|
||||
end
|
|
@ -1,89 +0,0 @@
|
|||
module Gitolitable
|
||||
module Authorizations
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# These are for repository Gitolite configuration
|
||||
|
||||
def git_daemon_available?
|
||||
User.anonymous.allowed_to?(:view_changesets, project) && git_daemon_enabled?
|
||||
end
|
||||
|
||||
|
||||
def git_web_available?
|
||||
User.anonymous.allowed_to?(:browse_repository, project) && smart_http_enabled?
|
||||
end
|
||||
|
||||
|
||||
def protected_branches_available?
|
||||
protected_branches_enabled? && project.active? && protected_branches.any?
|
||||
end
|
||||
|
||||
|
||||
def clonable_via_http?
|
||||
User.anonymous.allowed_to?(:view_changesets, project) || smart_http_enabled?
|
||||
end
|
||||
|
||||
|
||||
def pushable_via_http?
|
||||
https_access_enabled?
|
||||
end
|
||||
|
||||
|
||||
def git_notification_available?
|
||||
git_notification_enabled? && !mailing_list.empty?
|
||||
end
|
||||
|
||||
|
||||
# These are for repository URLs
|
||||
|
||||
def urls_are_viewable?
|
||||
RedmineGitHosting::Config.show_repositories_url? && User.current.allowed_to?(:view_changesets, project)
|
||||
end
|
||||
|
||||
|
||||
def ssh_access_available?
|
||||
git_ssh_enabled? && !git_annex_enabled? && User.current.allowed_to_commit?(self)
|
||||
end
|
||||
|
||||
|
||||
def https_access_available?
|
||||
https_access_enabled?
|
||||
end
|
||||
|
||||
|
||||
def http_access_available?
|
||||
http_access_enabled?
|
||||
end
|
||||
|
||||
|
||||
def git_access_available?
|
||||
(public_project? || public_repo?) && git_daemon_enabled?
|
||||
end
|
||||
|
||||
|
||||
def go_access_available?
|
||||
(public_project? || public_repo?) && smart_http_enabled? && git_go_enabled?
|
||||
end
|
||||
|
||||
|
||||
def git_annex_access_available?
|
||||
git_annex_enabled?
|
||||
end
|
||||
|
||||
|
||||
def downloadable?
|
||||
git_annex_enabled? ? false : User.current.allowed_to_download?(self)
|
||||
end
|
||||
|
||||
|
||||
def deletable?
|
||||
RedmineGitHosting::Config.delete_git_repositories?
|
||||
end
|
||||
|
||||
|
||||
def movable?
|
||||
!identifier.nil? && !identifier.empty?
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,90 +0,0 @@
|
|||
module Gitolitable
|
||||
module Cache
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
class << self
|
||||
|
||||
# Are repositories identifier unique?
|
||||
#
|
||||
def repo_ident_unique?
|
||||
RedmineGitHosting::Config.unique_repo_identifier?
|
||||
end
|
||||
|
||||
|
||||
# Translate repository path into a unique ID for use in caching of git commands.
|
||||
#
|
||||
def repo_path_to_git_cache_id(repo_path)
|
||||
repo = find_by_path(repo_path, loose: true)
|
||||
repo ? repo.git_cache_id : nil
|
||||
end
|
||||
|
||||
|
||||
# Parse a path of the form <proj1>/<proj2>/<proj3>/<repo> and return the specified
|
||||
# repository. If either 'repo_ident_unique?' is true or the <repo> is a project
|
||||
# identifier, just return the last component. Otherwise,
|
||||
# use the immediate parent (<proj3>) to try to identify the repo.
|
||||
#
|
||||
# Flags:
|
||||
# :loose => true : Try to identify corresponding repo even if path is not quite correct
|
||||
#
|
||||
# Note that the :loose flag is used when interpreting the contents of the
|
||||
# repository. If switching back and forth between the "repo_ident_unique?"
|
||||
# form, it will still identify the repository (as long as there are not more than
|
||||
# one repo with the same identifier.
|
||||
#
|
||||
# Example of data captured by regex :
|
||||
# <MatchData "test/test2/test3/test4/test5.git" 1:"test4/" 2:"test4" 3:"test5" 4:".git">
|
||||
# <MatchData "blabla2.git" 1:nil 2:nil 3:"blabla2" 4:".git">
|
||||
#
|
||||
def find_by_path(path, flags = {})
|
||||
parseit = path.match(/\A.*?(([^\/]+)\/)?([^\/]+?)(\.git)?\z/)
|
||||
return nil if parseit.nil?
|
||||
|
||||
project = Project.find_by_identifier(parseit[3])
|
||||
|
||||
# return default or first repo with blank identifier (or first Git repo--very rare?)
|
||||
if project
|
||||
project.repository || project.repo_blank_ident || project.gitolite_repos.first
|
||||
|
||||
elsif repo_ident_unique? || flags[:loose] && parseit[2].nil?
|
||||
find_by_identifier(parseit[3])
|
||||
|
||||
elsif parseit[2]
|
||||
project = Project.find_by_identifier(parseit[2])
|
||||
|
||||
if project.nil?
|
||||
find_by_identifier(parseit[3])
|
||||
else
|
||||
find_by_identifier_and_project_id(parseit[3], project.id) || (flags[:loose] && find_by_identifier(parseit[3]))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# If repositories identifiers are unique, identifier forms a unique label,
|
||||
# else use directory notation: <project identifier>/<repo identifier>
|
||||
#
|
||||
def git_cache_id
|
||||
if identifier.blank?
|
||||
# Should only happen with one repo/project (the default)
|
||||
project.identifier
|
||||
elsif self.class.repo_ident_unique?
|
||||
identifier
|
||||
else
|
||||
"#{project.identifier}/#{identifier}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Note: RedmineGitHosting::Cache doesn't know about repository object, it only knows *git_cache_id*.
|
||||
#
|
||||
def empty_cache!
|
||||
RedmineGitHosting::Cache.clear_cache_for_repository(git_cache_id)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,85 +0,0 @@
|
|||
module Gitolitable
|
||||
module Config
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def git_config
|
||||
repo_conf = {}
|
||||
|
||||
# This is needed for all Redmine repositories
|
||||
repo_conf['redminegitolite.projectid'] = project.identifier.to_s
|
||||
repo_conf['redminegitolite.repositoryid'] = identifier || ''
|
||||
repo_conf['redminegitolite.repositorykey'] = gitolite_hook_key
|
||||
|
||||
if project.active?
|
||||
repo_conf['http.uploadpack'] = clonable_via_http?.to_s
|
||||
repo_conf['http.receivepack'] = pushable_via_http?.to_s
|
||||
|
||||
if git_notification_available?
|
||||
repo_conf['multimailhook.enabled'] = 'true'
|
||||
repo_conf['multimailhook.mailinglist'] = mailing_list.join(', ')
|
||||
repo_conf['multimailhook.from'] = sender_address
|
||||
repo_conf['multimailhook.emailPrefix'] = email_prefix
|
||||
else
|
||||
repo_conf['multimailhook.enabled'] = 'false'
|
||||
end
|
||||
|
||||
git_config_keys.each do |git|
|
||||
repo_conf[git.key] = git.value
|
||||
end if git_config_keys.any?
|
||||
|
||||
else
|
||||
# Disable repository
|
||||
repo_conf['http.uploadpack'] = 'false'
|
||||
repo_conf['http.receivepack'] = 'false'
|
||||
repo_conf['multimailhook.enabled'] = 'false'
|
||||
end
|
||||
|
||||
repo_conf
|
||||
end
|
||||
|
||||
|
||||
def gitolite_options
|
||||
repo_conf = {}
|
||||
|
||||
git_option_keys.each do |option|
|
||||
repo_conf[option.key] = option.value
|
||||
end if git_option_keys.any?
|
||||
|
||||
repo_conf
|
||||
end
|
||||
|
||||
|
||||
def owner
|
||||
{ name: Setting['app_title'], email: Setting['mail_from'] }
|
||||
end
|
||||
|
||||
|
||||
def github_payload
|
||||
{
|
||||
repository: {
|
||||
owner: owner,
|
||||
description: project.description,
|
||||
fork: false,
|
||||
forks: 0,
|
||||
homepage: project.homepage,
|
||||
name: redmine_name,
|
||||
open_issues: project.issues.open.length,
|
||||
watchers: 0,
|
||||
private: !project.is_public,
|
||||
url: repository_url
|
||||
},
|
||||
pusher: owner,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def repository_url
|
||||
Rails.application.routes.url_helpers.url_for(
|
||||
controller: 'repositories', action: 'show',
|
||||
id: project, repository_id: identifier_param,
|
||||
only_path: false, host: Setting['host_name'], protocol: Setting['protocol']
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,97 +0,0 @@
|
|||
module Gitolitable
|
||||
module Features
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# Always true to force repository fetch_changesets.
|
||||
def report_last_commit
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
# Always true to force repository fetch_changesets.
|
||||
def extra_report_last_commit
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
def git_default_branch
|
||||
extra[:default_branch]
|
||||
end
|
||||
|
||||
|
||||
def gitolite_hook_key
|
||||
extra[:key]
|
||||
end
|
||||
|
||||
|
||||
def git_daemon_enabled?
|
||||
extra[:git_daemon]
|
||||
end
|
||||
|
||||
|
||||
def git_annex_enabled?
|
||||
extra[:git_annex]
|
||||
end
|
||||
|
||||
|
||||
def git_notification_enabled?
|
||||
extra[:git_notify]
|
||||
end
|
||||
|
||||
|
||||
def git_ssh_enabled?
|
||||
extra[:git_ssh]
|
||||
end
|
||||
|
||||
|
||||
def git_go_enabled?
|
||||
extra[:git_go]
|
||||
end
|
||||
|
||||
|
||||
def https_access_enabled?
|
||||
extra[:git_https]
|
||||
end
|
||||
|
||||
|
||||
def http_access_enabled?
|
||||
extra[:git_http]
|
||||
end
|
||||
|
||||
|
||||
def smart_http_enabled?
|
||||
https_access_enabled? || http_access_enabled?
|
||||
end
|
||||
|
||||
|
||||
def only_https_access_enabled?
|
||||
https_access_enabled? && !http_access_enabled?
|
||||
end
|
||||
|
||||
|
||||
def only_http_access_enabled?
|
||||
http_access_enabled? && !https_access_enabled?
|
||||
end
|
||||
|
||||
|
||||
def protected_branches_enabled?
|
||||
extra[:protected_branch]
|
||||
end
|
||||
|
||||
|
||||
def public_project?
|
||||
project.is_public?
|
||||
end
|
||||
|
||||
|
||||
def public_repo?
|
||||
extra[:public_repo]
|
||||
end
|
||||
|
||||
|
||||
def urls_order
|
||||
extra[:urls_order]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,43 +0,0 @@
|
|||
module Gitolitable
|
||||
module Notifications
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def mailing_list
|
||||
default_list + global_include_list - global_exclude_list
|
||||
end
|
||||
|
||||
|
||||
def default_list
|
||||
watcher_users.map(&:email_address).map(&:address)
|
||||
end
|
||||
|
||||
|
||||
def global_include_list
|
||||
RedmineGitHosting::Config.gitolite_notify_global_include
|
||||
end
|
||||
|
||||
|
||||
def global_exclude_list
|
||||
RedmineGitHosting::Config.gitolite_notify_global_exclude
|
||||
end
|
||||
|
||||
|
||||
def sender_address
|
||||
if extra.notification_sender.nil? || extra.notification_sender.empty?
|
||||
RedmineGitHosting::Config.gitolite_notify_global_sender_address
|
||||
else
|
||||
extra.notification_sender
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def email_prefix
|
||||
if extra.notification_prefix.nil? || extra.notification_prefix.empty?
|
||||
RedmineGitHosting::Config.gitolite_notify_global_prefix
|
||||
else
|
||||
extra.notification_prefix
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,94 +0,0 @@
|
|||
module Gitolitable
|
||||
module Paths
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
||||
# This is the repository path from Redmine point of view.
|
||||
# It is used to build HTTP(s) urls (including GoLang url).
|
||||
# It doesn't contain references to internal directories like *gitolite_global_storage_dir* or *gitolite_redmine_storage_dir*
|
||||
# to stay abstract from the real repository location.
|
||||
# In this case, the real repository path is deduced from the path given thanks to the *find_by_path* method.
|
||||
#
|
||||
# Example : blabla/test-blabla/uuuuuuuuuuu/oooooo
|
||||
#
|
||||
# Call File.expand_path to add then remove heading /
|
||||
#
|
||||
def redmine_repository_path
|
||||
File.expand_path(File.join('./', get_full_parent_path, git_cache_id), '/')[1..-1]
|
||||
end
|
||||
|
||||
|
||||
# This is the Gitolite repository identifier as it should appear in Gitolite config file.
|
||||
# Example : redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo
|
||||
# (with 'redmine' a subdir of the Gitolite storage directory)
|
||||
#
|
||||
# Call File.expand_path to add then remove heading /
|
||||
#
|
||||
def gitolite_repository_name
|
||||
File.expand_path(File.join('./', RedmineGitHosting::Config.gitolite_redmine_storage_dir, get_full_parent_path, git_cache_id), '/')[1..-1]
|
||||
end
|
||||
|
||||
|
||||
# The Gitolite repository identifier with the .git extension.
|
||||
# Example : redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo.git
|
||||
#
|
||||
def gitolite_repository_name_with_extension
|
||||
"#{gitolite_repository_name}.git"
|
||||
end
|
||||
|
||||
|
||||
# This is the relative path to the Gitolite repository.
|
||||
# Example : repositories/redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo.git
|
||||
# (with 'repositories' the Gitolite storage directory).
|
||||
#
|
||||
def gitolite_repository_path
|
||||
File.join(RedmineGitHosting::Config.gitolite_global_storage_dir, gitolite_repository_name_with_extension)
|
||||
end
|
||||
|
||||
|
||||
# This is the full absolute path to the Gitolite repository.
|
||||
# Example : /home/git/repositories/redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo.git
|
||||
#
|
||||
def gitolite_full_repository_path
|
||||
File.join(RedmineGitHosting::Config.gitolite_home_dir, gitolite_repository_path)
|
||||
end
|
||||
|
||||
|
||||
# A syntaxic sugar used to move repository from a location to an other
|
||||
# Example : repositories/blabla/test-blabla/uuuuuuuuuuu/oooooo
|
||||
#
|
||||
def new_repository_name
|
||||
gitolite_repository_name
|
||||
end
|
||||
|
||||
|
||||
# Used to move repository from a location to an other.
|
||||
# At this point repository url still points to the old location but
|
||||
# it contains the Gitolite storage directory in its path and the '.git' extension.
|
||||
# Strip them to get the old repository name.
|
||||
# Example :
|
||||
# before : repositories/redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo.git
|
||||
# after : redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo
|
||||
#
|
||||
def old_repository_name
|
||||
url.gsub(RedmineGitHosting::Config.gitolite_global_storage_dir, '').gsub('.git', '')
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def get_full_parent_path
|
||||
return '' if !RedmineGitHosting::Config.hierarchical_organisation?
|
||||
parent_parts = []
|
||||
p = project
|
||||
while p.parent
|
||||
parent_id = p.parent.identifier.to_s
|
||||
parent_parts.unshift(parent_id)
|
||||
p = p.parent
|
||||
end
|
||||
parent_parts.join('/')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,66 +0,0 @@
|
|||
module Gitolitable
|
||||
module Permissions
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def build_gitolite_permissions(old_perms = {})
|
||||
permissions_builder.build(self, gitolite_users, old_perms)
|
||||
end
|
||||
|
||||
|
||||
# We assume here that ':gitolite_config_file' is different than 'gitolite.conf'
|
||||
# like 'redmine.conf' with 'include "redmine.conf"' in 'gitolite.conf'.
|
||||
# This way, we know that all repos in this file are managed by Redmine so we
|
||||
# don't need to backup users
|
||||
#
|
||||
def backup_gitolite_permissions(current_permissions)
|
||||
if protected_branches_available? || RedmineGitHosting::Config.gitolite_identifier_prefix == ''
|
||||
{}
|
||||
else
|
||||
extract_permissions(current_permissions)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def permissions_builder
|
||||
if protected_branches_available?
|
||||
PermissionsBuilder::ProtectedBranches
|
||||
else
|
||||
PermissionsBuilder::Standard
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
SKIP_USERS = ['gitweb', 'daemon', 'DUMMY_REDMINE_KEY', 'REDMINE_ARCHIVED_PROJECT', 'REDMINE_CLOSED_PROJECT']
|
||||
|
||||
|
||||
def extract_permissions(current_permissions)
|
||||
old_permissions = {}
|
||||
|
||||
current_permissions.each do |perm, branch_settings|
|
||||
old_permissions[perm] = {}
|
||||
|
||||
branch_settings.each do |branch, user_list|
|
||||
next if user_list.empty?
|
||||
|
||||
new_user_list = []
|
||||
|
||||
user_list.each do |user|
|
||||
# ignore these users
|
||||
next if SKIP_USERS.include?(user)
|
||||
|
||||
# backup users that are not Redmine users
|
||||
new_user_list.push(user) if !user.include?(RedmineGitHosting::Config.gitolite_identifier_prefix)
|
||||
end
|
||||
|
||||
old_permissions[perm][branch] = new_user_list if new_user_list.any?
|
||||
end
|
||||
end
|
||||
|
||||
old_permissions
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,122 +0,0 @@
|
|||
module Gitolitable
|
||||
module Urls
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def http_user_login
|
||||
User.current.anonymous? ? '' : "#{User.current.login}@"
|
||||
end
|
||||
|
||||
|
||||
def git_access_path
|
||||
gitolite_repository_name_with_extension
|
||||
end
|
||||
|
||||
|
||||
def http_access_path
|
||||
"#{RedmineGitHosting::Config.http_server_subdir}#{redmine_repository_path}.git"
|
||||
end
|
||||
|
||||
|
||||
def go_access_path
|
||||
"go/#{redmine_repository_path}"
|
||||
end
|
||||
|
||||
|
||||
def ssh_url
|
||||
"ssh://#{RedmineGitHosting::Config.gitolite_user}@#{RedmineGitHosting::Config.ssh_server_domain}/#{git_access_path}"
|
||||
end
|
||||
|
||||
|
||||
def git_url
|
||||
"git://#{RedmineGitHosting::Config.ssh_server_domain}/#{git_access_path}"
|
||||
end
|
||||
|
||||
|
||||
def http_url
|
||||
"http://#{http_user_login}#{RedmineGitHosting::Config.http_root_url}/#{http_access_path}"
|
||||
end
|
||||
|
||||
|
||||
def https_url
|
||||
"https://#{http_user_login}#{RedmineGitHosting::Config.https_root_url}/#{http_access_path}"
|
||||
end
|
||||
|
||||
|
||||
def git_annex_url
|
||||
"#{RedmineGitHosting::Config.gitolite_user}@#{RedmineGitHosting::Config.ssh_server_domain}:#{git_access_path}"
|
||||
end
|
||||
|
||||
|
||||
# This is the url used by Go to clone repository
|
||||
#
|
||||
def go_access_url
|
||||
return '' if !smart_http_enabled?
|
||||
return https_url if https_access_available?
|
||||
return http_url if http_access_available?
|
||||
end
|
||||
|
||||
|
||||
# This is the url to add in Go files
|
||||
#
|
||||
def go_url
|
||||
return '' if !smart_http_enabled?
|
||||
return "#{RedmineGitHosting::Config.https_root_url}/#{go_access_path}" if https_access_available?
|
||||
return "#{RedmineGitHosting::Config.http_root_url}/#{go_access_path}" if http_access_available?
|
||||
end
|
||||
|
||||
|
||||
def ssh_access
|
||||
{ url: ssh_url, committer: User.current.allowed_to_commit?(self).to_s }
|
||||
end
|
||||
|
||||
|
||||
## Unsecure channels (clear password), commit is disabled
|
||||
def http_access
|
||||
{ url: http_url, committer: 'false' }
|
||||
end
|
||||
|
||||
|
||||
def https_access
|
||||
{ url: https_url, committer: User.current.allowed_to_commit?(self).to_s }
|
||||
end
|
||||
|
||||
|
||||
def git_access
|
||||
{ url: git_url, committer: 'false' }
|
||||
end
|
||||
|
||||
|
||||
def git_annex_access
|
||||
{ url: git_annex_url, committer: User.current.allowed_to_commit?(self).to_s }
|
||||
end
|
||||
|
||||
|
||||
def go_access
|
||||
{ url: go_url, committer: 'false' }
|
||||
end
|
||||
|
||||
|
||||
def available_urls
|
||||
hash = {}
|
||||
hash[:ssh] = ssh_access if ssh_access_available?
|
||||
hash[:https] = https_access if https_access_available?
|
||||
hash[:http] = http_access if http_access_available?
|
||||
hash[:git] = git_access if git_access_available?
|
||||
hash[:go] = go_access if go_access_available?
|
||||
hash[:git_annex] = git_annex_access if git_annex_access_available?
|
||||
hash
|
||||
end
|
||||
|
||||
|
||||
def available_urls_sorted
|
||||
return available_urls if urls_order.nil? || urls_order.empty?
|
||||
hash = {}
|
||||
urls_order.each do |url|
|
||||
next if !available_urls[url.to_sym]
|
||||
hash[url.to_sym] = available_urls[url.to_sym]
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,109 +0,0 @@
|
|||
module Gitolitable
|
||||
module Users
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def gitolite_users
|
||||
if project.active?
|
||||
users_for_active_project
|
||||
elsif project.archived?
|
||||
users_for_archived_project
|
||||
else
|
||||
users_for_closed_project
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def users_for_active_project
|
||||
data = {}
|
||||
data[:rewind_users] = rewind_users + rewind_deploy_users
|
||||
data[:write_users] = write_users
|
||||
data[:read_users] = read_users + read_deploy_users
|
||||
data[:developer_team] = developer_team
|
||||
data[:all_read] = all_users
|
||||
|
||||
# Add other users
|
||||
data[:read_users] << 'DUMMY_REDMINE_KEY' if read_users.empty? && write_users.empty? && rewind_users.empty?
|
||||
data[:read_users] << 'gitweb' if git_web_available?
|
||||
data[:read_users] << 'daemon' if git_daemon_available?
|
||||
|
||||
# Return users
|
||||
data
|
||||
end
|
||||
|
||||
|
||||
def users_for_archived_project
|
||||
data = {}
|
||||
data[:read_users] = ['REDMINE_ARCHIVED_PROJECT']
|
||||
data
|
||||
end
|
||||
|
||||
|
||||
def users_for_closed_project
|
||||
data = {}
|
||||
data[:read_users] = all_users
|
||||
data[:read_users] << 'REDMINE_CLOSED_PROJECT'
|
||||
data
|
||||
end
|
||||
|
||||
|
||||
def users
|
||||
project.users_available
|
||||
end
|
||||
|
||||
|
||||
def rewind_users
|
||||
@rewind_users ||= users.select { |u| u.allowed_to?(:manage_repository, project) }.map { |u| u.gitolite_identifier }.sort
|
||||
end
|
||||
|
||||
|
||||
def write_users
|
||||
@write_users ||= users.select { |u| u.allowed_to?(:commit_access, project) }.map { |u| u.gitolite_identifier }.sort - rewind_users
|
||||
end
|
||||
|
||||
|
||||
def read_users
|
||||
@read_users ||= users.select { |u| u.allowed_to?(:view_changesets, project) }.map { |u| u.gitolite_identifier }.sort - rewind_users - write_users
|
||||
end
|
||||
|
||||
|
||||
def developer_team
|
||||
@developer_team ||= (rewind_users + write_users).sort
|
||||
end
|
||||
|
||||
|
||||
def all_users
|
||||
@all_users ||= (rewind_users + write_users + read_users).sort
|
||||
end
|
||||
|
||||
|
||||
def rewind_deploy_users
|
||||
deploy_users_for_keys(rewind_deploy_keys)
|
||||
end
|
||||
|
||||
|
||||
def read_deploy_users
|
||||
deploy_users_for_keys(read_deploy_keys)
|
||||
end
|
||||
|
||||
|
||||
def rewind_deploy_keys
|
||||
deploy_keys_by_perm('RW+')
|
||||
end
|
||||
|
||||
|
||||
def read_deploy_keys
|
||||
deploy_keys_by_perm('R')
|
||||
end
|
||||
|
||||
|
||||
def deploy_keys_by_perm(perm)
|
||||
deployment_credentials.active.select { |cred| cred.perm == perm }
|
||||
end
|
||||
|
||||
|
||||
def deploy_users_for_keys(keys)
|
||||
keys.map { |cred| cred.gitolite_public_key.owner }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,122 +0,0 @@
|
|||
module Gitolitable
|
||||
module Validations
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
# Set URL ourself as relative path.
|
||||
#
|
||||
before_validation :set_git_urls
|
||||
|
||||
# Make sure that identifier does not match Gitolite Admin repository
|
||||
#
|
||||
validates_exclusion_of :identifier, in: %w(gitolite-admin)
|
||||
|
||||
# Place additional constraints on repository identifiers
|
||||
# because of multi repos
|
||||
#
|
||||
validate :additional_constraints_on_identifier
|
||||
validate :identifier_dont_change
|
||||
validate :default_repository_has_identifier
|
||||
|
||||
class << self
|
||||
|
||||
# Build a hash of repository identifier :
|
||||
# <repo_1_identifier> => 1
|
||||
# <repo_2_identifier> => 1
|
||||
# etc...
|
||||
# If the same repository identifier is found many times, increment the corresponding counter.
|
||||
# Repository identifiers are unique if all values of the hash are 1.
|
||||
#
|
||||
def identifiers_to_hash
|
||||
self.all.map(&:identifier).inject(Hash.new(0)) do |h, x|
|
||||
h[x] += 1 unless x.blank?
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def have_duplicated_identifier?
|
||||
(identifiers_to_hash.values.max || 0) > 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def exists_in_gitolite?
|
||||
RedmineGitHosting::Commands.sudo_dir_exists?(gitolite_repository_path)
|
||||
end
|
||||
|
||||
|
||||
def empty_in_gitolite?
|
||||
RedmineGitHosting::Commands.sudo_repository_empty?(gitolite_repository_path)
|
||||
end
|
||||
|
||||
|
||||
def git_objects_count
|
||||
RedmineGitHosting::Commands.sudo_git_objects_count(File.join(gitolite_repository_path, 'objects'))
|
||||
end
|
||||
|
||||
|
||||
def empty?
|
||||
extra_info.nil? || (!extra_info.has_key?('heads') && !extra_info.has_key?('branches'))
|
||||
end
|
||||
|
||||
|
||||
def data_for_destruction
|
||||
{
|
||||
repo_name: gitolite_repository_name,
|
||||
repo_path: gitolite_full_repository_path,
|
||||
delete_repository: deletable?,
|
||||
git_cache_id: git_cache_id
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
# Set up git urls for new repositories
|
||||
#
|
||||
def set_git_urls
|
||||
self.url = gitolite_repository_path if self.url.blank?
|
||||
self.root_url = self.url if self.root_url.blank?
|
||||
end
|
||||
|
||||
|
||||
# Check several aspects of repository identifier (only for Redmine 1.4+)
|
||||
# 1) cannot equal identifier of any project
|
||||
# 2) if repo_ident_unique? make sure that repo identifier is globally unique
|
||||
# 3) cannot make this repo the default if there will be some other repo with blank identifier
|
||||
#
|
||||
def additional_constraints_on_identifier
|
||||
if !identifier.blank? && (new_record? || identifier_changed?)
|
||||
errors.add(:identifier, :cannot_equal_project) if Project.find_by_identifier(identifier)
|
||||
|
||||
# See if a repo for another project has the same identifier (existing validations already check for current project)
|
||||
errors.add(:identifier, :taken) if self.class.repo_ident_unique? && Repository.where("identifier = ? and project_id <> ?", identifier, project.id).any?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Make sure identifier hasn't changed. Allow null and blank
|
||||
# Note that simply using identifier_changed doesn't seem to work
|
||||
# if the identifier was "NULL" but the new identifier is ""
|
||||
#
|
||||
def identifier_dont_change
|
||||
return if new_record?
|
||||
errors.add(:identifier, :cannot_change) if (identifier_was.blank? && !identifier.blank?) || (!identifier_was.blank? && identifier_changed?)
|
||||
end
|
||||
|
||||
|
||||
# Need to make sure that we don't take the default slot away from a sibling repo with blank identifier
|
||||
#
|
||||
def default_repository_has_identifier
|
||||
if project && (is_default? || set_as_default?)
|
||||
possibles = Repository.where("project_id = ? and (identifier = '' or identifier is null)", project.id)
|
||||
errors.add(:base, :blank_default_exists) if possibles.any? && (new_record? || possibles.detect { |x| x.id != id })
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
class GitCache < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
|
||||
CACHE_ADAPTERS = [%w[Database database],
|
||||
%w[Memcached memcached],
|
||||
%w[Redis redis]].freeze
|
||||
|
||||
## Attributes
|
||||
safe_attributes 'repo_identifier', 'command', 'command_output'
|
||||
|
||||
## Validations
|
||||
validates :repo_identifier, presence: true
|
||||
validates :command, presence: true
|
||||
validates :command_output, presence: true
|
||||
|
||||
class << self
|
||||
def adapters
|
||||
CACHE_ADAPTERS.map(&:last)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
class GithubComment < ActiveRecord::Base
|
||||
|
||||
## Relations
|
||||
belongs_to :journal
|
||||
|
||||
## Validations
|
||||
validates :github_id, presence: true
|
||||
validates :journal_id, presence: true, uniqueness: { scope: :github_id }
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
class GithubIssue < ActiveRecord::Base
|
||||
|
||||
## Relations
|
||||
belongs_to :issue
|
||||
|
||||
## Validations
|
||||
validates :github_id, presence: true
|
||||
validates :issue_id, presence: true, uniqueness: { scope: :github_id }
|
||||
end
|
|
@ -1,202 +0,0 @@
|
|||
class GitolitePublicKey < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
|
||||
TITLE_LENGTH_LIMIT = 60
|
||||
|
||||
KEY_TYPE_USER = 0
|
||||
KEY_TYPE_DEPLOY = 1
|
||||
|
||||
## Attributes
|
||||
safe_attributes 'title', 'key', 'key_type', 'delete_when_unused'
|
||||
|
||||
## Relations
|
||||
belongs_to :user
|
||||
has_many :repository_deployment_credentials, dependent: :destroy
|
||||
|
||||
## Validations
|
||||
validates :user_id, presence: true
|
||||
|
||||
validates :title, presence: true, uniqueness: { case_sensitive: false, scope: :user_id },
|
||||
length: { maximum: TITLE_LENGTH_LIMIT }, format: /\A[a-z0-9_\-]*\z/i
|
||||
|
||||
validates :identifier, presence: true, uniqueness: { case_sensitive: false, scope: :user_id }
|
||||
validates :key, presence: true
|
||||
validates :key_type, presence: true, numericality: { only_integer: true },
|
||||
inclusion: { in: [KEY_TYPE_USER, KEY_TYPE_DEPLOY] }
|
||||
|
||||
validate :has_not_been_changed
|
||||
validate :key_correctness
|
||||
validate :key_not_admin
|
||||
validate :key_uniqueness
|
||||
|
||||
## Scopes
|
||||
scope :user_key, -> { where(key_type: KEY_TYPE_USER) }
|
||||
scope :deploy_key, -> { where(key_type: KEY_TYPE_DEPLOY) }
|
||||
|
||||
## Callbacks
|
||||
before_validation :strip_whitespace
|
||||
before_validation :remove_control_characters
|
||||
|
||||
before_validation :set_identifier
|
||||
before_validation :set_fingerprint
|
||||
|
||||
def key_type_as_string
|
||||
user_key? ? 'user_key' : 'deploy_key'
|
||||
end
|
||||
|
||||
def to_s
|
||||
title
|
||||
end
|
||||
|
||||
def data_for_destruction
|
||||
{ title: identifier, key: key, location: location, owner: owner }
|
||||
end
|
||||
|
||||
# Returns the path to this key under the gitolite keydir
|
||||
# resolves to <user.gitolite_identifier>/<location>/<owner>.pub
|
||||
#
|
||||
# tile: test-key
|
||||
# identifier: redmine_admin_1@redmine_test_key
|
||||
# identifier: redmine_admin_1@redmine_deploy_key_1
|
||||
#
|
||||
#
|
||||
# keydir/
|
||||
# ├── redmine_git_hosting
|
||||
# │ └── redmine_admin_1
|
||||
# │ ├── redmine_test_key
|
||||
# │ │ └── redmine_admin_1.pub
|
||||
# │ ├── redmine_deploy_key_1
|
||||
# │ │ └── redmine_admin_1.pub
|
||||
# │ └── redmine_deploy_key_2
|
||||
# │ └── redmine_admin_1.pub
|
||||
# └── redmine_gitolite_admin_id_rsa.pub
|
||||
#
|
||||
#
|
||||
# The root folder for this user is the user's identifier
|
||||
# for logical grouping of their keys, which are organized
|
||||
# by their title in subfolders.
|
||||
#
|
||||
# This is due to the new gitolite multi-keys organization
|
||||
# using folders. See https://gitolite.com/gitolite/users.html
|
||||
def gitolite_path
|
||||
File.join('keydir', RedmineGitHosting::Config.gitolite_key_subdir, user.gitolite_identifier, location, owner) + '.pub'
|
||||
end
|
||||
|
||||
# Make sure that current identifier is consistent with current user login.
|
||||
# This method explicitly overrides the static nature of the identifier
|
||||
def reset_identifiers(opts = {})
|
||||
# Fix identifier
|
||||
self.identifier = nil
|
||||
self.fingerprint = nil
|
||||
|
||||
self.identifier = GitolitePublicKeys::GenerateIdentifier.call(self, user, opts)
|
||||
set_fingerprint
|
||||
|
||||
# Need to override the "never change identifier" constraint
|
||||
save(validate: false)
|
||||
end
|
||||
|
||||
# Key type checking functions
|
||||
def user_key?
|
||||
key_type == KEY_TYPE_USER
|
||||
end
|
||||
|
||||
def deploy_key?
|
||||
key_type == KEY_TYPE_DEPLOY
|
||||
end
|
||||
|
||||
def owner
|
||||
identifier.split('@')[0]
|
||||
end
|
||||
|
||||
def location
|
||||
identifier.split('@')[1]
|
||||
end
|
||||
|
||||
def type
|
||||
key.split(' ')[0]
|
||||
end
|
||||
|
||||
def blob
|
||||
key.split(' ')[1]
|
||||
end
|
||||
|
||||
def email
|
||||
key.split(' ')[2]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Strip leading and trailing whitespace
|
||||
# Don't mess with existing keys (since cannot change key text anyway)
|
||||
#
|
||||
def strip_whitespace
|
||||
return unless new_record?
|
||||
|
||||
self.title = title.strip rescue ''
|
||||
self.key = key.strip rescue ''
|
||||
end
|
||||
|
||||
# Remove control characters from key
|
||||
# Don't mess with existing keys (since cannot change key text anyway)
|
||||
#
|
||||
def remove_control_characters
|
||||
return unless new_record?
|
||||
|
||||
self.key = RedmineGitHosting::Utils::Ssh.sanitize_ssh_key(key)
|
||||
end
|
||||
|
||||
# Returns the unique identifier for this key based on the key_type
|
||||
#
|
||||
# For user public keys, this simply is the user's gitolite_identifier.
|
||||
# For deployment keys, we use an incrementing number.
|
||||
#
|
||||
def set_identifier
|
||||
return nil if user_id.nil?
|
||||
|
||||
self.identifier ||= GitolitePublicKeys::GenerateIdentifier.call(self, user)
|
||||
end
|
||||
|
||||
def set_fingerprint
|
||||
self.fingerprint = RedmineGitHosting::Utils::Ssh.ssh_fingerprint(key)
|
||||
rescue RedmineGitHosting::Error::InvalidSshKey => e
|
||||
errors.add(:key, :corrupted)
|
||||
end
|
||||
|
||||
def has_not_been_changed
|
||||
return if new_record?
|
||||
|
||||
%w[identifier key user_id key_type title fingerprint].each do |attribute|
|
||||
method = "#{attribute}_changed?"
|
||||
errors.add(attribute, :cannot_change) if send(method)
|
||||
end
|
||||
end
|
||||
|
||||
# Test correctness of fingerprint from output
|
||||
# and general ssh-(r|d|ecd)sa <key> <id> structure
|
||||
#
|
||||
def key_correctness
|
||||
return false if key.nil?
|
||||
|
||||
key.match(/^(\S+)\s+(\S+)/) && (fingerprint =~ /^(\w{2}:?)+$/i)
|
||||
end
|
||||
|
||||
def key_not_admin
|
||||
errors.add(:key, :taken_by_gitolite_admin) if fingerprint == RedmineGitHosting::Config.gitolite_ssh_public_key_fingerprint
|
||||
end
|
||||
|
||||
def key_uniqueness
|
||||
return unless new_record?
|
||||
|
||||
existing = GitolitePublicKey.find_by_fingerprint(fingerprint)
|
||||
return unless existing
|
||||
|
||||
if existing.user == User.current
|
||||
errors.add(:key, :taken_by_you, name: existing.title)
|
||||
elsif User.current.admin?
|
||||
errors.add(:key, :taken_by_other, login: existing.user.login, name: existing.title)
|
||||
else
|
||||
errors.add(:key, :taken_by_someone)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
class ProtectedBranchesMember < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
|
||||
## Attributes
|
||||
safe_attributes 'principal_id', 'inherited_by'
|
||||
|
||||
## Relations
|
||||
belongs_to :protected_branch, class_name: 'RepositoryProtectedBranche'
|
||||
belongs_to :principal
|
||||
|
||||
## Callbacks
|
||||
after_destroy :remove_dependent_objects
|
||||
|
||||
private
|
||||
|
||||
def remove_dependent_objects
|
||||
return unless principal.class.name == 'Group'
|
||||
|
||||
principal.users.each do |user|
|
||||
member = self.class.find_by_principal_id_and_inherited_by(user.id, principal.id)
|
||||
member.destroy! unless member.nil?
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,74 +0,0 @@
|
|||
require_dependency 'redmine/scm/adapters/xitolite_adapter'
|
||||
|
||||
class Repository::Xitolite < Repository::Git
|
||||
# Include Gitolitable concern
|
||||
include Gitolitable
|
||||
|
||||
# Virtual attributes
|
||||
attr_accessor :create_readme
|
||||
attr_accessor :enable_git_annex
|
||||
|
||||
# Redmine uses safe_attributes on Repository, so we need to declare our virtual attributes.
|
||||
safe_attributes 'create_readme', 'enable_git_annex'
|
||||
|
||||
# Relations
|
||||
has_one :extra, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryGitExtra'
|
||||
has_many :mirrors, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryMirror'
|
||||
has_many :post_receive_urls, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryPostReceiveUrl'
|
||||
has_many :deployment_credentials, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryDeploymentCredential'
|
||||
has_many :git_keys, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryGitConfigKey'
|
||||
has_many :git_config_keys, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryGitConfigKey::GitConfig'
|
||||
has_many :git_option_keys, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryGitConfigKey::Option'
|
||||
has_many :protected_branches, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryProtectedBranche'
|
||||
|
||||
# Additionnal validations
|
||||
validate :valid_repository_options, on: :create
|
||||
|
||||
acts_as_watchable
|
||||
|
||||
class << self
|
||||
def scm_adapter_class
|
||||
Redmine::Scm::Adapters::XitoliteAdapter
|
||||
end
|
||||
|
||||
def scm_name
|
||||
'Gitolite'
|
||||
end
|
||||
end
|
||||
|
||||
def sti_name
|
||||
'Repository::Xitolite'
|
||||
end
|
||||
|
||||
# Override the original method to accept options hash
|
||||
# which may contain *bypass_cache* flag.
|
||||
#
|
||||
def diff(path, rev, rev_to, opts = {})
|
||||
scm.diff(path, rev, rev_to, opts)
|
||||
end
|
||||
|
||||
def rev_list(revision, args = [])
|
||||
scm.rev_list(revision, args)
|
||||
end
|
||||
|
||||
def rev_parse(revision)
|
||||
scm.rev_parse(revision)
|
||||
end
|
||||
|
||||
def archive(revision, format = 'tar')
|
||||
scm.archive(revision, format)
|
||||
end
|
||||
|
||||
def mirror_push(url, branch, args = [])
|
||||
scm.mirror_push(url, branch, args)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def valid_repository_options
|
||||
return unless Additionals.true? create_readme
|
||||
return unless Additionals.true? enable_git_annex
|
||||
|
||||
errors.add(:base, :invalid_options)
|
||||
end
|
||||
end
|
|
@ -1,55 +0,0 @@
|
|||
class RepositoryDeploymentCredential < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
|
||||
VALID_PERMS = ['R', 'RW+'].freeze
|
||||
DEFAULT_PERM = 'RW+'.freeze
|
||||
|
||||
## Attributes
|
||||
safe_attributes 'perm', 'active', 'gitolite_public_key_id'
|
||||
|
||||
## Relations
|
||||
belongs_to :repository
|
||||
belongs_to :gitolite_public_key
|
||||
belongs_to :user
|
||||
|
||||
## Validations
|
||||
validates :repository_id, presence: true,
|
||||
uniqueness: { scope: :gitolite_public_key_id }
|
||||
|
||||
validates :gitolite_public_key_id, presence: true
|
||||
validates :user_id, presence: true
|
||||
validates :perm, presence: true,
|
||||
inclusion: { in: VALID_PERMS }
|
||||
|
||||
validates_associated :repository
|
||||
validates_associated :gitolite_public_key
|
||||
validates_associated :user
|
||||
|
||||
validate :correct_key_type
|
||||
validate :owner_matches_key
|
||||
|
||||
## Scopes
|
||||
scope :active, -> { where(active: true) }
|
||||
scope :inactive, -> { where(active: false) }
|
||||
|
||||
def to_s
|
||||
"#{repository.identifier}-#{gitolite_public_key.identifier} : #{perm}"
|
||||
end
|
||||
|
||||
# Deployment Credentials ignored unless created by someone who still has permission to create them
|
||||
def honored?
|
||||
user.admin? || user.allowed_to?(:create_repository_deployment_credentials, repository.project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def correct_key_type
|
||||
errors.add(:base, :invalid_key) if gitolite_public_key && gitolite_public_key.key_type_as_string != 'deploy_key'
|
||||
end
|
||||
|
||||
def owner_matches_key
|
||||
return if user.nil? || gitolite_public_key.nil?
|
||||
|
||||
errors.add(:base, :invalid_user) if user != gitolite_public_key.user
|
||||
end
|
||||
end
|
|
@ -1,42 +0,0 @@
|
|||
class RepositoryGitConfigKey < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
|
||||
## Attributes
|
||||
safe_attributes 'type', 'key', 'value'
|
||||
|
||||
## Relations
|
||||
belongs_to :repository
|
||||
|
||||
## Validations
|
||||
validates :repository_id, presence: true
|
||||
validates :type, presence: true, inclusion: { in: ['RepositoryGitConfigKey::GitConfig', 'RepositoryGitConfigKey::Option'] }
|
||||
validates :value, presence: true
|
||||
|
||||
## Callbacks
|
||||
after_save :check_if_key_changed
|
||||
|
||||
## Virtual attribute
|
||||
attr_accessor :key_has_changed
|
||||
attr_accessor :old_key
|
||||
|
||||
# Syntaxic sugar
|
||||
def key_has_changed?
|
||||
key_has_changed
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# This is Rails method : <attribute>_changed?
|
||||
# However, the value is cleared before passing the object to the controller.
|
||||
# We need to save it in virtual attribute to trigger Gitolite resync if changed.
|
||||
#
|
||||
def check_if_key_changed
|
||||
if key_changed?
|
||||
self.key_has_changed = true
|
||||
self.old_key = key_change[0]
|
||||
else
|
||||
self.key_has_changed = false
|
||||
self.old_key = ''
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
class RepositoryGitConfigKey::GitConfig < RepositoryGitConfigKey
|
||||
|
||||
VALID_CONFIG_KEY_REGEX = /\A[a-zA-Z0-9]+\.[a-zA-Z0-9.]+\z/
|
||||
|
||||
validates :key, presence: true,
|
||||
uniqueness: { case_sensitive: false, scope: [:type, :repository_id] },
|
||||
format: { with: VALID_CONFIG_KEY_REGEX }
|
||||
|
||||
end
|
|
@ -1,6 +0,0 @@
|
|||
class RepositoryGitConfigKey::Option < RepositoryGitConfigKey
|
||||
|
||||
validates :key, presence: true,
|
||||
uniqueness: { case_sensitive: false, scope: [:type, :repository_id] }
|
||||
|
||||
end
|
|
@ -1,115 +0,0 @@
|
|||
class RepositoryGitExtra < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
|
||||
SMART_HTTP_OPTIONS = [[l(:label_disabled), '0'],
|
||||
[l(:label_http_only), '3'],
|
||||
[l(:label_https_only), '1'],
|
||||
[l(:label_https_and_http), '2']].freeze
|
||||
|
||||
ALLOWED_URLS = %w[ssh http https go git git_annex].freeze
|
||||
|
||||
URLS_ICONS = { go: { label: 'Go', icon: 'fab_google' },
|
||||
http: { label: 'HTTP', icon: 'fas_external-link-alt' },
|
||||
https: { label: 'HTTPS', icon: 'fas_external-link-alt' },
|
||||
ssh: { label: 'SSH', icon: 'fas_shield-alt' },
|
||||
git: { label: 'Git', icon: 'fab_git' },
|
||||
git_annex: { label: 'GitAnnex', icon: 'fab_git' } }.freeze
|
||||
|
||||
## Attributes
|
||||
safe_attributes 'git_http', 'git_https', 'git_ssh', 'git_go', 'git_daemon', 'git_notify', 'git_annex', 'default_branch',
|
||||
'protected_branch', 'public_repo', 'key', 'urls_order', 'notification_sender', 'notification_prefix'
|
||||
|
||||
## Relations
|
||||
belongs_to :repository
|
||||
|
||||
## Validations
|
||||
validates :repository_id, presence: true, uniqueness: true
|
||||
validates :default_branch, presence: true
|
||||
validates :key, presence: true
|
||||
validates :notification_sender, format: { with: URI::MailTo::EMAIL_REGEXP, allow_blank: true }
|
||||
|
||||
validate :validate_urls_order
|
||||
|
||||
## Serializations
|
||||
serialize :urls_order, Array
|
||||
|
||||
## Callbacks
|
||||
before_save :check_urls_order_consistency
|
||||
after_save :check_if_default_branch_changed
|
||||
|
||||
## Virtual attribute
|
||||
attr_accessor :default_branch_has_changed
|
||||
|
||||
# Syntaxic sugar
|
||||
def default_branch_has_changed?
|
||||
default_branch_has_changed
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_urls_order
|
||||
urls_order.each do |url|
|
||||
errors.add(:urls_order, :invalid) unless ALLOWED_URLS.include?(url)
|
||||
end
|
||||
end
|
||||
|
||||
# This is Rails method : <attribute>_changed?
|
||||
# However, the value is cleared before passing the object to the controller.
|
||||
# We need to save it in virtual attribute to trigger Gitolite resync if changed.
|
||||
#
|
||||
def check_if_default_branch_changed
|
||||
self.default_branch_has_changed = if default_branch_changed?
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def check_urls_order_consistency
|
||||
check_ssh_url
|
||||
check_git_http_urls
|
||||
check_go_url
|
||||
check_git_url
|
||||
check_git_annex_url
|
||||
end
|
||||
|
||||
def check_ssh_url
|
||||
git_ssh? ? add_url('ssh') : remove_url('ssh')
|
||||
end
|
||||
|
||||
def check_git_http_urls
|
||||
if git_http? && git_https?
|
||||
add_url('http')
|
||||
add_url('https')
|
||||
elsif git_http?
|
||||
add_url('http')
|
||||
remove_url('https')
|
||||
elsif git_https?
|
||||
add_url('https')
|
||||
remove_url('http')
|
||||
else
|
||||
remove_url('http')
|
||||
remove_url('https')
|
||||
end
|
||||
end
|
||||
|
||||
def check_go_url
|
||||
git_go? ? add_url('go') : remove_url('go')
|
||||
end
|
||||
|
||||
def check_git_annex_url
|
||||
git_annex? ? add_url('git_annex') : remove_url('git_annex')
|
||||
end
|
||||
|
||||
def check_git_url
|
||||
git_daemon? ? add_url('git') : remove_url('git')
|
||||
end
|
||||
|
||||
def remove_url(url)
|
||||
urls_order.delete(url)
|
||||
end
|
||||
|
||||
def add_url(url)
|
||||
urls_order.push(url).uniq!
|
||||
end
|
||||
end
|
|
@ -1,106 +0,0 @@
|
|||
class RepositoryMirror < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
|
||||
PUSHMODE_MIRROR = 0
|
||||
PUSHMODE_FORCE = 1
|
||||
PUSHMODE_FAST_FORWARD = 2
|
||||
|
||||
## Attributes
|
||||
safe_attributes 'url', 'push_mode', 'include_all_branches', 'include_all_tags',
|
||||
'explicit_refspec', 'active'
|
||||
|
||||
## Relations
|
||||
belongs_to :repository
|
||||
|
||||
## Validations
|
||||
validates :repository_id, presence: true
|
||||
|
||||
## Only allow SSH format
|
||||
## ssh://git@redmine.example.org/project1/project2/project3/project4.git
|
||||
## ssh://git@redmine.example.org:2222/project1/project2/project3/project4.git
|
||||
validates :url, presence: true,
|
||||
uniqueness: { case_sensitive: false, scope: :repository_id },
|
||||
format: { with: RedmineGitHosting::Validators::GIT_SSH_URL_REGEX }
|
||||
|
||||
validates :push_mode, presence: true,
|
||||
numericality: { only_integer: true },
|
||||
inclusion: { in: [PUSHMODE_MIRROR, PUSHMODE_FORCE, PUSHMODE_FAST_FORWARD] }
|
||||
|
||||
## Additional validations
|
||||
validate :mirror_configuration
|
||||
|
||||
## Scopes
|
||||
scope :active, -> { where(active: true) }
|
||||
scope :inactive, -> { where(active: false) }
|
||||
scope :has_explicit_refspec, -> { where(push_mode: '> 0') }
|
||||
|
||||
## Callbacks
|
||||
before_validation :strip_whitespace
|
||||
|
||||
def mirror_mode?
|
||||
push_mode == PUSHMODE_MIRROR
|
||||
end
|
||||
|
||||
def force_mode?
|
||||
push_mode == PUSHMODE_FORCE
|
||||
end
|
||||
|
||||
def push_mode_to_s
|
||||
case push_mode
|
||||
when 0
|
||||
'mirror'
|
||||
when 1
|
||||
'force'
|
||||
when 2
|
||||
'fast_forward'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Strip leading and trailing whitespace
|
||||
def strip_whitespace
|
||||
self.url = url.strip rescue ''
|
||||
self.explicit_refspec = explicit_refspec.strip rescue ''
|
||||
end
|
||||
|
||||
def mirror_configuration
|
||||
if mirror_mode?
|
||||
reset_fields
|
||||
elsif include_all_branches? && include_all_tags?
|
||||
mutual_exclusion_error
|
||||
elsif explicit_refspec.present?
|
||||
if include_all_branches?
|
||||
errors.add(:explicit_refspec, "cannot be used with #{l(:label_mirror_include_all_branches)}.")
|
||||
else
|
||||
validate_refspec
|
||||
end
|
||||
elsif !include_all_branches? && !include_all_tags?
|
||||
errors.add(:base, :nothing_to_push)
|
||||
end
|
||||
end
|
||||
|
||||
# Check format of refspec
|
||||
#
|
||||
def validate_refspec
|
||||
RedmineGitHosting::Validators.valid_git_refspec_path?(explicit_refspec)
|
||||
rescue RedmineGitHosting::Error::InvalidRefspec::BadFormat => e
|
||||
errors.add(:explicit_refspec, :bad_format)
|
||||
rescue RedmineGitHosting::Error::InvalidRefspec::NullComponent => e
|
||||
errors.add(:explicit_refspec, :have_null_component)
|
||||
end
|
||||
|
||||
def reset_fields
|
||||
# clear out all extra parameters.. (we use javascript to hide them anyway)
|
||||
self.include_all_branches = false
|
||||
self.include_all_tags = false
|
||||
self.explicit_refspec = ''
|
||||
end
|
||||
|
||||
def mutual_exclusion_error
|
||||
errors.add(:base, "Cannot #{l(:label_mirror_include_all_branches)} and #{l(:label_mirror_include_all_tags)} at the same time.")
|
||||
return if explicit_refspec.blank?
|
||||
|
||||
errors.add(:explicit_refspec, "cannot be used with #{l(:label_mirror_include_all_branches)} or #{l(:label_mirror_include_all_tags)}")
|
||||
end
|
||||
end
|
|
@ -1,56 +0,0 @@
|
|||
require 'uri'
|
||||
|
||||
class RepositoryPostReceiveUrl < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
|
||||
## Attributes
|
||||
safe_attributes 'url', 'mode', 'active', 'use_triggers', 'triggers', 'split_payloads'
|
||||
|
||||
## Relations
|
||||
belongs_to :repository
|
||||
|
||||
## Validations
|
||||
validates :repository_id, presence: true
|
||||
|
||||
# Only allow HTTP(s) format
|
||||
validates :url, presence: true,
|
||||
uniqueness: { case_sensitive: false, scope: :repository_id },
|
||||
format: { with: URI::regexp(%w[http https]) }
|
||||
|
||||
validates :mode, presence: true, inclusion: { in: %i[github get] }
|
||||
|
||||
## Serializations
|
||||
serialize :triggers, Array
|
||||
|
||||
## Scopes
|
||||
scope :active, -> { where(active: true) }
|
||||
scope :inactive, -> { where(active: false) }
|
||||
|
||||
## Callbacks
|
||||
before_validation :strip_whitespace
|
||||
before_validation :remove_blank_triggers
|
||||
|
||||
def mode
|
||||
self[:mode].to_sym
|
||||
end
|
||||
|
||||
def mode=(value)
|
||||
self[:mode] = value.to_s
|
||||
end
|
||||
|
||||
def github_mode?
|
||||
mode == :github
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Strip leading and trailing whitespace
|
||||
def strip_whitespace
|
||||
self.url = url.strip rescue ''
|
||||
end
|
||||
|
||||
# Remove blank entries in triggers
|
||||
def remove_blank_triggers
|
||||
self.triggers = triggers.select(&:present?)
|
||||
end
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
class RepositoryProtectedBranche < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
VALID_PERMS = ['RW+', 'RW', 'R', '-'].freeze
|
||||
DEFAULT_PERM = 'RW+'.freeze
|
||||
|
||||
acts_as_positioned
|
||||
|
||||
## Attributes
|
||||
safe_attributes 'path', 'permissions', 'position'
|
||||
|
||||
## Relations
|
||||
belongs_to :repository
|
||||
has_many :protected_branches_members, foreign_key: :protected_branch_id, dependent: :destroy
|
||||
has_many :members, through: :protected_branches_members, source: :principal
|
||||
|
||||
## Validations
|
||||
validates :repository_id, presence: true
|
||||
validates :path, presence: true, uniqueness: { scope: %i[permissions repository_id] }
|
||||
validates :permissions, presence: true, inclusion: { in: VALID_PERMS }
|
||||
|
||||
## Scopes
|
||||
default_scope { order(position: :asc) }
|
||||
|
||||
class << self
|
||||
def clone_from(parent)
|
||||
parent = find_by(id: parent) unless parent.is_a? RepositoryProtectedBranche
|
||||
copy = new
|
||||
copy.attributes = parent.attributes
|
||||
copy.repository = parent.repository
|
||||
copy
|
||||
end
|
||||
end
|
||||
|
||||
# Accessors
|
||||
#
|
||||
def users
|
||||
members.select { |m| m.class.name == 'User' }.uniq
|
||||
end
|
||||
|
||||
def groups
|
||||
members.select { |m| m.class.name == 'Group' }.uniq
|
||||
end
|
||||
|
||||
def allowed_users
|
||||
users.map(&:gitolite_identifier).sort
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue