Merge branch 'master' into build_list_visibilities

This commit is contained in:
George Vinogradov 2011-12-15 03:29:22 +04:00
commit e3663381db
42 changed files with 491 additions and 140 deletions

2
.rspec
View File

@ -1 +1 @@
--colour
--colour --format doc

24
Gemfile
View File

@ -28,6 +28,7 @@ gem 'grack', :git => 'git://github.com/rdblue/grack.git', :require => 'git_http'
gem "grit"
gem 'whenever', :require => false
gem 'delayed_job'
gem 'highline', '~> 1.6.8'
# XML-RPC support
# gem 'actionwebservice' #, :git => 'git://github.com/ywen/actionwebservice.git'
@ -39,6 +40,7 @@ gem 'unicorn', '~> 4.1.1'
group :production do
gem "airbrake", '~> 3.0.5'
# gem 'newrelic_rpm', '~> 3.1.1'
gem 'bluepill', :require => false
end
group :development do
@ -72,14 +74,14 @@ group :development, :test do
gem 'rr'
end
group :test do
# gem 'spork', '>= 0.9.0.rc9'
# gem 'guard-spork', '~> 0.3.1'
# gem 'guard-rspec', '~> 0.5.0'
# gem 'guard-bundler', '~> 0.1.3'
#
# gem 'rb-fsevent', '>= 0.4.3', :require => false
# gem 'growl', '~> 1.0.3', :require => false
# gem 'rb-inotify', '>= 0.8.6', :require => false
# gem 'libnotify', '~> 0.5.7', :require => false
end
# group :test do
# gem 'spork', '>= 0.9.0.rc9'
# gem 'guard-spork', '~> 0.3.1'
# gem 'guard-rspec', '~> 0.5.0'
# gem 'guard-bundler', '~> 0.1.3'
#
# gem 'rb-fsevent', '>= 0.4.3', :require => false
# gem 'growl', '~> 1.0.3', :require => false
# gem 'rb-inotify', '>= 0.8.6', :require => false
# gem 'libnotify', '~> 0.5.7', :require => false
# end

View File

@ -41,6 +41,11 @@ GEM
activerecord (>= 2.2.2)
arel (2.0.10)
bcrypt-ruby (3.0.1)
bluepill (0.0.51)
activesupport (>= 3.0.0)
daemons (~> 1.1.0)
i18n (>= 0.5.0)
state_machine (~> 0.9.4)
builder (2.1.2)
cancan (1.6.7)
cape (1.0.1)
@ -180,6 +185,7 @@ GEM
i18n (>= 0.5.0)
sexp_processor (3.0.8)
silent-postgres (0.1.1)
state_machine (0.9.4)
thor (0.14.6)
treetop (1.4.10)
polyglot
@ -204,6 +210,7 @@ PLATFORMS
DEPENDENCIES
airbrake (~> 3.0.5)
ancestry (~> 1.2.4)
bluepill
cancan (~> 1.6.7)
cape
capistrano
@ -215,6 +222,7 @@ DEPENDENCIES
grack!
grit
haml-rails (~> 0.3.4)
highline (~> 1.6.8)
hirb
hpricot
jammit

View File

@ -78,7 +78,7 @@ class BuildListsController < ApplicationController
end
def pre_build
@build_list.status = BuildList::BUILD_STARTED
@build_list.status = BuildServer::BUILD_STARTED
@build_list.notified_at = Time.current
@build_list.save

View File

@ -30,7 +30,6 @@ class CollaboratorsController < ApplicationController
def update
all_user_ids = []
all_groups_ids = []
puts params.inspect
Relation::ROLES.each { |r|
all_user_ids = all_user_ids | params['user'][r.to_sym].keys if params['user'] && params['user'][r.to_sym]
all_groups_ids = all_groups_ids | params['group'][r.to_sym].keys if params['group'] && params['group'][r.to_sym]
@ -82,6 +81,41 @@ class CollaboratorsController < ApplicationController
def destroy
end
def add
# TODO: Here is used Chelyabinsk method to display Flash messages.
member = User.find(params['member_id']) if params['member_id'] && !params['member_id'].empty?
group = Group.find(params['group_id']) if params['group_id'] && !params['group_id'].empty?
flash[:notice], flash[:error], flash[:warning] = [], [], []
[member, group].compact.each do |mem|
if mem and @project.relations.exists?(:object_id => mem.id, :object_type => mem.class.to_s)
flash[:warning] << [t('flash.collaborators.member_already_added'), mem.uname]
end
unless @project.relations.exists?(:object_id => mem.id, :object_type => mem.class.to_s)
rel = @project.relations.build(:role => 'reader')
rel.object = mem
if rel.save
flash[:notice] << [t('flash.collaborators.successfully_added'), mem.uname]
else
flash[:notice] << [t('flash.collaborators.error_in_adding'), mem.uname]
end
end
end
[:notice, :warning, :error].each do |k|
if flash[k].size > 0
flash[k] = flash[k].map{|i| (i.is_a? Array) ? sprintf(i.first, i.last) : i}.join('; ')
else
flash[k] = nil
end
end
flash.delete_if{|k, v| v.nil?}
redirect_to(edit_project_collaborators_path(@project))
end
protected
def find_project
@ -89,10 +123,10 @@ class CollaboratorsController < ApplicationController
end
def find_users
@users = User.all
@users = @project.collaborators#User.all
end
def find_groups
@groups = Group.all
@groups = @project.groups#Group.all
end
end

View File

@ -8,6 +8,7 @@ class GroupsController < ApplicationController
before_filter :find_group, :only => [:show, :edit, :update, :destroy]
load_and_authorize_resource
autocomplete :group, :uname
def index
puts parent.inspect

View File

@ -67,10 +67,27 @@ class MembersController < ApplicationController
def destroy
end
def add
if params['user_id'] and !params['user_id'].empty?
@user = User.find_by_uname(params['user_id'])
unless parent.objects.exists? :object_id => @user.id, :object_type => 'User'
relation = parent.objects.build(:object_id => @user.id, :object_type => 'User', :role => 'reader')
if relation.save
flash[:notice] = t("flash.members.successfully_added")
else
flash[:error] = t("flash.members.error_in_adding")
end
else
flash[:error] = t("flash.members.already_added")
end
end
redirect_to edit_group_members_path(parent)
end
protected
def find_users
@users = User.all
@users = parent.members #User.all
end
end

View File

@ -45,18 +45,39 @@ class PlatformsController < ApplicationController
def new
@platform = Platform.new
@admin_uname = current_user.uname
@admin_id = current_user.id
end
def edit
@admin_id = @platform.owner.id
@admin_uname = @platform.owner.uname
end
def create
@platform = Platform.new params[:platform]
@platform.owner = (params[:admin_uname]) ? User.find_by_uname(params[:admin_uname]) : nil
@platform.owner ||= get_owner
@admin_id = params[:admin_id]
@admin_uname = params[:admin_uname]
@platform.owner = @admin_id.blank? ? get_owner : User.find(@admin_id)
if @platform.save!
# @platform.make_admin_relation(@platform.owner.id)
if @platform.save
flash[:notice] = I18n.t("flash.platform.saved")
redirect_to @platform
else
flash[:error] = I18n.t("flash.platform.saved_error")
render :action => :new
end
end
def update
@admin_id = params[:admin_id]
@admin_uname = params[:admin_uname]
if @platform.update_attributes(
:owner => @admin_id.blank? ? get_owner : User.find(@admin_id),
:description => params[:platform][:description],
:released => params[:platform][:released]
)
flash[:notice] = I18n.t("flash.platform.saved")
redirect_to @platform
else

View File

@ -4,6 +4,7 @@ class UsersController < ApplicationController
before_filter :find_user, :only => [:show, :edit, :update, :destroy]
load_and_authorize_resource
autocomplete :user, :uname
def index
@users = User.paginate(:page => params[:user_page])

View File

@ -44,6 +44,9 @@ class Ability
can :publish, BuildList do |build_list|
build_list.can_published? && build_list.project.relations.exists?(:object_type => 'User', :object_id => user.id)
end
can :read, BuildList do |build_list|
build_list.project.public? || build_list.project.relations.exists?(:object_type => 'User', :object_id => user.id)
end
can [:read, :create], PrivateUser, :platform => {:owner_type => 'User', :owner_id => user.id}
# If rule has multiple conditions CanCan joins them by 'AND' sql operator
@ -100,6 +103,9 @@ class Ability
can :publish, BuildList do |build_list|
build_list.can_published? && build_list.project.relations.exists?(:object_type => 'Group', :object_id => user.group_ids)
end
can :read, BuildList do |build_list|
build_list.project.public? || build_list.project.relations.exists?(:object_type => 'Group', :object_id => user.group_ids)
end
can :manage_collaborators, Project, projects_in_relations_with(:role => 'admin', :object_type => 'Group', :object_id => user.group_ids) do |project|
project.relations.exists? :object_id => user.group_ids, :object_type => 'Group', :role => 'admin'

View File

@ -52,7 +52,7 @@ class BuildList < ActiveRecord::Base
BuildServer::BINARY_TEST_FAILED => :binary_test_failed
}
scope :recent, order("updated_at DESC")
scope :recent, order("#{table_name}.updated_at DESC")
scope :current, lambda {
outdatable_statuses = [BuildServer::SUCCESS, BuildServer::ERROR, BuildServer::PLATFORM_NOT_FOUND, BuildServer::PLATFORM_PENDING, BuildServer::PROJECT_NOT_FOUND, BuildServer::PROJECT_VERSION_NOT_FOUND]
where(["status in (?) OR (status in (?) AND notified_at >= ?)", [WAITING_FOR_RESPONSE, BUILD_PENDING, BuildServer::BUILD_STARTED], outdatable_statuses, Time.now - 2.days])
@ -63,11 +63,11 @@ class BuildList < ActiveRecord::Base
scope :scoped_to_is_circle, lambda {|is_circle| where(:is_circle => is_circle) }
scope :for_creation_date_period, lambda{|start_date, end_date|
if start_date && end_date
where(["created_at BETWEEN ? AND ?", start_date, end_date])
where(["#{table_name}.created_at BETWEEN ? AND ?", start_date, end_date])
elsif start_date && !end_date
where(["created_at >= ?", start_date])
where(["#{table_name}.created_at >= ?", start_date])
elsif !start_date && end_date
where(["created_at <= ?", end_date])
where(["#{table_name}.created_at <= ?", end_date])
end
}
scope :for_notified_date_period, lambda{|start_date, end_date|

View File

@ -12,7 +12,7 @@ class Download < ActiveRecord::Base
def parse_nginx_log
File.open(PREV_LOG_FILE) do |log|
while (line = log.gets)
if package = line.match( /GET \/.+\/([\w\d]+)-([\d.]+)-((\d+mdv[\d.]+)|([\d\w]+-mdv[\d.]+))\.([\w\d]+)\.rpm/ )
if package = line.match( /GET \/.+\/([\w\d-]+)-([\d.]+)-((\d+mdv[\d.]+)|([\d\w]+-mdv[\d.]+))\.([\w\d]+)\.rpm/ )
increase(
:name => package[1],
:version => package[2],

View File

@ -14,7 +14,9 @@ class Platform < ActiveRecord::Base
has_many :groups, :through => :objects, :source => :object, :source_type => 'Group'
validates :description, :presence => true, :uniqueness => true
validates :name, :uniqueness => true, :presence => true, :format => { :with => /^[a-zA-Z0-9_]+$/ }
if !Rails.env.development?
validates :name, :uniqueness => true, :presence => true, :format => { :with => /^[a-zA-Z0-9_]+$/ }
end
validates :distrib_type, :presence => true, :inclusion => {:in => APP_CONFIG['distr_types']}
before_create :xml_rpc_create, :unless => lambda {Thread.current[:skip]}
@ -22,6 +24,7 @@ class Platform < ActiveRecord::Base
# before_update :check_freezing
after_create lambda { mount_directory_for_rsync unless hidden? }
after_destroy lambda { umount_directory_for_rsync unless hidden? }
after_update :update_owner_relation
scope :by_visibilities, lambda {|v| {:conditions => ['visibility in (?)', v.join(',')]}}
scope :open, where(:visibility => 'open')
@ -60,6 +63,10 @@ class Platform < ActiveRecord::Base
build_path(name)
end
def mount_path
Rails.root.join("public", "downloads", name)
end
def hidden?
visibility == 'hidden'
end
@ -106,31 +113,27 @@ class Platform < ActiveRecord::Base
end
def mount_directory_for_rsync
#FileUtils.rm_rf "#{ Rails.root.join('tmp', 'umount', self.name) }" if File.exist? "#{ Rails.root.join('tmp', 'umount', name) }"
#FileUtils.mkdir_p "#{ Rails.root.join('tmp', 'mount', name) }"
system("sudo mkdir -p #{ Rails.root.join("public", "downloads") }/#{ name }")
system("sudo mount --bind /home/share/platforms/#{ name } #{ Rails.root.join("public", "downloads") }/#{ name }")
#system("sudo cp -f /srv/rosa_build/current/tmp/mount/#{ name }/* /home/share/platforms/#{ name }/repository/")
#system("sudo rm -Rf \"/srv/rosa_build/current/tmp/mount/#{ name }\"")
# umount_directory_for_rsync # TODO ignore errors
system("sudo mkdir -p #{mount_path}")
system("sudo mount --bind #{path} #{mount_path}")
Arch.all.each do |arch|
host = EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
url = "http://#{host}/downloads/#{name}/repository/"
str = "country=Russian Federation,city=Moscow,latitude=52.18,longitude=48.88,bw=1GB,version=2011,arch=#{arch.name},type=distrib,url=#{url}\n"
File.open(Rails.root.join("public", 'downloads', name, "#{name}.#{arch.name}.list"), 'w') {|f| f.write(str) }
File.open(File.join(mount_path, "#{name}.#{arch.name}.list"), 'w') {|f| f.write(str) }
end
end
def umount_directory_for_rsync
system("sudo umount #{ Rails.root.join("public", "downloads") }/#{ name }")
system("sudo rm -Rf #{ Rails.root.join("public", "downloads") }/#{ name }")
#system("rm -Rf \"/srv/rosa_build/current/tmp/umount/#{ name }\"")
#FileUtils.rm_rf "#{ Rails.root.join('tmp', 'mount', name) }" if File.exist? "#{ Rails.root.join('tmp', 'mount', name) }"
#FileUtils.mkdir_p "#{ Rails.root.join('tmp', 'umount', name) }"
system("sudo umount #{mount_path}")
system("sudo rm -Rf #{mount_path}")
end
def make_admin_relation(user_id)
r = self.relations.build :object_id => user_id, :object_type => 'User', :role => 'admin'
r.save
def update_owner_relation
if owner_id_was != owner_id
r = relations.where(:object_id => owner_id_was, :object_type => owner_type_was)[0]
r.update_attributes(:object_id => owner_id, :object_type => owner_type)
end
end
protected

View File

@ -21,28 +21,28 @@
.columns.wat-cf
.column.left
.group
= f.label :status, t("layout.build_lists.created_at_start"), :class => :label
= f.label :created_at_start, t("layout.build_lists.created_at_start"), :class => :label
= f.date_select(:created_at_start, :include_blank => true, :selected => @filter.created_at_start)
.group
= f.label :status, t("layout.build_lists.notified_at_start"), :class => :label
= f.label :notified_at_start, t("layout.build_lists.notified_at_start"), :class => :label
= f.date_select(:notified_at_start, :include_blank => true, :selected => @filter.notified_at_start)
.column.right
.group
= f.label :status, t("layout.build_lists.created_at_end"), :class => :label
= f.label :created_at_end, t("layout.build_lists.created_at_end"), :class => :label
= f.date_select(:created_at_end, :include_blank => true, :selected => @filter.created_at_end)
.group
= f.label :status, t("layout.build_lists.notified_at_end"), :class => :label
= f.label :notified_at_end, t("layout.build_lists.notified_at_end"), :class => :label
= f.date_select(:notified_at_end, :include_blank => true, :selected => @filter.notified_at_end)
.columns.wat-cf
.column.left
.group
= f.label :status, t("layout.build_lists.bs_id_search"), :class => :label
= f.text_field :bs_id, :class => :text_field
= f.label :project_name, t("layout.build_lists.project_name_search"), :class => :label
= f.text_field :project_name, :class => :text_field
.column.right
.group
= f.label :status, t("layout.build_lists.project_name"), :class => :label
= f.text_field :project_name, :class => :text_field
= f.label :bs_id, t("layout.build_lists.bs_id_search"), :class => :label
= f.text_field :bs_id, :class => :text_field
.group.navform.wat-cf
%button.button{ :type => "submit" }

View File

@ -5,6 +5,26 @@
%li.active= link_to t("layout.collaborators.edit"), edit_project_collaborators_path(@project)
.content
.inner
= form_tag add_project_collaborators_path(@project) do
= javascript_include_tag 'autocomplete-rails.js'
.group
%h2.title= t("layout.collaborators.add")
= label_tag "member_uname", t("layout.collaborators.input_username")
= autocomplete_field_tag 'member_id', params[:member_id], autocomplete_user_uname_users_path, :id_element => '#member_id_field'
&nbsp;
= t('layout.or')
&nbsp;
= label_tag "group_uname", t("layout.collaborators.input_groupname")
= autocomplete_field_tag 'group_id', params[:group_id], autocomplete_group_uname_groups_path, :id_element => '#group_id_field'
= hidden_field_tag 'member_id', nil, :id => 'member_id_field'
= hidden_field_tag 'group_id', nil, :id => 'group_id_field'
%br
.group.navform.wat-cf
%button.button{:type => "submit"}
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.add"))
= t("layout.add")
= form_tag project_collaborators_path(@project) do
%h2.title= t("layout.users.list_header")
%table.table
@ -31,8 +51,8 @@
%tr
%th.first ID
%th= t("activerecord.attributes.group.name")
%th= t("activerecord.attributes.group.roles")
%th= t("activerecord.attributes.group.uname")
%th.last= t("layout.collaborators.add")
- @groups.each do |group|
%tr{:class => cycle("odd", "even")}
%td

View File

@ -22,7 +22,7 @@
= link_to user.name, user_path(user)
%td
- Relation::ROLES.each do |role|
= check_box_tag "#{ role }[#{user.id}]", '1', ((parent.relations.exists? :object_id => user.id, :object_type => 'User', :role => role) ? :checked : nil), {:class => "user_role_chbx"}
= check_box_tag "#{ role }[#{user.id}]", '1', ((parent.objects.exists? :object_id => user.id, :object_type => 'User', :role => role) ? :checked : nil), {:class => "user_role_chbx"}
= label_tag "#{ role }[#{user.id}]", t("layout.members.roles.#{ role }")
%td
= user.uname
@ -33,3 +33,15 @@
%span.text_button_padding= t("layout.or")
= link_to t("layout.cancel"), group_path(parent), :class => "text_button_padding link_button"
= form_tag add_group_members_path(parent) do
= javascript_include_tag 'autocomplete-rails.js'
.group
%h2.title= t("layout.members.add_member")
= label_tag "", t("layout.members.input_username")
= autocomplete_field_tag 'user_id', params[:user_id], autocomplete_user_uname_users_path
%br
.group.navform.wat-cf
%button.button{:type => "submit"}
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.add"))
= t("layout.add")

View File

@ -1,29 +1,31 @@
= javascript_include_tag "autocomplete-rails.js"
.group
= f.label :name, :class => :label
= f.text_field :name, :class => 'text_field'
- unless ['edit', 'update'].include? controller.action_name
.group
= f.label :name, :class => :label
= f.text_field :name, :class => 'text_field'
.group
= f.label :description, :class => :label
= f.text_field :description, :class => 'text_field'
.group
= f.label :distrib_type, :class => :label
= f.select :distrib_type, options_for_select(APP_CONFIG['distr_types'])
- unless ['edit', 'update'].include? controller.action_name
.group
= f.label :distrib_type, :class => :label
= f.select :distrib_type, options_for_select(APP_CONFIG['distr_types'])
.group
= f.label :parent, :class => :label
= f.collection_select :parent_platform_id, Platform.all, :id, :description, :include_blank => true
.group
= f.label :parent, :class => :label
= f.collection_select :parent_platform_id, Platform.all, :id, :description, :include_blank => true
.group
= f.label :released, :class => :label
= f.check_box :released, :class => 'check_box'
.group
= label_tag "admin_uname", t("layout.platforms.admin_uname"), :class => :label
= autocomplete_field_tag 'admin_uname', params[:admin_uname], autocomplete_user_uname_platforms_path
=# text_field_tag 'admin_id', '', :id => 'admin_id_field'
= label_tag "", t("layout.platforms.admin_id"), :class => :label
= autocomplete_field_tag 'admin_id', @admin_uname, autocomplete_user_uname_platforms_path, :id_element => '#admin_id_field'
= hidden_field_tag 'admin_id', @admin_id, :id => 'admin_id_field'
.group.navform.wat-cf
%button.button{:type => "submit"}

View File

@ -64,6 +64,7 @@
= link_to t("layout.platforms.freeze"), freeze_platform_path(@platform), :confirm => I18n.t("layout.platforms.confirm_freeze"), :method => :post, :class => "button" if can? :freeze, @platform
= link_to "Клонировать", clone_platform_path(@platform), :class => "button" if can? :clone, @platform
= link_to t("layout.platforms.build_all"), build_all_platform_path(@platform), :confirm => I18n.t("layout.confirm"), :method => :post, :class => "button" if can? :build_all, @platform
= link_to t("layout.platforms.edit"), edit_platform_path(@platform), :class => "button" if can? :edit, @platform
%a{ :name => "repositories" }
.block

8
bin/autostart.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
for f in `ls /srv`
do
su -l rosa -c "cd /srv/$f/current && APP_NAME=$f bundle exec bluepill --no-privileged load /srv/$f/current/config/production.pill"
done
/srv/rosa_build/current/bin/mount_downloads.sh

View File

@ -2,8 +2,9 @@
for f in `ls /srv/rosa_build/shared/downloads`
do
if [ -d "/home/share/platforms/$f" ]
if [ -d /home/share/platforms/$f ]
then
mount --bind "/home/share/platforms/$f" "/srv/rosa_build/shared/downloads/$f"
sudo umount /srv/rosa_build/shared/downloads/$f 2>&1 >> /dev/null
sudo mount --bind /home/share/platforms/$f /srv/rosa_build/shared/downloads/$f
fi
done

View File

@ -1,9 +0,0 @@
#!/bin/bash
for f in `ls /srv/rosa_build/current/tmp/mount`
do
mkdir -p "/srv/rosa_build/shared/downloads/$f"
mount --bind "/home/share/platforms/$f" "/srv/rosa_build/shared/downloads/$f"
cp -f /srv/rosa_build/current/tmp/mount/$f/* /home/share/platforms/$f/repository/
rm -Rf "/srv/rosa_build/current/tmp/mount/$f"
done

View File

@ -1,6 +0,0 @@
#!/bin/bash
mv /srv/rosa_build/shared/log/nginx.access.log /srv/rosa_build/shared/log/nginx.access.log.0
/etc/init.d/nginx reload
chown rosa /srv/rosa_build/shared/log/nginx.access.log.0
# touch /home/rosa/i_was_launched.txt

View File

@ -1,8 +0,0 @@
#!/bin/bash
for f in `ls /srv/rosa_build/current/tmp/umount`
do
umount "/srv/rosa_build/shared/downloads/$f"
rm -Rf "/srv/rosa_build/shared/downloads/$f"
rm -Rf "/srv/rosa_build/current/tmp/umount/$f"
done

View File

@ -29,6 +29,7 @@ set :scm, "git"
require 'lib/recipes/nginx'
require 'lib/recipes/unicorn'
require 'lib/recipes/bluepill'
namespace :deploy do
# task :restart, :roles => :app, :except => { :no_release => true } do
# run "touch #{current_release}/tmp/restart.txt"
@ -50,17 +51,11 @@ namespace :deploy do
run "mkdir -p #{fetch :shared_path}/downloads"
run "ln -nfs #{fetch :shared_path}/downloads/ #{fetch :release_path}/public/downloads"
run "mkdir -p #{fetch :shared_path}/tmp"
run "ln -nfs #{fetch :shared_path}/pids/ #{fetch :shared_path}/tmp/pids"
run "ln -nfs #{fetch :shared_path}/tmp/ #{fetch :release_path}/tmp"
run "mkdir -p #{fetch :release_path}/tmp/mount"
run "mkdir -p #{fetch :release_path}/tmp/umount"
end
end
after "deploy:update_code", "deploy:symlink_all", "deploy:migrate"
after "deploy:restart", "delayed_job:restart", "deploy:cleanup"
after "deploy:restart", "delayed_job:restart", "bluepill:restart", "deploy:cleanup"
require 'cape'
namespace :rake_tasks do

View File

@ -10,6 +10,6 @@ role :db, domain, :primary => true
set :application, "rosa_build_#{stage}"
set :deploy_to, "/srv/#{application}"
set :unicorn_port, 8081
# set :unicorn_port, 8081
before "deploy:restart", "deploy:stub_xml_rpc"

View File

@ -10,6 +10,6 @@ role :db, domain, :primary => true
set :application, "rosa_build_#{stage}"
set :deploy_to, "/srv/#{application}"
set :unicorn_port, 8082
# set :unicorn_port, 8082
before "deploy:restart", "deploy:stub_xml_rpc"

View File

@ -25,3 +25,7 @@ Rosa::Application.configure do
end
require 'stub_xml_rpc'
Rails.application.config.to_prepare {
Platform.send :include, Modules::Models::RsyncStub
}

View File

@ -94,10 +94,11 @@ ru:
confirm_delete: Вы уверены, что хотите удалить эту категорию?
platforms:
admin_uname: Владелец
admin_id: Владелец
build_all: Собрать все
list: Список
new: Создать
edit: Редактировать
new_header: Новая платформа
edit_header: Редактировать
list_header: Платформы
@ -222,11 +223,15 @@ ru:
edit_roles: Редактировать роли
roles_header: Роли для
add_role: Добавить/Удалить роль
input_username: Введите псевдоним пользователя
input_groupname: Введите псевдоним группы
members:
back_to_group: Вернуться к группе
edit: Редактировать список
roles: Роли
add_member: Добавить участника
input_username: Псевдоним пользователя
groups:
list: Список
@ -280,7 +285,7 @@ ru:
notified_at_start: "Время последнего обновления от BS с:"
notified_at_end: "Время последнего обновления от BS по:"
bs_id_search: 'Поиск по Id'
project_name: 'Название проекта'
project_name_search: Поиск по названию проекта
bs_id_not_set: Id еще не присвоен
items_header: Элементы сборки
no_items_data: Данных нет
@ -330,10 +335,17 @@ ru:
collaborators:
successfully_changed: Список коллабораторов успешно изменен
error_in_changing: Ошибка изменения списка коллабораторов
member_already_added: Участник %s уже добавлен
group_already_added: Группа уже добавлена
successfully_added: Участник %s успешно добавлен
error_in_adding: Ошибка при добавлении участника %s
members:
successfully_changed: Список участников успешно изменен
error_in_changing: Ошибка изменения списка участников
successfully_added: Участник успешно добавлен
error_in_adding: Ошибка при добавлении участника
already_added: Пользователь уже добавлен
auto_build_list:
success: Сборка проекта автоматизорована!

34
config/production.pill Normal file
View File

@ -0,0 +1,34 @@
#! /usr/bin/env ruby
app_name = ENV['APP_NAME'] || 'rosa_build'
Bluepill.application(app_name) do |app|
app.uid = app.gid = 'rosa'
app.working_dir = "/srv/#{app_name}/current"
app.process("delayed_job") do |process|
process.start_grace_time = 10.seconds
process.stop_grace_time = 10.seconds
process.restart_grace_time = 10.seconds
process.start_command = "/usr/bin/env RAILS_ENV=production script/delayed_job start"
process.stop_command = "/usr/bin/env RAILS_ENV=production script/delayed_job stop"
process.pid_file = File.join(app.working_dir, 'tmp', 'pids', 'delayed_job.pid')
end
app.process("unicorn") do |process|
process.start_grace_time = 8.seconds
process.stop_grace_time = 5.seconds
process.restart_grace_time = 13.seconds
process.start_command = "bundle exec unicorn -l /tmp/#{app_name}_unicorn.sock -E production -c config/unicorn.rb -D"
process.stop_command = "kill -QUIT {{PID}}"
process.restart_command = "kill -USR2 {{PID}}"
process.pid_file = File.join(app.working_dir, 'tmp', 'pids', 'unicorn.pid')
process.monitor_children do |child_process|
child_process.stop_command = "kill -QUIT {{PID}}"
child_process.checks :mem_usage, :every => 10.seconds, :below => 150.megabytes, :times => [3,4], :fires => :stop
child_process.checks :cpu_usage, :every => 10.seconds, :below => 20, :times => [3,4], :fires => :stop
end
end
end

View File

@ -8,6 +8,7 @@ Rosa::Application.routes.draw do
resources :users do
resources :groups, :only => [:new, :create, :index]
get :autocomplete_user_uname, :on => :collection
end
resources :event_logs, :only => :index
@ -25,7 +26,7 @@ Rosa::Application.routes.draw do
match 'build_lists/' => 'build_lists#all', :as => :all_build_lists
match 'build_lists/:id/cancel/' => 'build_lists#cancel', :as => :build_list_cancel
resources :auto_build_lists, :only => [:index, :create, :destroy]
resources :personal_repositories, :only => [:show] do
@ -78,10 +79,11 @@ Rosa::Application.routes.draw do
end
end
resources :collaborators, :only => [:index, :edit, :update] do
resources :collaborators, :only => [:index, :edit, :update, :add] do
collection do
get :edit
post :update
post :add
end
member do
post :update
@ -108,9 +110,11 @@ Rosa::Application.routes.draw do
end
resources :groups do
resources :members, :only => [:index, :edit, :update] do
get :autocomplete_group_uname, :on => :collection
resources :members, :only => [:index, :edit, :update, :add] do
collection do
get :edit
get :edit
post :add
post :update
end
member do

View File

@ -1,11 +1,10 @@
base_path = File.expand_path(File.join File.dirname(__FILE__), '..')
rails_env = ENV['RAILS_ENV'] || 'production'
worker_processes 4
working_directory base_path # available in 0.94.0+
preload_app true
working_directory File.expand_path(File.join(File.dirname(__FILE__), "..")) # available in 0.94.0+
# listen '/tmp/rosa_build.sock', :backlog => 2048
# listen File.join(base_path, 'tmp', 'pids', 'unicorn.sock')
# listen "/tmp/.sock", :backlog => 64
# listen 8080, :tcp_nopush => true
@ -13,7 +12,7 @@ working_directory File.expand_path(File.join(File.dirname(__FILE__), "..")) # a
timeout 600
# feel free to point this anywhere accessible on the filesystem
pid File.expand_path(File.join(File.dirname(__FILE__), "..")) + '/tmp/pids/unicorn.pid'
pid File.join(base_path, 'tmp', 'pids', 'unicorn.pid')
# REE
# http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
@ -24,8 +23,8 @@ end
# By default, the Unicorn logger will write to stderr.
# Additionally, ome applications/frameworks log to stderr or stdout,
# so prevent them from going to /dev/null when daemonized here:
stderr_path File.expand_path(File.join(File.dirname(__FILE__), "..")) + "/log/unicorn.stderr.log"
stdout_path File.expand_path(File.join(File.dirname(__FILE__), "..")) + "/log/unicorn.stdout.log"
stderr_path File.join(base_path, 'log', 'unicorn.stderr.log')
stdout_path File.join(base_path, 'log', 'unicorn.stdout.log')
# combine REE with "preload_app true" for memory savings
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
@ -42,7 +41,7 @@ before_fork do |server, worker|
# we send it a QUIT.
#
# Using this method we get 0 downtime deploys.
old_pid = File.expand_path(File.join(File.dirname(__FILE__), "..")) + '/tmp/pids/unicorn.pid.oldbin'
old_pid = File.join(base_path, 'tmp', 'pids', '/unicorn.pid.oldbin')
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)

View File

@ -1,3 +1,8 @@
=== Basic bootstrap
* rake db:drop db:setup
==
=== Setup autostart
Add to /etc/rc.d/rc.local following /srv/rosa_build/current/bin/autostart.sh
==

View File

@ -0,0 +1,23 @@
module Modules
module Models
module RsyncStub
extend ActiveSupport::Concern
included do
def mount_directory_for_rsync
true
end
def umount_directory_for_rsync
true
end
end
module InstanceMethods
end
module ClassMethods
end
end
end
end

30
lib/recipes/bluepill.rb Normal file
View File

@ -0,0 +1,30 @@
Capistrano::Configuration.instance(:must_exist).load do
namespace :bluepill do
set(:bluepill_binary) {"bundle exec bluepill --no-privileged"}
desc "Load bluepill configuration and start it"
task :start, :roles => [:app] do
run "cd #{fetch :current_path} && #{try_sudo} APP_NAME=#{fetch :application} #{bluepill_binary} load config/production.pill"
end
desc "Stop processes that bluepill is monitoring"
task :stop, :roles => [:app], :on_error => :continue do
run "cd #{fetch :current_path} && #{try_sudo} #{bluepill_binary} #{fetch :application} stop"
end
task :restart, :roles => [:app] do
# run "cd #{fetch :current_path} && #{try_sudo} #{bluepill_binary} #{fetch :application} restart"
stop; quit; start
end
desc "Stop processes that bluepill is monitoring and quit bluepill"
task :quit, :roles => [:app] do
run "cd #{fetch :current_path} && #{try_sudo} #{bluepill_binary} #{fetch :application} quit"
end
desc "Prints bluepills monitored processes statuses"
task :status, :roles => [:app] do
run "cd #{fetch :current_path} && #{try_sudo} #{bluepill_binary} #{fetch :application} status"
end
end
end

View File

@ -8,7 +8,8 @@ Capistrano::Configuration.instance(:must_exist).load do
task :generate_configuration, :roles => :web, :except => { :no_release => true } do
config = %Q{
upstream #{application}_backend {
server 127.0.0.1:#{unicorn_port};
# server 127.0.0.1:#{unicorn_port rescue 8080};
server unix:/tmp/#{fetch :application}_unicorn.sock;
}
server {

View File

@ -1,12 +1,11 @@
Capistrano::Configuration.instance(:must_exist).load do
namespace :deploy do
set :unicorn_binary, "bundle exec unicorn"
set(:unicorn_config) { "#{fetch :current_path}/config/unicorn.rb" }
set(:unicorn_pid) { "#{fetch :shared_path}/tmp/pids/unicorn.pid" }
set :unicorn_port, 8080
# set :unicorn_port, 8080
task :start, :roles => :app, :except => { :no_release => true } do
run "cd #{fetch :current_path} && #{try_sudo} #{unicorn_binary} -c #{unicorn_config} -p #{unicorn_port} -E #{rails_env} -D"
run "cd #{fetch :current_path} && #{try_sudo} #{unicorn_binary} -l /tmp/#{fetch :application}_unicorn.sock -E #{rails_env} -c config/unicorn.rb -D" # -p #{unicorn_port}
end
task :stop, :roles => :app, :except => { :no_release => true } do
run "#{try_sudo} kill `cat #{unicorn_pid}`" rescue warn 'deploy:stop FAILED'
@ -18,9 +17,8 @@ Capistrano::Configuration.instance(:must_exist).load do
run "#{try_sudo} kill -s USR2 `cat #{unicorn_pid}`" rescue warn 'deploy:reload FAILED'
end
task :restart, :roles => :app, :except => { :no_release => true } do
# reload
stop
start
start # blue pill will do it?
end
end
end

View File

@ -1,17 +1,27 @@
require 'highline/import'
require 'open-uri'
namespace :import do
desc "Load projects"
task :projects => :environment do
open('http://dl.dropbox.com/u/984976/package_list.txt').readlines.each do |name|
source = ENV['SOURCE'] || 'http://dl.dropbox.com/u/984976/package_list.txt'
owner = User.find_by_uname(ENV['OWNER_UNAME']) || Group.find_by_uname(ENV['OWNER_UNAME']) || User.first
platform = Platform.find_by_name(ENV['PLATFORM_NAME']) # 'mandriva2011'
repo = platform.repositories.first rescue nil
say "START import projects from '#{source}' for '#{owner.uname}'.#{repo ? " To repo '#{platform.name}/#{repo.name}'." : ''}"
ask 'Press enter to continue'
open(source).readlines.each do |name|
name.chomp!; name.strip! #; name.downcase!
# name = name.match(/^([a-z\d_\-\+\.]+?)-(\d[a-z\d\-\.]+)\.src\.rpm$/)[1] # parse
print "Import #{name}..."
owner = User.find(1) # I am
# owner = Group.find(1) # Core Team
p = Project.find_or_create_by_name(name) {|p| p.owner = owner}
puts p.persisted? ? "Ok!" : "Fail!"
print "Import '#{name}'..."
p = Project.find_or_create_by_name_and_owner_type_and_owner_id(name, owner.class.to_s, owner.id)
print p.persisted? ? "Ok!" : "Fail!"
if repo
print " Add to repo '#{platform.name}/#{repo.name}'."
repo.projects << p rescue print ' Fail!'
end
puts
end
puts 'DONE'
say 'DONE'
end
end

View File

@ -1,6 +1,21 @@
require 'spec_helper'
describe BuildListsController do
shared_examples_for 'show build list' do
it 'should be able to perform show action' do
get :show, @show_params
response.should be_success
end
end
shared_examples_for 'not show build list' do
it 'should not be able to perform show action' do
get :show, @show_params
response.should redirect_to(forbidden_url)
end
end
context 'crud' do
context 'for guest' do
it 'should not be able to perform all action' do
@ -10,12 +25,58 @@ describe BuildListsController do
end
context 'for user' do
before(:each) { set_session_for Factory(:user) }
before(:each) do
stub_rsync_methods
@build_list = Factory(:build_list_core)
@project = @build_list.project
@owner_user = @project.owner
@member_user = Factory(:user)
rel = @project.relations.build(:role => 'reader')
rel.object = @member_user
rel.save
@user = Factory(:user)
set_session_for(@user)
@show_params = {:project_id => @project.id, :id => @build_list.id}
end
it 'should not be able to perform all action' do
get :all
response.should redirect_to(forbidden_url)
end
context 'for open project' do
it_should_behave_like 'show build list'
context 'if user is project owner' do
before(:each) {set_session_for(@owner_user)}
it_should_behave_like 'show build list'
end
context 'if user is project owner' do
before(:each) {set_session_for(@member_user)}
it_should_behave_like 'show build list'
end
end
context 'for hidden project' do
before(:each) do
@project.visibility = 'hidden'
@project.save
end
it_should_behave_like 'not show build list'
context 'if user is project owner' do
before(:each) {set_session_for(@owner_user)}
it_should_behave_like 'show build list'
end
context 'if user is project owner' do
before(:each) {set_session_for(@member_user)}
it_should_behave_like 'show build list'
end
end
end
context 'for admin' do
@ -35,10 +96,25 @@ describe BuildListsController do
end
context 'filter' do
before(:each) do
stub_rsync_methods
set_session_for Factory(:admin)
end
let(:build_list1) { Factory(:build_list_core) }
let(:build_list2) { Factory(:build_list_core) }
let(:build_list3) { Factory(:build_list_core) }
before(:each) { set_session_for Factory(:admin) }
let(:build_list4) do
b = Factory(:build_list_core)
b.created_at = b.created_at - 1.day
b.project = build_list3.project
b.pl = build_list3.pl
b.arch = build_list3.arch
b.save
b
end
before(:each) { set_session_for Factory(:admin); stub_rsync_methods; }
it 'should filter by bs_id' do
get :all, :filter => {:bs_id => build_list1.bs_id, :project_name => 'fdsfdf', :any_other_field => 'do not matter'}
@ -54,6 +130,18 @@ describe BuildListsController do
assigns[:build_lists].should include(build_list2)
assigns[:build_lists].should_not include(build_list3)
end
it 'should filter by project_name and start_date' do
get :all, :filter => {:project_name => build_list3.project.name,
"created_at_start(1i)"=>build_list3.created_at.year.to_s,
"created_at_start(2i)"=>build_list3.created_at.month.to_s,
"created_at_start(3i)"=>build_list3.created_at.day.to_s}
assigns[:build_lists].should_not include(build_list1)
assigns[:build_lists].should_not include(build_list2)
assigns[:build_lists].should include(build_list3)
assigns[:build_lists].should_not include(build_list4)
# response.should be_success
end
end
context 'callbacks' do

View File

@ -36,12 +36,30 @@ describe CollaboratorsController do
@user = Factory(:user)
@user.relations
set_session_for(@user)
@group = Factory(:group)
@project.relations.create!(:object_type => 'User', :object_id => @user.id, :role => 'reader')
end
it_should_behave_like 'show collaborators list'
it_should_behave_like 'update collaborators'
it_should_behave_like 'update collaborator relation'
it 'should add new collaborator with reader role' do
@params = {:member_id => @another_user.id.to_s, :project_id => @project.id.to_s}
post :add, @params
@project.relations.exists?(:object_type => 'User', :object_id => @another_user.id, :role => 'reader').should be_true
end
it 'should add new group with reader role' do
@params = {:group_id => @group.id.to_s, :project_id => @project.id.to_s}
post :add, @params
@project.relations.exists?(:object_type => 'Group', :object_id => @group.id, :role => 'reader').should be_true
end
it_should_behave_like 'show collaborators list'
it_should_behave_like 'update collaborators'
it_should_behave_like 'update collaborator relation'
end
context 'for owner user' do

View File

@ -1,5 +1,24 @@
require 'spec_helper'
describe MembersController do
before(:each) do
@group = Factory(:group)
@user = @group.owner
set_session_for @user
@another_user = Factory(:user)
@add_params = {:group_id => @group.id, :user_id => @another_user.uname}
end
context 'for owner user' do
it 'should add member to group' do
post :add, @add_params
response.should redirect_to(edit_group_members_path(@group))
Relation.by_target(@group).by_object(@another_user).count.should eql(1)
end
it 'should add reader member to group' do
post :add, @add_params
Relation.by_target(@group).by_object(@another_user).first.role.should eql('reader')
end
end
end

View File

@ -42,11 +42,6 @@ describe PlatformsController do
@admin = Factory(:admin)
@user = Factory(:user)
set_session_for(@admin)
any_instance_of(Platform) do |plat|
stub(plat).mount_directory_for_rsync {|args| true}
stub(plat).umount_directory_for_rsync {|args| true}
end
# any_instance_of(Platform).umount_directory_for_rsync{true}
end
it_should_behave_like 'able_to_perform_index#platforms'
@ -69,13 +64,15 @@ describe PlatformsController do
it_should_behave_like 'change_objects_count_on_destroy_success'
it_should_behave_like 'not_be_able_to_destroy_personal_platform'
context 'when owner uname present' do
it 'should create platform with mentioned owner' do
post :create, @create_params.merge({:admin_uname => @user.uname})
Platform.last.owner.id.should eql(@user.id)
end
it 'should create platform with mentioned owner if owner id present' do
post :create, @create_params.merge({:admin_id => @user.id})
Platform.last.owner.id.should eql(@user.id)
end
it 'should create platform with current user as owner if owner id not present' do
post :create, @create_params
Platform.last.owner.id.should eql(@admin.id)
end
end

View File

@ -213,7 +213,7 @@ describe CanCan do
end
[:manage, :add_project, :remove_project, :change_visibility, :settings].each do |action|
it 'should be able to #{ action } repository' do
it "should be able to #{ action } repository" do
@ability.should be_able_to(action, @repository)
end
end