2012-01-30 20:39:34 +00:00
# -*- encoding : utf-8 -*-
2011-03-09 17:38:21 +00:00
class Project < ActiveRecord :: Base
2011-10-23 22:39:44 +01:00
VISIBILITIES = [ 'open' , 'hidden' ]
2012-01-27 00:16:07 +00:00
MAX_OWN_PROJECTS = 32000
2012-05-14 14:24:01 +01:00
NAME_REGEXP = / [a-zA-Z0-9_ \ - \ + \ .]+ /
2011-10-23 22:39:44 +01:00
2012-01-27 06:13:56 +00:00
belongs_to :owner , :polymorphic = > true , :counter_cache = > :own_projects_count
2012-08-24 16:19:26 +01:00
belongs_to :maintainer , :class_name = > " User "
2011-10-18 16:00:06 +01:00
2011-12-19 15:30:14 +00:00
has_many :issues , :dependent = > :destroy
2012-10-03 12:36:04 +01:00
has_many :pull_requests , :dependent = > :destroy , :foreign_key = > 'to_project_id'
2012-05-02 10:18:07 +01:00
has_many :labels , :dependent = > :destroy
2011-04-07 14:20:21 +01:00
has_many :build_lists , :dependent = > :destroy
2011-03-10 12:35:23 +00:00
2012-01-27 15:35:18 +00:00
has_many :project_imports , :dependent = > :destroy
2011-10-26 21:57:51 +01:00
has_many :project_to_repositories , :dependent = > :destroy
2011-10-13 23:35:16 +01:00
has_many :repositories , :through = > :project_to_repositories
2013-02-14 12:46:25 +00:00
has_many :project_tags , :dependent = > :destroy
2011-10-13 16:55:03 +01:00
2011-10-26 21:57:51 +01:00
has_many :relations , :as = > :target , :dependent = > :destroy
2012-04-26 02:38:33 +01:00
has_many :collaborators , :through = > :relations , :source = > :actor , :source_type = > 'User'
has_many :groups , :through = > :relations , :source = > :actor , :source_type = > 'Group'
2011-10-13 16:55:03 +01:00
2012-05-14 20:08:31 +01:00
has_many :packages , :class_name = > " BuildList::Package " , :dependent = > :destroy
2012-06-18 23:49:17 +01:00
has_and_belongs_to_many :advisories # should be without :dependent => :destroy
2012-05-04 18:12:51 +01:00
2012-08-28 16:00:04 +01:00
validates :name , :uniqueness = > { :scope = > [ :owner_id , :owner_type ] , :case_sensitive = > false } ,
:presence = > true ,
2012-11-07 10:20:24 +00:00
:format = > { :with = > / \ A #{ NAME_REGEXP } \ z / , :message = > I18n . t ( " activerecord.errors.project.uname " ) }
2011-10-26 21:57:51 +01:00
validates :owner , :presence = > true
2012-08-28 16:00:04 +01:00
validates :maintainer_id , :presence = > true , :unless = > :new_record?
2012-08-06 21:48:29 +01:00
validates :visibility , :presence = > true , :inclusion = > { :in = > VISIBILITIES }
2012-01-27 06:13:56 +00:00
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
2012-04-04 13:13:10 +01:00
2013-02-07 11:11:57 +00:00
attr_accessible :name , :description , :visibility , :srpm , :is_package , :default_branch , :has_issues , :has_wiki , :maintainer_id , :publish_i686_into_x86_64
2012-08-06 21:48:29 +01:00
attr_readonly :name , :owner_id , :owner_type
2011-03-10 12:38:42 +00:00
2011-03-31 02:15:17 +01:00
scope :recent , order ( " name ASC " )
2012-03-07 21:34:49 +00:00
scope :search_order , order ( " CHAR_LENGTH(name) ASC " )
2012-04-05 18:11:02 +01:00
scope :search , lambda { | q | by_name ( " % #{ q . to_s . strip } % " ) }
2012-10-02 16:14:08 +01:00
scope :by_name , lambda { | name | where ( 'projects.name ILIKE ?' , name ) if name . present? }
2012-03-06 15:53:04 +00:00
scope :by_visibilities , lambda { | v | where ( :visibility = > v ) }
2012-03-28 00:58:03 +01:00
scope :opened , where ( :visibility = > 'open' )
2012-08-27 22:12:53 +01:00
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 |
where ( " (projects.owner_id in (?) AND projects.owner_type = 'Group') OR (projects.owner_id in (?) AND projects.owner_type = 'User') " , group_owner_ids , user_owner_ids )
2012-09-23 17:22:49 +01:00
}
2012-10-15 09:28:18 +01:00
before_validation :truncate_name , :on = > :create
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
2011-11-23 15:52:33 +00:00
2012-07-24 17:02:02 +01:00
has_ancestry :orphan_strategy = > :rootify #:adopt not available yet
2012-01-24 20:35:16 +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
class << self
def find_by_owner_and_name ( owner_name , project_name )
owner = User . find_by_uname ( owner_name ) || Group . find_by_uname ( owner_name ) || User . by_uname ( owner_name ) . first || Group . by_uname ( owner_name ) . first and
scoped = where ( :owner_id = > owner . id , :owner_type = > owner . class ) and
scoped . find_by_name ( project_name ) || scoped . by_name ( project_name ) . first
# owner.projects.find_by_name(project_name) || owner.projects.by_name(project_name).first # TODO force this work?
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
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
2012-11-08 09:41:07 +00:00
host || = EventLog . current_controller . request . host_with_port rescue :: Rosa :: Application . config . action_mailer . default_url_options [ :host ]
protocol = APP_CONFIG [ 'mailer_https_url' ] ? " https " : " http " rescue " http "
2012-12-18 11:15:45 +00:00
opts = { :host = > host , :protocol = > protocol }
opts . merge! ( { :user = > auth_user . authentication_token , :password = > '' } ) unless self . public?
2012-12-14 11:25:10 +00: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
2013-01-28 21:16:29 +00:00
def build_for ( platform , repository_id , user , arch = Arch . find_by_name ( 'i586' ) , auto_publish = false , mass_build_id = nil , priority = 0 )
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
2012-12-06 19:34:32 +00:00
main_rep_id = platform . repositories . find_by_name ( 'main' ) . try ( :id )
2012-08-06 21:48:29 +01:00
build_reps_ids = [ main_rep_id , repository_id ] . compact . uniq
2012-08-06 21:53:43 +01:00
2012-12-25 17:06:57 +00:00
project_version = repo . commits ( " #{ platform . name } " ) . try ( :first ) . try ( :id ) ?
2013-01-21 17:08:19 +00:00
platform . name : 'master'
2012-12-25 16:01:44 +00:00
build_list = build_lists . build do | bl |
2012-05-04 18:12:51 +01:00
bl . save_to_platform = platform
2012-05-18 16:12:51 +01:00
bl . build_for_platform = platform
2012-02-23 20:20:44 +00:00
bl . update_type = 'newpackage'
2012-03-07 23:25:17 +00:00
bl . arch = arch
2012-12-25 17:36:34 +00:00
bl . project_version = project_version
2011-12-20 17:09:29 +00:00
bl . user = user
2012-05-21 22:10:00 +01:00
bl . auto_publish = auto_publish
bl . include_repos = build_reps_ids
2012-04-24 20:03:45 +01:00
bl . priority = priority
2012-05-18 16:12:51 +01:00
bl . mass_build_id = mass_build_id
2012-08-06 21:48:29 +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
2011-11-23 15:52:33 +00:00
def fork ( new_owner )
2012-03-07 21:34:49 +00:00
dup . tap do | c |
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-07-17 09:02:56 +01:00
def human_average_build_time
I18n . t ( " layout.projects.human_average_build_time " , { :hours = > ( average_build_time / 3600 ) . to_i , :minutes = > ( average_build_time % 3600 / 60 ) . to_i } )
2011-12-23 17:01:47 +00:00
end
2012-08-11 23:08:28 +01:00
def formatted_average_build_time
" %02d:%02d " % [ average_build_time / 3600 , average_build_time % 3600 / 60 ]
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 create_archive ( treeish , format )
file_name = " #{ name } - #{ treeish } "
fullname = " #{ file_name } . #{ tag_file_format ( format ) } "
file = Tempfile . new fullname , 'tmp'
system ( " cd #{ path } ; git archive --format= #{ format == 'zip' ? 'zip' : 'tar' } --prefix= #{ file_name } / #{ treeish } #{ format == 'zip' ? '' : ' | gzip -9' } > #{ file . path } " )
file . close
{
:path = > file . path ,
:fullname = > fullname
}
end
def get_project_tag_sha1 ( tag , format )
2013-02-14 13:20:08 +00:00
format_id = ProjectTag :: FORMATS [ " #{ tag_file_format ( format ) } " ]
2013-02-14 12:46:25 +00:00
project_tag = project_tags . where ( :tag_name = > tag . name , :format_id = > format_id ) . first
return project_tag . sha1 if project_tag && project_tag . commit_id == tag . commit . id
archive = create_archive ( tag . name , format )
sha1 = Digest :: SHA1 . file ( archive [ :path ] ) . hexdigest
token = User . find_by_uname ( 'rosa_system' ) . authentication_token
if %x[ curl #{ APP_CONFIG [ 'file_store_url' ] } /api/v1/file_stores.json?hash= #{ sha1 } ] == '[]'
2013-02-14 13:35:10 +00:00
system " 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 "
2013-02-14 12:46:25 +00:00
end
if project_tag
2013-02-14 13:53:26 +00:00
project_tag . remove_archive_from_file_store ( project_tag . sha1 )
2013-02-14 12:46:25 +00:00
project_tag . update_attributes ( :sha1 = > sha1 )
else
project_tags . create (
:tag_name = > tag . name ,
:format_id = > format_id ,
:commit_id = > tag . commit . id ,
:sha1 = > sha1
)
end
return sha1
end
2011-03-09 17:38:21 +00:00
protected
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
2012-09-12 16:06:34 +01:00
owner_rep = self . owner . personal_repository
if is_package
repositories << owner_rep unless repositories . exists? ( :id = > owner_rep )
else
repositories . delete owner_rep
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
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