2011-03-09 17:38:21 +00:00
class Project < ActiveRecord :: Base
2014-02-16 20:51:41 +00:00
include Modules :: Models :: Autostart
2011-10-23 22:39:44 +01:00
VISIBILITIES = [ 'open' , 'hidden' ]
2012-01-27 00:16:07 +00:00
MAX_OWN_PROJECTS = 32000
2013-07-08 15:44:07 +01:00
NAME_REGEXP = / [ \ w \ - \ + \ .]+ /
2011-10-23 22:39:44 +01:00
2014-01-21 04:51:49 +00:00
belongs_to :owner , polymorphic : true , counter_cache : :own_projects_count
belongs_to :maintainer , class_name : " User "
has_many :issues , dependent : :destroy
has_many :pull_requests , dependent : :destroy , foreign_key : 'to_project_id'
has_many :labels , dependent : :destroy
has_many :project_imports , dependent : :destroy
has_many :project_to_repositories , dependent : :destroy
has_many :repositories , through : :project_to_repositories
has_many :project_tags , dependent : :destroy
has_many :project_statistics , dependent : :destroy
has_many :build_lists , dependent : :destroy
has_many :hooks , dependent : :destroy
has_many :relations , as : :target , dependent : :destroy
has_many :collaborators , through : :relations , source : :actor , source_type : 'User'
has_many :groups , through : :relations , source : :actor , source_type : 'Group'
has_many :packages , class_name : " BuildList::Package " , dependent : :destroy
has_and_belongs_to_many :advisories # should be without dependent: :destroy
validates :name , uniqueness : { scope : [ :owner_id , :owner_type ] , case_sensitive : false } ,
presence : true ,
format : { with : / \ A #{ NAME_REGEXP } \ z / ,
message : I18n . t ( " activerecord.errors.project.uname " ) }
validates :maintainer_id , presence : true , unless : :new_record?
validates :url , presence : true , format : { with : / \ Ahttps?: \/ \/ [ \ S]+ \ z / } , if : :mass_import
validates :add_to_repository_id , presence : true , if : :mass_import
validates :visibility , presence : true , inclusion : { in : VISIBILITIES }
validate { errors . add ( :base , :can_have_less_or_equal , count : MAX_OWN_PROJECTS ) if owner . projects . size > = MAX_OWN_PROJECTS }
2012-12-06 12:35:05 +00:00
validate :check_default_branch
2013-04-09 11:21:17 +01:00
# throws validation error message from ProjectToRepository model into Project model
2013-04-08 15:27:50 +01:00
validate do | project |
project . project_to_repositories . each do | p_to_r |
next if p_to_r . valid?
p_to_r . errors . full_messages . each { | msg | errors [ :base ] << msg }
end
errors . delete :project_to_repositories
end
2012-04-04 13:13:10 +01:00
2013-11-13 22:01:12 +00:00
attr_accessible :name , :description , :visibility , :srpm , :is_package , :default_branch ,
:has_issues , :has_wiki , :maintainer_id , :publish_i686_into_x86_64 ,
2014-02-17 21:02:48 +00:00
:url , :srpms_list , :mass_import , :add_to_repository_id , :architecture_dependent ,
:autostart_status
2013-08-13 14:56:50 +01:00
attr_readonly :owner_id , :owner_type
2011-03-10 12:38:42 +00:00
2013-07-01 11:50:35 +01:00
scope :recent , order ( " lower( #{ table_name } .name) ASC " )
2013-02-28 15:27:50 +00:00
scope :search_order , order ( " CHAR_LENGTH( #{ table_name } .name) ASC " )
2013-07-01 11:50:35 +01:00
scope :search , lambda { | q |
q = q . to_s . strip
by_name ( " % #{ q } % " ) . search_order if q . present?
}
2013-02-28 15:27:50 +00:00
scope :by_name , lambda { | name | where ( " #{ table_name } .name ILIKE ? " , name ) if name . present? }
2013-04-04 14:33:11 +01:00
scope :by_owner_and_name , lambda { | * params |
term = params . map ( & :strip ) . join ( '/' ) . downcase
where ( " lower(concat(owner_uname, '/', name)) ILIKE ? " , " % #{ term } % " ) if term . present?
}
2014-01-21 04:51:49 +00:00
scope :by_visibilities , lambda { | v | where ( visibility : v ) }
scope :opened , where ( visibility : 'open' )
scope :package , where ( is_package : true )
2012-08-28 16:00:04 +01:00
scope :addable_to_repository , lambda { | repository_id | where %Q(
projects . id NOT IN (
SELECT
2012-08-30 17:19:12 +01:00
ptr . project_id
2012-08-28 16:00:04 +01:00
FROM
2012-08-30 17:19:12 +01:00
project_to_repositories AS ptr
WHERE ( ptr . repository_id = #{ repository_id })
2012-08-28 16:00:04 +01:00
)
) }
2012-09-24 19:04:53 +01:00
scope :by_owners , lambda { | group_owner_ids , user_owner_ids |
2013-02-28 15:27:50 +00:00
where ( " ( #{ table_name } .owner_id in (?) AND #{ table_name } .owner_type = 'Group') OR ( #{ table_name } .owner_id in (?) AND #{ table_name } .owner_type = 'User') " , group_owner_ids , user_owner_ids )
2012-09-23 17:22:49 +01:00
}
2014-01-21 04:51:49 +00:00
before_validation :truncate_name , on : :create
2013-04-08 19:53:15 +01:00
before_save lambda { self . owner_uname = owner . uname if owner_uname . blank? || owner_id_changed? || owner_type_changed? }
2012-08-28 16:00:04 +01:00
before_create :set_maintainer
2012-09-12 16:06:34 +01:00
after_save :attach_to_personal_repository
2012-12-06 07:18:49 +00:00
after_update :set_new_git_head
2014-01-21 04:51:49 +00:00
after_update lambda { update_path_to_project ( name_was ) } , if : :name_changed?
2011-11-23 15:52:33 +00:00
2014-01-21 04:51:49 +00:00
has_ancestry orphan_strategy : :rootify #:adopt not available yet
2012-01-24 20:35:16 +00:00
2013-11-15 14:46:09 +00:00
attr_accessor :url , :srpms_list , :mass_import , :add_to_repository_id
2013-11-13 22:01:12 +00:00
2011-11-24 21:46:19 +00:00
include Modules :: Models :: Owner
2012-07-17 09:02:56 +01:00
include Modules :: Models :: Git
include Modules :: Models :: Wiki
2013-05-16 19:50:18 +01:00
include Modules :: Models :: UrlHelper
2012-07-17 09:02:56 +01:00
class << self
def find_by_owner_and_name ( owner_name , project_name )
2014-01-21 04:51:49 +00:00
where ( owner_uname : owner_name , name : project_name ) . first ||
2013-04-04 14:33:11 +01:00
by_owner_and_name ( owner_name , project_name ) . first
2012-07-17 09:02:56 +01:00
end
def find_by_owner_and_name! ( owner_name , project_name )
find_by_owner_and_name ( owner_name , project_name ) or raise ActiveRecord :: RecordNotFound
end
end
2011-11-24 21:46:19 +00:00
2013-11-14 21:26:05 +00:00
def init_mass_import
2013-11-15 14:46:09 +00:00
Project . perform_later :clone_build , :run_mass_import , url , srpms_list , visibility , owner , add_to_repository_id
2012-07-17 09:02:56 +01:00
end
2011-11-24 21:46:19 +00:00
2013-04-03 22:06:13 +01:00
def name_with_owner
2013-04-03 22:16:20 +01:00
" #{ owner_uname || owner . uname } / #{ name } "
2013-04-03 22:06:13 +01:00
end
2012-05-02 10:18:07 +01:00
def to_param
name
end
2012-04-19 20:45:50 +01:00
2012-09-17 17:17:43 +01:00
def all_members
2012-09-17 18:17:22 +01:00
members | ( owner_type == 'User' ? [ owner ] : owner . members )
2012-09-17 17:17:43 +01:00
end
2012-07-17 09:02:56 +01:00
def members
2012-09-17 17:17:43 +01:00
collaborators | groups . map ( & :members ) . flatten
2012-04-19 20:45:50 +01:00
end
2012-10-17 14:46:16 +01:00
def add_member ( member , role = 'admin' )
Relation . add_member ( member , self , role )
end
def remove_member ( member )
Relation . remove_member ( member , self )
end
2012-07-17 09:02:56 +01:00
def platforms
@platforms || = repositories . map ( & :platform ) . uniq
end
2012-12-13 18:18:22 +00:00
def admins
admins = self . collaborators . where ( " relations.role = 'admin' " )
grs = self . groups . where ( " relations.role = 'admin' " )
if self . owner . is_a? Group
grs = grs . where ( " relations.actor_id != ? " , self . owner . id )
admins = admins | owner . members . where ( " relations.role = 'admin' " )
end
admins = admins | grs . map ( & :members ) . flatten # member of the admin group is admin
2012-04-19 20:45:50 +01:00
end
2012-07-17 09:02:56 +01:00
def public?
visibility == 'open'
end
def owner? ( user )
owner == user
2012-04-19 20:45:50 +01:00
end
2012-12-14 11:25:10 +00:00
def git_project_address auth_user
2013-05-16 19:50:18 +01:00
opts = default_url_options
2014-01-21 04:51:49 +00:00
opts . merge! ( { user : auth_user . authentication_token , password : '' } ) unless self . public?
2013-05-16 19:50:18 +01:00
Rails . application . routes . url_helpers . project_url ( self . owner . uname , self . name , opts ) + '.git'
2012-11-08 09:41:07 +00:00
#path #share by NFS
2012-08-09 14:56:45 +01:00
end
2014-01-14 19:13:26 +00:00
def build_for ( mass_build , repository_id , arch = Arch . find_by_name ( 'i586' ) , priority = 0 , increase_rt = false )
2013-09-18 20:01:02 +01:00
build_for_platform = mass_build . build_for_platform
save_to_platform = mass_build . save_to_platform
user = mass_build . user
2012-04-14 14:46:39 +01:00
# Select main and project platform repository(contrib, non-free and etc)
2012-04-14 17:10:18 +01:00
# If main does not exist, will connect only project platform repository
# If project platform repository is main, only main will be connect
2014-02-17 21:02:48 +00:00
main_rep_id = build_for_platform . repositories . main . first . try ( :id )
2013-06-03 16:44:55 +01:00
include_repos = ( [ main_rep_id ] << ( save_to_platform . main? ? repository_id : nil ) ) . compact . uniq
2014-02-16 20:51:41 +00:00
project_version = project_version_for save_to_platform , build_for_platform
2014-01-21 04:51:49 +00:00
2014-01-14 19:13:26 +00:00
increase_release_tag ( project_version , user , " MassBuild # #{ mass_build . id } : Increase release tag " ) if increase_rt
2012-08-06 21:53:43 +01:00
2012-12-25 16:01:44 +00:00
build_list = build_lists . build do | bl |
2013-06-03 16:44:55 +01:00
bl . save_to_platform = save_to_platform
bl . build_for_platform = build_for_platform
2013-06-03 16:20:23 +01:00
bl . update_type = 'newpackage'
bl . arch = arch
bl . project_version = project_version
bl . user = user
2014-02-19 21:19:49 +00:00
bl . auto_publish_status = mass_build . auto_publish? ? BuildList :: AUTO_PUBLISH_STATUS_DEFAULT : BuildList :: AUTO_PUBLISH_STATUS_NONE
2013-06-03 16:20:23 +01:00
bl . include_repos = include_repos
2013-06-04 20:59:08 +01:00
bl . extra_repositories = mass_build . extra_repositories
bl . extra_build_lists = mass_build . extra_build_lists
2013-06-03 16:20:23 +01:00
bl . priority = priority
2013-06-04 20:59:08 +01:00
bl . mass_build_id = mass_build . id
2013-06-03 16:20:23 +01:00
bl . save_to_repository_id = repository_id
2011-11-30 21:43:01 +00:00
end
2012-12-25 16:01:44 +00:00
build_list . save
2011-11-30 21:43:01 +00:00
end
2014-02-16 20:51:41 +00:00
def project_version_for ( save_to_platform , build_for_platform )
if repo . commits ( " #{ save_to_platform . name } " ) . try ( :first ) . try ( :id )
save_to_platform . name
elsif repo . commits ( " #{ build_for_platform . name } " ) . try ( :first ) . try ( :id )
build_for_platform . name
else
default_branch
end
end
2013-11-19 12:35:07 +00:00
def fork ( new_owner , new_name = name )
2013-11-19 11:02:05 +00:00
new_name = new_name . presence || name
2012-03-07 21:34:49 +00:00
dup . tap do | c |
2013-11-19 11:02:05 +00:00
c . name = new_name
2011-11-29 22:23:09 +00:00
c . parent_id = id
2011-11-23 15:52:33 +00:00
c . owner = new_owner
c . updated_at = nil ; c . created_at = nil # :id = nil
2012-08-28 16:00:04 +01:00
# Hack to call protected method :)
c . send :set_maintainer
2011-11-23 15:52:33 +00:00
c . save
end
2011-03-11 17:38:28 +00:00
end
2012-12-17 14:39:02 +00:00
def destroy_project_from_repository ( repository )
2013-01-17 16:41:23 +00:00
AbfWorker :: BuildListsPublishTaskManager . destroy_project_from_repository self , repository
2012-12-17 14:39:02 +00:00
end
2013-01-31 16:26:49 +00:00
def default_head treeish = nil # maybe need change 'head'?
2013-02-13 17:20:43 +00:00
# Attention!
# repo.commit(nil) => <Grit::Commit "b6c0f81deb17590d22fc07ba0bbd4aa700256f61">
# repo.commit(nil.to_s) => nil
return treeish if treeish . present? && repo . commit ( treeish ) . present?
2013-01-31 16:26:49 +00:00
if repo . branches_and_tags . map ( & :name ) . include? ( treeish || default_branch )
2013-01-31 17:18:57 +00:00
treeish || default_branch
2013-01-31 16:26:49 +00:00
else
2013-01-31 17:44:02 +00:00
repo . branches_and_tags [ 0 ] . try ( :name ) || default_branch
2013-01-31 16:26:49 +00:00
end
end
2013-02-14 12:46:25 +00:00
def get_project_tag_sha1 ( tag , format )
2013-02-14 13:20:08 +00:00
format_id = ProjectTag :: FORMATS [ " #{ tag_file_format ( format ) } " ]
2014-01-21 04:51:49 +00:00
project_tag = project_tags . where ( tag_name : tag . name , format_id : format_id ) . first
2013-02-14 12:46:25 +00:00
2013-02-14 21:49:18 +00:00
return project_tag . sha1 if project_tag && project_tag . commit_id == tag . commit . id && Modules :: Models :: FileStoreClean . file_exist_on_file_store? ( project_tag . sha1 )
2013-02-14 12:46:25 +00:00
2013-02-14 21:49:18 +00:00
archive = archive_by_treeish_and_format tag . name , format
2013-02-14 12:46:25 +00:00
sha1 = Digest :: SHA1 . file ( archive [ :path ] ) . hexdigest
2013-02-14 21:49:18 +00:00
unless Modules :: Models :: FileStoreClean . file_exist_on_file_store? sha1
token = User . find_by_uname ( 'rosa_system' ) . authentication_token
begin
resp = JSON ` curl --user #{ token } : -POST -F 'file_store[file]=@ #{ archive [ :path ] } ;filename= #{ name } - #{ tag . name } . #{ tag_file_format ( format ) } ' #{ APP_CONFIG [ 'file_store_url' ] } /api/v1/upload `
rescue # Dont care about it
resp = { }
end
return nil if resp [ 'sha1_hash' ] . nil?
2013-02-14 12:46:25 +00:00
end
if project_tag
2013-02-15 09:21:05 +00:00
project_tag . destroy_files_from_file_store ( project_tag . sha1 )
2014-01-21 04:51:49 +00:00
project_tag . update_attributes ( sha1 : sha1 )
2013-02-14 12:46:25 +00:00
else
project_tags . create (
2014-01-21 04:51:49 +00:00
tag_name : tag . name ,
format_id : format_id ,
commit_id : tag . commit . id ,
sha1 : sha1
2013-02-14 12:46:25 +00:00
)
end
return sha1
end
2013-02-14 21:49:18 +00:00
def archive_by_treeish_and_format ( treeish , format )
@archive || = create_archive treeish , format
end
2013-09-19 13:07:49 +01:00
# Finds release tag and increase its:
# 'Release: %mkrel 4mdk' => 'Release: 5mdk'
# 'Release: 4' => 'Release: 5'
# Finds release macros and increase it:
# '%define release %mkrel 4mdk' => '%define release 5mdk'
# '%define release 4' => '%define release 5'
def self . replace_release_tag ( content )
build_new_release = Proc . new do | release , combine_release |
if combine_release . present?
r = combine_release . split ( '.' ) . last . to_i
release << combine_release . gsub ( / .[ \ d]+$ / , '' ) << " . #{ r + 1 } "
else
release = release . to_i + 1
end
2014-01-21 04:51:49 +00:00
release
2013-09-19 13:07:49 +01:00
end
content . gsub ( / ^Release:( \ s+)(%mkrel \ s+)?( \ d+)([. \ d]+)?(mdk)?$ / ) do | line |
tab , mkrel , mdk = $1 , $2 , $5
" Release: #{ tab } #{ build_new_release . call ( $3 , $4 ) } #{ mdk } "
end . gsub ( / ^%define \ s+release:?( \ s+)(%mkrel \ s+)?( \ d+)([. \ d]+)?(mdk)?$ / ) do | line |
tab , mkrel , mdk = $1 , $2 , $5
" %define release #{ tab } #{ build_new_release . call ( $3 , $4 ) } #{ mdk } "
end
end
2014-02-16 20:51:41 +00:00
class << self
Modules :: Models :: Autostart :: HUMAN_AUTOSTART_STATUSES . each do | autostart_status , human_autostart_status |
define_method " autostart_build_lists_ #{ human_autostart_status } " do
2014-02-17 21:02:48 +00:00
autostart_build_lists autostart_status
2014-02-16 20:51:41 +00:00
end
end
end
def self . autostart_build_lists ( autostart_status )
Project . where ( autostart_status : autostart_status ) . find_each do | p |
2014-02-17 21:02:48 +00:00
p . project_to_repositories . autostart_enabled . includes ( repository : :platform ) . each do | p_to_r |
repository = p_to_r . repository
2014-02-17 21:32:47 +00:00
user = User . find ( p_to_r . user_id )
if repository . platform . personal?
platforms = Platform . availables_main_platforms ( user )
else
platforms = [ repository . platform ]
end
platforms . each do | platform |
platform . platform_arch_settings . by_default . pluck ( :arch_id ) . each do | arch_id |
build_list = p . build_lists . build do | bl |
bl . save_to_platform = repository . platform
bl . build_for_platform = platform
bl . update_type = 'newpackage'
bl . arch_id = arch_id
bl . project_version = p . project_version_for ( platform , platform )
bl . user = user
2014-02-19 21:19:49 +00:00
bl . auto_publish_status = p_to_r . auto_publish? ? BuildList :: AUTO_PUBLISH_STATUS_DEFAULT : BuildList :: AUTO_PUBLISH_STATUS_NONE
2014-02-17 21:32:47 +00:00
bl . save_to_repository = repository
bl . include_repos = [ repository . id , platform . repositories . main . first . try ( :id ) ] . uniq . compact
end
build_list . save!
2014-02-16 20:51:41 +00:00
end
end
end
end
end
2011-03-09 17:38:21 +00:00
protected
2013-09-18 20:01:02 +01:00
def increase_release_tag ( project_version , user , message )
blob = repo . tree ( project_version ) . contents . find { | n | n . is_a? ( Grit :: Blob ) && n . name =~ / .spec$ / }
return unless blob
raw = Grit :: GitRuby :: Repository . new ( repo . path ) . get_raw_object_by_sha1 ( blob . id )
2013-09-19 13:07:49 +01:00
content = self . class . replace_release_tag raw . content
2013-09-18 20:01:02 +01:00
return if content == raw . content
update_file ( blob . name , content . gsub ( " \r " , '' ) ,
2014-01-21 04:51:49 +00:00
message : message ,
actor : user ,
head : project_version
2013-09-18 20:01:02 +01:00
)
end
2013-09-19 13:07:49 +01:00
2013-02-14 21:49:18 +00:00
def create_archive ( treeish , format )
file_name = " #{ name } - #{ treeish } "
fullname = " #{ file_name } . #{ tag_file_format ( format ) } "
2014-01-17 17:27:44 +00:00
file = Tempfile . new fullname , File . join ( Rails . root , 'tmp' )
2013-02-14 21:49:18 +00:00
system ( " cd #{ path } ; git archive --format= #{ format == 'zip' ? 'zip' : 'tar' } --prefix= #{ file_name } / #{ treeish } #{ format == 'zip' ? '' : ' | gzip -9' } > #{ file . path } " )
file . close
{
2014-01-21 04:51:49 +00:00
path : file . path ,
fullname : fullname
2013-02-14 21:49:18 +00:00
}
end
2013-02-14 12:46:25 +00:00
def tag_file_format ( format )
format == 'zip' ? 'zip' : 'tar.gz'
end
2012-10-15 09:28:18 +01:00
def truncate_name
self . name = name . strip if name
end
2012-01-27 15:35:18 +00:00
def attach_to_personal_repository
2013-04-09 12:08:49 +01:00
owner_repos = self . owner . personal_platform . repositories
2012-09-12 16:06:34 +01:00
if is_package
2014-01-21 04:51:49 +00:00
repositories << self . owner . personal_repository unless repositories . exists? ( id : owner_repos . pluck ( :id ) )
2012-09-12 16:06:34 +01:00
else
2013-04-09 12:08:49 +01:00
repositories . delete owner_repos
2012-09-12 16:06:34 +01:00
end
2012-01-27 15:35:18 +00:00
end
2012-08-24 16:19:26 +01:00
2012-08-28 16:00:04 +01:00
def set_maintainer
2012-10-17 13:18:52 +01:00
if maintainer_id . blank?
self . maintainer_id = ( owner_type == 'User' ) ? self . owner_id : self . owner . owner_id
end
2012-08-28 16:00:04 +01:00
end
2012-12-06 07:18:49 +00:00
def set_new_git_head
` cd #{ path } && git symbolic-ref HEAD refs/heads/ #{ self . default_branch } ` if self . default_branch_changed? && self . repo . branches . map ( & :name ) . include? ( self . default_branch )
end
2012-12-06 12:35:05 +00:00
2013-08-13 14:56:50 +01:00
def update_path_to_project ( old_name )
2013-08-13 16:36:09 +01:00
new_name , new_path = name , path
self . name = old_name
old_path = path
2013-08-13 16:05:16 +01:00
self . name = new_name
2014-01-21 04:51:49 +00:00
FileUtils . mv old_path , new_path , force : true if Dir . exists? ( old_path )
2013-08-13 16:05:16 +01:00
2013-08-13 16:56:27 +01:00
pull_requests_old_path = File . join ( APP_CONFIG [ 'git_path' ] , 'pull_requests' , owner . uname , old_name )
if Dir . exists? ( pull_requests_old_path )
FileUtils . mv pull_requests_old_path ,
File . join ( APP_CONFIG [ 'git_path' ] , 'pull_requests' , owner . uname , new_name ) ,
2014-01-21 04:51:49 +00:00
force : true
2013-08-13 16:56:27 +01:00
end
2013-08-13 16:05:16 +01:00
2014-01-21 04:51:49 +00:00
PullRequest . where ( from_project_id : id ) . update_all ( from_project_name : new_name )
2013-08-13 16:05:16 +01:00
2014-01-21 04:51:49 +00:00
PullRequest . where ( from_project_id : id ) . each { | p | p . update_relations ( old_name ) }
2013-08-13 16:36:09 +01:00
pull_requests . where ( 'from_project_id != to_project_id' ) . each ( & :update_relations )
2013-08-13 14:56:50 +01:00
end
2014-01-21 04:51:49 +00:00
later :update_path_to_project , queue : :clone_build
2013-08-13 14:56:50 +01:00
2012-12-06 12:35:05 +00:00
def check_default_branch
if self . repo . branches . count > 0 && self . repo . branches . map ( & :name ) . exclude? ( self . default_branch )
errors . add :default_branch , I18n . t ( 'activerecord.errors.project.default_branch' )
end
end
2011-03-09 17:38:21 +00:00
end