diff --git a/Gemfile b/Gemfile index 2a7ce25f2..7ed9a93a3 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,7 @@ gem 'resque_mailer', '~> 2.1.0' gem 'perform_later', '~> 1.3.0' # should be after resque_mailer gem 'russian', '~> 0.6.0' gem 'highline', '~> 1.6.11' +gem 'state_machine' # gem 'rugged', '~> 0.16.0' gem 'grack', :git => 'git://github.com/rdblue/grack.git', :require => 'git_http' diff --git a/Gemfile.lock b/Gemfile.lock index 31ab968c5..15dc97662 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -389,6 +389,7 @@ DEPENDENCIES sass-rails (~> 3.2.5) shotgun shoulda + state_machine therubyracer (~> 0.10.1) therubyrhino (~> 1.73.1) trinidad (~> 1.0.2) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e89ed7d79..6b311c6f5 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -71,4 +71,14 @@ $(document).ready(function() { } }); + $(".toggle_btn").click(function() { + var target = $( $(this).attr('data-target') ); + //target.toggle(); + if ( target.css('visibility') == 'hidden' ) { + target.css('visibility', 'visible'); + } else { + target.css('visibility', 'hidden'); + } + return false; + }); }); diff --git a/app/assets/javascripts/extra/build_list.js b/app/assets/javascripts/extra/build_list.js index 8dccd6d86..654fc0d04 100644 --- a/app/assets/javascripts/extra/build_list.js +++ b/app/assets/javascripts/extra/build_list.js @@ -71,7 +71,7 @@ function setBranchSelected() { var pl_id = $('#build_list_save_to_platform_id').val(); // Checks if selected platform is main or not: if ( $('.all_platforms').find('input[type="checkbox"][value=' + pl_id + '].build_bpl_ids').size() > 0 ) { - var pl_name = $('#build_list_save_to_platform_id option[value="' + pl_id + '"]').text().match(/([\w-]+)\/[\w-]+/)[1]; + var pl_name = $('#build_list_save_to_platform_id option[value="' + pl_id + '"]').text().match(/([\w-.]+)\/[\w-.]+/)[1]; var branch_pl_opt = $('#build_list_project_version option[value="latest_' + pl_name + '"]'); // If there is branch we need - set it selected: if ( branch_pl_opt.size() > 0 ) { diff --git a/app/assets/stylesheets/design/custom.scss b/app/assets/stylesheets/design/custom.scss index 65fd753f7..7238a04d4 100644 --- a/app/assets/stylesheets/design/custom.scss +++ b/app/assets/stylesheets/design/custom.scss @@ -1126,6 +1126,17 @@ form.mass_build section.right { margin-right: 50px; } +.toggle { + overflow: hidden; + padding-top: 10px; + display: block; + visibility: hidden; +} + +.min_width_120 { + min-width: 120px; +} + .chzn-select { width: 350px; } diff --git a/app/controllers/platforms/platforms_controller.rb b/app/controllers/platforms/platforms_controller.rb index 347704c40..14058ba36 100644 --- a/app/controllers/platforms/platforms_controller.rb +++ b/app/controllers/platforms/platforms_controller.rb @@ -18,6 +18,7 @@ class Platforms::PlatformsController < Platforms::BaseController if mass_build.save redirect_to(mass_builds_platform_path(@platform), :notice => t("flash.platform.build_all_success")) else + @auto_publish_selected = params[:auto_publish].present? @mass_builds = MassBuild.by_platform(@platform).order('created_at DESC').paginate(:page => params[:page], :per_page => 20) flash[:warning] = mass_build.errors.full_messages.join('. ') flash[:error] = t("flash.platform.build_all_error") @@ -26,9 +27,15 @@ class Platforms::PlatformsController < Platforms::BaseController def mass_builds @mass_builds = MassBuild.by_platform(@platform).order('created_at DESC').paginate(:page => params[:page], :per_page => 20) + @auto_publish_selected = true render :action => :build_all end + def failed_builds_list + @mass_build = MassBuild.find params[:mass_build_id] + render :text => @mass_build.generate_failed_builds_list + end + def index @platforms = @platforms.accessible_by(current_ability, :related).paginate(:page => params[:page], :per_page => 20) end @@ -143,4 +150,11 @@ class Platforms::PlatformsController < Platforms::BaseController def advisories @advisories = @platform.advisories.paginate(:page => params[:page]) end + + def clear + @platform.clear + flash[:notice] = t('flash.repository.clear') + redirect_to edit_platform_path(@platform) + end + end diff --git a/app/controllers/platforms/product_build_lists_controller.rb b/app/controllers/platforms/product_build_lists_controller.rb index daab1ef25..9531cd68c 100644 --- a/app/controllers/platforms/product_build_lists_controller.rb +++ b/app/controllers/platforms/product_build_lists_controller.rb @@ -11,14 +11,13 @@ class Platforms::ProductBuildListsController < Platforms::BaseController before_filter :find_product_build_list, :only => [:status_build] def create - @product.product_build_lists.create! :base_url => "http://#{request.host_with_port}", :notified_at => Time.current + @product.product_build_lists.create! :base_url => "http://#{request.host_with_port}" flash[:notice] = t('flash.product.build_started') redirect_to [@platform, @product] end def status_build @product_build_list.status = params[:status].to_i # ProductBuildList::BUILD_COMPLETED : ProductBuildList::BUILD_FAILED) - @product_build_list.notified_at = Time.current @product_build_list.save! render :nothing => true end @@ -46,7 +45,8 @@ class Platforms::ProductBuildListsController < Platforms::BaseController end def authenticate_product_builder! - unless APP_CONFIG['product_builder_ip'].values.include?(request.remote_ip) + # FIXME: Rails(?) interpret the internal IP as 127.0.0.1 + unless (APP_CONFIG['product_builder_ip'].values + ["127.0.0.1"]).include?(request.remote_ip) render :nothing => true, :status => 403 end end diff --git a/app/controllers/projects/build_lists_controller.rb b/app/controllers/projects/build_lists_controller.rb index 758b584e9..ad3c6603e 100644 --- a/app/controllers/projects/build_lists_controller.rb +++ b/app/controllers/projects/build_lists_controller.rb @@ -94,13 +94,10 @@ class Projects::BuildListsController < Projects::BaseController def publish_build if params[:status].to_i == 0 # ok - @build_list.status = BuildList::BUILD_PUBLISHED - @build_list.package_version = "#{params[:version]}-#{params[:release]}" - system("cd #{@build_list.project.git_repository.path} && git tag #{@build_list.package_version} #{@build_list.commit_hash}") # TODO REDO through grit + @build_list.published else - @build_list.status = BuildList::FAILED_PUBLISH + @build_list.fail_publish end - @build_list.save render :nothing => true, :status => 200 end @@ -119,14 +116,13 @@ class Projects::BuildListsController < Projects::BaseController end def pre_build - @build_list.status = BuildServer::BUILD_STARTED - @build_list.save + @build_list.start_build render :nothing => true, :status => 200 end def post_build - @build_list.status = params[:status] + params[:status].to_i == BuildServer::SUCCESS ? @build_list.build_success : @build_list.build_error @build_list.container_path = params[:container_path] @build_list.save diff --git a/app/models/ability.rb b/app/models/ability.rb index 743572488..f14e06989 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -18,7 +18,7 @@ class Ability can :read, Issue, :project => {:visibility => 'open'} can :search, BuildList can :read, BuildList, :project => {:visibility => 'open'} - can :read, ProductBuildList, :product => {:platform => {:visibility => 'open'}} + can :read, ProductBuildList#, :product => {:platform => {:visibility => 'open'}} # double nested hash don't work can :read, Advisory can(:advisories, Platform) {APP_CONFIG['anonymous_access']} # Core callbacks @@ -91,6 +91,7 @@ class Ability can [:read, :projects_list], Repository, :platform => {:owner_type => 'Group', :owner_id => user.group_ids} can([:read, :projects_list], Repository, read_relations_for('repositories', 'platforms')) {|repository| local_reader? repository.platform} can([:create, :update, :projects_list, :add_project, :remove_project], Repository) {|repository| local_admin? repository.platform} + can(:clear, Platform) {|platform| local_admin?(platform) && platform.platform_type == 'personal'} can([:change_visibility, :settings, :destroy], Repository) {|repository| owner? repository.platform} can :read, Product, :platform => {:visibility => 'open'} @@ -120,6 +121,7 @@ class Ability # Shared cannot rights for all users (registered, admin) cannot :destroy, Platform, :platform_type => 'personal' cannot [:create, :destroy, :add_project, :remove_project], Repository, :platform => {:platform_type => 'personal'} + cannot :clear, Platform, :platform_type => 'main' cannot :destroy, Issue cannot [:members, :add_member, :remove_member, :remove_members], Platform, :platform_type => 'personal' @@ -146,21 +148,16 @@ class Ability relations.actor_type = 'Group' AND relations.actor_id IN (?)))", parent.classify, @user, @user.group_ids] end - def relation_exists_for(target, roles) - target.relations.exists?(:actor_id => @user.id, :actor_type => 'User', :role => roles) or - target.relations.exists?(:actor_id => @user.group_ids, :actor_type => 'Group', :role => roles) - end - def local_reader?(target) - relation_exists_for(target, %w{reader writer admin}) or owner?(target) + %w{reader writer admin}.include? @user.best_role(target) end def local_writer?(target) - relation_exists_for(target, %w{writer admin}) or owner?(target) + %w{writer admin}.include? @user.best_role(target) end def local_admin?(target) - relation_exists_for(target, 'admin') or owner?(target) + @user.best_role(target) == 'admin' end def owner?(target) diff --git a/app/models/build_list.rb b/app/models/build_list.rb index 65202ee0e..14ccd466d 100644 --- a/app/models/build_list.rb +++ b/app/models/build_list.rb @@ -6,7 +6,7 @@ class BuildList < ActiveRecord::Base belongs_to :build_for_platform, :class_name => 'Platform' belongs_to :user belongs_to :advisory - belongs_to :mass_build + belongs_to :mass_build, :counter_cache => true has_many :items, :class_name => "BuildList::Item", :dependent => :destroy has_many :packages, :class_name => "BuildList::Package", :dependent => :destroy @@ -96,10 +96,121 @@ class BuildList < ActiveRecord::Base serialize :additional_repos serialize :include_repos - before_create :set_default_status - after_create :place_build + after_commit :place_build after_destroy :delete_container + @queue = :clone_and_build + + state_machine :status, :initial => :waiting_for_response do + + # WTF? around_transition -> infinite loop + before_transition do |build_list, transition| + if build_list.mass_build && MassBuild::COUNT_STATUSES.include?(build_list.status) + MassBuild.decrement_counter "#{BuildList::HUMAN_STATUSES[build_list.status].to_s}_count", build_list.mass_build_id + end + end + + after_transition do |build_list, transition| + if build_list.mass_build && MassBuild::COUNT_STATUSES.include?(build_list.status) + MassBuild.increment_counter "#{BuildList::HUMAN_STATUSES[build_list.status].to_s}_count", build_list.mass_build_id + end + end + + after_transition :on => :published, :do => :set_version_and_tag + + event :place_build do + transition :waiting_for_response => :build_pending, :if => lambda { |build_list| + build_list.add_to_queue == BuildServer::SUCCESS + } + [ + 'BuildList::BUILD_PENDING', + 'BuildServer::PLATFORM_PENDING', + 'BuildServer::PLATFORM_NOT_FOUND', + 'BuildServer::PROJECT_NOT_FOUND', + 'BuildServer::PROJECT_VERSION_NOT_FOUND' + ].each do |code| + transition :waiting_for_response => code.demodulize.downcase.to_sym, :if => lambda { |build_list| + build_list.add_to_queue == code.constantize + } + end + end + + event :start_build do + transition [ :build_pending, + :platform_pending, + :platform_not_found, + :project_not_found, + :project_version_not_found ] => :build_started + end + + event :cancel do + transition [:build_pending, :platform_pending] => :build_canceled, :if => lambda { |build_list| + build_list.can_cancel? && BuildServer.delete_build_list(build_list.bs_id) == BuildServer::SUCCESS + } + end + + event :published do + transition [:build_publish, :rejected_publish] => :build_published + end + + event :fail_publish do + transition [:build_publish, :rejected_publish] => :failed_publish + end + + event :publish do + transition [:success, :failed_publish] => :build_publish, :if => lambda { |build_list| + BuildServer.publish_container(build_list.bs_id) == BuildServer::SUCCESS + } + transition [:success, :failed_publish] => :failed_publish + end + + event :reject_publish do + transition :success => :rejected_publish, :if => :can_reject_publish? + end + + event :build_success do + transition [:build_started, :build_canceled] => :success + end + + event :build_error do + transition [:build_started, :build_canceled] => :build_error + end + + HUMAN_STATUSES.each do |code,name| + state name, :value => code + end + end + + later :publish, :queue => :clone_build + + def set_version_and_tag + pkg = self.packages.where(:package_type => 'source', :project_id => self.project_id).first + # TODO: remove 'return' after deployment ABF kernel 2.0 + return if pkg.nil? # For old client that does not sends data about packages + self.package_version = "#{pkg.platform.name}-#{pkg.version}-#{pkg.release}" + system("cd #{self.project.git_repository.path} && git tag #{self.package_version} #{self.commit_hash}") # TODO REDO through grit + save + end + + #TODO: Share this checking on product owner. + def can_cancel? + [BUILD_PENDING, BuildServer::PLATFORM_PENDING].include?(status) && bs_id + end + + def can_publish? + [BuildServer::SUCCESS, FAILED_PUBLISH].include? status + end + + def can_reject_publish? + can_publish? and save_to_platform.released + end + + + def add_to_queue + #XML-RPC params: project_name, project_version, plname, arch, bplname, update_type, build_requires, id_web, include_repos, priority + @status ||= BuildServer.add_build_list project.name, project_version, save_to_platform.name, arch.name, (save_to_platform_id == build_for_platform_id ? '' : build_for_platform.name), update_type, build_requires, id, include_repos, priority + end + def self.human_status(status) I18n.t("layout.build_lists.statuses.#{HUMAN_STATUSES[status]}") end @@ -126,39 +237,6 @@ class BuildList < ActiveRecord::Base end end - def publish - return false unless can_publish? - has_published = BuildServer.publish_container bs_id - update_attribute(:status, has_published == 0 ? BUILD_PUBLISH : FAILED_PUBLISH) - return has_published == 0 - end - later :publish, :loner => true, :queue => :clone_build - - def can_publish? - status == BuildServer::SUCCESS or status == FAILED_PUBLISH - end - - def reject_publish - return false unless can_reject_publish? - update_attribute(:status, REJECTED_PUBLISH) - end - - def can_reject_publish? - can_publish? and save_to_platform.released - end - - def cancel - return false unless can_cancel? - has_canceled = BuildServer.delete_build_list bs_id - update_attribute(:status, BUILD_CANCELED) if has_canceled == 0 - return has_canceled == 0 - end - - #TODO: Share this checking on product owner. - def can_cancel? - status == BUILD_PENDING && bs_id - end - def event_log_message {:project => project.name, :version => project_version, :arch => arch.name}.inspect end @@ -182,19 +260,6 @@ class BuildList < ActiveRecord::Base protected - def set_default_status - self.status = WAITING_FOR_RESPONSE unless self.status.present? - return true - end - - def place_build - #XML-RPC params: project_name, project_version, plname, arch, bplname, update_type, build_requires, id_web, include_repos, priority - self.status = BuildServer.add_build_list project.name, project_version, save_to_platform.name, arch.name, (save_to_platform_id == build_for_platform_id ? '' : build_for_platform.name), update_type, build_requires, id, include_repos, priority - self.status = BUILD_PENDING if self.status == 0 - save - end - - def delete_container if can_cancel? BuildServer.delete_build_list bs_id diff --git a/app/models/build_list_observer.rb b/app/models/build_list_observer.rb index 50ef167cd..bc54e088d 100644 --- a/app/models/build_list_observer.rb +++ b/app/models/build_list_observer.rb @@ -7,13 +7,13 @@ class BuildListObserver < ActiveRecord::Observer if [BuildServer::BUILD_ERROR, BuildServer::SUCCESS].include? record.status # stores time interval beetwin build start and finish in seconds record.duration = record.current_duration - + if record.status == BuildServer::SUCCESS # Update project average build time build_count = record.project.build_count new_av_time = ( record.project.average_build_time * build_count + record.duration ) / ( build_count + 1 ) record.project.update_attributes({ :average_build_time => new_av_time, :build_count => build_count + 1 }, :without_protection => true) - end + end end end end diff --git a/app/models/git_hook.rb b/app/models/git_hook.rb index ed9639902..cb7037619 100644 --- a/app/models/git_hook.rb +++ b/app/models/git_hook.rb @@ -5,7 +5,7 @@ class GitHook include Resque::Plugins::Status - def initialize(owner_uname, repo, newrev, oldrev, ref, newrev_type, oldrev_type) + def initialize(owner_uname, repo, newrev, oldrev, ref, newrev_type, oldrev_type = nil) @repo, @newrev, @oldrev, @refname, @newrev_type, @oldrev_type = repo, newrev, oldrev, ref, newrev_type, oldrev_type if @owner = User.where(:uname => owner_uname).first || Group.where(:uname => owner_uname).first! @project = @owner.own_projects.where(:name => repo).first! diff --git a/app/models/mass_build.rb b/app/models/mass_build.rb index 1c2f5c3ad..3c13d754a 100644 --- a/app/models/mass_build.rb +++ b/app/models/mass_build.rb @@ -12,6 +12,15 @@ class MassBuild < ActiveRecord::Base after_create :build_all + COUNT_STATUSES = [ + :build_lists, + :build_published, + :build_pending, + :build_started, + :build_publish, + :build_error + ] + def initialize(args = nil) super @@ -32,4 +41,13 @@ class MassBuild < ActiveRecord::Base :auto_publish => self.auto_publish ) # later with resque end + + def generate_failed_builds_list + report = "" + BuildList.where(:status => BuildServer::BUILD_ERROR, :mass_build_id => self.id).each do |build_list| + report << "ID: #{build_list.id}; " + report << "PROJECT_NAME: #{build_list.project.name}\n" + end + report + end end diff --git a/app/models/platform.rb b/app/models/platform.rb index 580def2c8..95cc24ba2 100644 --- a/app/models/platform.rb +++ b/app/models/platform.rb @@ -48,6 +48,10 @@ class Platform < ActiveRecord::Base include Modules::Models::Owner + def clear + system("rm -Rf #{ APP_CONFIG['root_path'] }/platforms/#{ self.name }/repository/*") + end + def urpmi_list(host, pair = nil) blank_pair = {:login => 'login', :pass => 'password'} pair = blank_pair if pair.blank? @@ -184,7 +188,7 @@ class Platform < ActiveRecord::Base def destroy with_skip {super} # avoid cascade XML RPC requests end - later :destroy, :loner => true, :queue => :clone_build + later :destroy, :queue => :clone_build protected diff --git a/app/models/product_build_list.rb b/app/models/product_build_list.rb index eb7569b61..774f1d0ca 100644 --- a/app/models/product_build_list.rb +++ b/app/models/product_build_list.rb @@ -20,11 +20,11 @@ class ProductBuildList < ActiveRecord::Base validates :status, :inclusion => { :in => [BUILD_STARTED, BUILD_COMPLETED, BUILD_FAILED] } attr_accessor :base_url - attr_accessible :status, :notified_at, :base_url + attr_accessible :status, :base_url attr_readonly :product_id - scope :default_order, order('notified_at DESC') + scope :default_order, order('updated_at DESC') scope :for_status, lambda {|status| where(:status => status) } scope :for_user, lambda { |user| where(:user_id => user.id) } scope :scoped_to_product_name, lambda {|product_name| joins(:product).where('products.name LIKE ?', "%#{product_name}%")} diff --git a/app/models/project.rb b/app/models/project.rb index fb0e06e3f..e00e74a11 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -41,7 +41,7 @@ class Project < ActiveRecord::Base after_create :attach_to_personal_repository after_create :create_git_repo - after_create {|p| p.fork_git_repo unless is_root?} # later with resque + after_create {|p| p.fork_git_repo unless p.is_root?} after_save :create_wiki after_destroy :destroy_git_repo @@ -247,15 +247,15 @@ class Project < ActiveRecord::Base def create_git_repo if is_root? Grit::Repo.init_bare(path) - write_hook # later with resque + write_hook end end def fork_git_repo dummy = Grit::Repo.new(path) rescue parent.git_repository.repo.fork_bare(path) - now_write_hook + write_hook end - later :fork_git_repo, :loner => true, :queue => :fork_import + later :fork_git_repo, :queue => :fork_import def destroy_git_repo FileUtils.rm_rf path @@ -267,7 +267,7 @@ class Project < ActiveRecord::Base self.srpm = nil; save # clear srpm end end - later :import_attached_srpm, :loner => true, :queue => :fork_import + later :import_attached_srpm, :queue => :fork_import def create_wiki if has_wiki && !FileTest.exist?(wiki_path) @@ -300,5 +300,4 @@ class Project < ActiveRecord::Base rescue Exception # FIXME end - later :write_hook, :loner => true, :queue => :hook end diff --git a/app/models/user.rb b/app/models/user.rb index 19771bdd5..7bbd42965 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -129,4 +129,28 @@ class User < ActiveRecord::Base false end end + + def best_role target + roles = target_roles(target) + return nil if roles.count == 0 + %w(admin writer reader).each {|role| return role if roles.include?(role)} + raise "unknown user #{self.uname} roles #{roles}" + end + + protected + + def target_roles target + rel, gr, roles = target.relations, self.groups, [] + + if target.owner.class == Group + owner_group = self.groups.where(:id => target.owner.id).first + roles += owner_group.actors.where(:actor_id => self) if owner_group# user group is owner + + gr = gr.where('groups.id != ?', target.owner.id) # exclude target owner group from users group list + end + roles += rel.where(:actor_id => self.id, :actor_type => 'User') # user is member + roles += rel.where(:actor_id => gr, :actor_type => 'Group') # user group is member + roles.map(&:role).uniq + end + end diff --git a/app/views/platforms/platforms/build_all.html.haml b/app/views/platforms/platforms/build_all.html.haml index 5a204a00a..67b275ac9 100644 --- a/app/views/platforms/platforms/build_all.html.haml +++ b/app/views/platforms/platforms/build_all.html.haml @@ -19,7 +19,7 @@ .both %h3= t("activerecord.attributes.build_list.preferences") .both.bottom_20 - = check_box_tag :auto_publish, true, params[:auto_publish].present? ? params[:auto_publish].present? : false, :id => 'auto_publish' + = check_box_tag :auto_publish, true, @auto_publish_selected, :id => 'auto_publish' = label_tag :auto_publish %br @@ -30,16 +30,31 @@ %tr %th.lpadding16= t('activerecord.attributes.mass_build.id') %th.lpadding16= t('activerecord.attributes.mass_build.name') - %th.lpadding16= t('activerecord.attributes.mass_build.arch_names') - %th.lpadding16= t('activerecord.attributes.mass_build.user') - %th.lpadding16= t('activerecord.attributes.mass_build.auto_publish') - %th.lpadding16= t('activerecord.attributes.mass_build.created_at') + %th.lpadding16= t("layout.mass_builds.statuses") + %th.lpadding16= t("layout.mass_builds.failed_builds_list") + %th.lpadding16= t("layout.mass_builds.extended_data") - @mass_builds.each do |mass_build| %tr %td= mass_build.id %td= link_to mass_build.name, build_lists_path(:filter => {:mass_build_id => mass_build.id}) - %td= mass_build.arch_names - %td= link_to mass_build.user.fullname, mass_build.user - %td= mass_build.auto_publish - %td= mass_build.created_at + %td.min_width_120 + - MassBuild::COUNT_STATUSES.each do |status| + = link_to t("layout.build_lists.statuses.#{status}") + ": ", build_lists_path(:filter => {:status => status, :mass_build_id => mass_build.id}) + = mass_build.read_attribute "#{status}_count" + .both + %td= link_to t("layout.mass_builds.failed_builds_list"), failed_builds_list_platforms_path(:mass_build_id => mass_build.id), :target => "_blank" + %td + %a.toggle_btn{:href => "#toggle_#{ mass_build.id }", :'data-target' => "#toggle_#{ mass_build.id }"}= t("layout.mass_builds.extended_data") + .toggle{:id => "toggle_#{ mass_build.id }"} + = t('activerecord.attributes.mass_build.arch_names') + ": " + = mass_build.arch_names + .both + = t('activerecord.attributes.mass_build.user') + ": " + = link_to mass_build.user.fullname, mass_build.user + .both + = t('activerecord.attributes.mass_build.auto_publish') + ": " + = mass_build.auto_publish + .both + = t('activerecord.attributes.mass_build.created_at') + ": " + = mass_build.created_at = will_paginate @mass_builds diff --git a/app/views/platforms/platforms/edit.html.haml b/app/views/platforms/platforms/edit.html.haml index a397e71d1..18442734e 100644 --- a/app/views/platforms/platforms/edit.html.haml +++ b/app/views/platforms/platforms/edit.html.haml @@ -9,3 +9,8 @@ .hr .leftside= t("layout.platforms.delete_warning") .rightside= link_to t("layout.delete"), platform_path(@platform), :method => :delete, :confirm => t("layout.platforms.confirm_delete"), :class => 'button' +- if can? :clear, @platform + .hr + .leftside= t("layout.repositories.clear_warning") + .rightside= link_to t("layout.repositories.clear"), clear_platform_path(@platform), :class => 'button', :confirm => t('layout.repositories.clear_confirm'), :method => :post + .both diff --git a/app/views/platforms/product_build_lists/_product_build_list.html.haml b/app/views/platforms/product_build_lists/_product_build_list.html.haml index ac8dcf130..47cd0d8a5 100644 --- a/app/views/platforms/product_build_lists/_product_build_list.html.haml +++ b/app/views/platforms/product_build_lists/_product_build_list.html.haml @@ -3,6 +3,5 @@ %td= product_build_list.human_status %td= link_to nil, product_build_list.container_path %td= link_to product_build_list.product.name, platform_product_path(product_build_list.product.platform, product_build_list.product) - -#%td= link_to product_build_list.user.try(:fullname), product_build_list.user %td= link_to image_tag('x.png'), platform_product_product_build_list_path(product_build_list.product.platform, product_build_list.product, product_build_list), :method => :delete, :confirm => t("layout.confirm") if can? :destroy, product_build_list - %td= l(product_build_list.notified_at, :format => :long) + %td= l(product_build_list.updated_at, :format => :long) \ No newline at end of file diff --git a/app/views/platforms/product_build_lists/index.html.haml b/app/views/platforms/product_build_lists/index.html.haml index 7103bcfe9..494484f71 100644 --- a/app/views/platforms/product_build_lists/index.html.haml +++ b/app/views/platforms/product_build_lists/index.html.haml @@ -6,7 +6,6 @@ %th.lpadding16= t("activerecord.attributes.product_build_list.status") %th.lpadding16= t("activerecord.attributes.product_build_list.container_path") %th.lpadding16= t("activerecord.attributes.product_build_list.product") - -#%th.lpadding16= t("activerecord.attributes.product_build_list.user") %th= t("layout.product_build_lists.action") %th.lpadding16= t("activerecord.attributes.product_build_list.notified_at") %tbody= render :partial => 'platforms/product_build_lists/product_build_list', :collection => @product_build_lists diff --git a/app/views/platforms/repositories/show.html.haml b/app/views/platforms/repositories/show.html.haml index dedcb69e6..5540913de 100644 --- a/app/views/platforms/repositories/show.html.haml +++ b/app/views/platforms/repositories/show.html.haml @@ -12,4 +12,4 @@ - if can? :add_project, @repository = link_to t("layout.projects.add"), add_project_platform_repository_path(@platform, @repository), :class => 'button' -= render 'proj_list' \ No newline at end of file += render 'proj_list' diff --git a/app/views/projects/build_lists/_build_list.html.haml b/app/views/projects/build_lists/_build_list.html.haml index abb5f43b8..9eb7b1380 100644 --- a/app/views/projects/build_lists/_build_list.html.haml +++ b/app/views/projects/build_lists/_build_list.html.haml @@ -6,5 +6,5 @@ %td= link_to build_list.project_version, "#" %td= build_list.arch.name %td= link_to build_list.user.try(:fullname), build_list.user - %td= link_to image_tag('x.png', :class => 'delete-row', :id => "delete-row#{build_list_counter}"), cancel_build_list_path(build_list), :method => :put, :confirm => t('layout.confirm') if build_list.can_cancel? and can?(:cancel, build_list) + %td= link_to image_tag('x.png', :class => 'delete-row', :id => "delete-row#{build_list_counter}"), cancel_build_list_path(build_list), :method => :put, :confirm => t('layout.confirm') if can?(:cancel, build_list) %td= build_list.updated_at diff --git a/app/views/projects/projects/_project.html.haml b/app/views/projects/projects/_project.html.haml index 537a266b6..f5514643f 100644 --- a/app/views/projects/projects/_project.html.haml +++ b/app/views/projects/projects/_project.html.haml @@ -11,7 +11,7 @@ %td - c = participant_class(alone_member, project) %span{:class => c, :title => t("layout.relations.#{c}")} - = t("layout.collaborators.role_names.#{project.relations.by_user_through_groups(current_user).first.role}") + = t("layout.collaborators.role_names.#{current_user.best_role project}") %td.td5 - unless project.owner == current_user or !alone_member = link_to remove_user_project_path(project), :method => :delete, :confirm => t("layout.confirm") do diff --git a/app/views/projects/projects/_project.json.jbuilder b/app/views/projects/projects/_project.json.jbuilder index 92e639a63..4052c1171 100644 --- a/app/views/projects/projects/_project.json.jbuilder +++ b/app/views/projects/projects/_project.json.jbuilder @@ -5,7 +5,7 @@ json.project do |proj| proj.description project.description proj.link project_path(project) - proj.role t("layout.collaborators.role_names.#{project.relations.by_user_through_groups(current_user).first.role}").force_encoding(Encoding::UTF_8) + proj.role t("layout.collaborators.role_names.#{current_user.best_role project}").force_encoding(Encoding::UTF_8) proj.leave_link remove_user_project_path(project) unless project.owner == current_user or !alone_member? project proj.rights_class participant_class(alone_member?(project), project) diff --git a/config/locales/models/build_list.en.yml b/config/locales/models/build_list.en.yml index 33c24080e..139ae436b 100644 --- a/config/locales/models/build_list.en.yml +++ b/config/locales/models/build_list.en.yml @@ -97,6 +97,7 @@ en: git_error: Git error statuses: + build_lists: All build_error: Build error build_published: Build has been published rejected_publish: Publishing rejected diff --git a/config/locales/models/build_list.ru.yml b/config/locales/models/build_list.ru.yml index 34b2dbdf8..910292188 100644 --- a/config/locales/models/build_list.ru.yml +++ b/config/locales/models/build_list.ru.yml @@ -96,6 +96,7 @@ ru: git_error: проблема с гит statuses: + build_lists: Всего build_error: ошибка сборки build_published: опубликован rejected_publish: публикация отклонена diff --git a/config/locales/models/mass_build.en.yml b/config/locales/models/mass_build.en.yml index 9d60859d1..508bc8507 100644 --- a/config/locales/models/mass_build.en.yml +++ b/config/locales/models/mass_build.en.yml @@ -2,6 +2,9 @@ en: layout: mass_builds: repositories: Repositories + extended_data: Extended data + failed_builds_list: Failed Builds List + statuses: Statuses activerecord: models: mass_build: Mass Build diff --git a/config/locales/models/mass_build.ru.yml b/config/locales/models/mass_build.ru.yml index 2954a4101..b5d0fee6f 100644 --- a/config/locales/models/mass_build.ru.yml +++ b/config/locales/models/mass_build.ru.yml @@ -2,6 +2,9 @@ ru: layout: mass_builds: repositories: Репозитории + extended_data: Параметры задания + failed_builds_list: Список ошибок сборок + statuses: Статусы activerecord: models: mass_build: Массовая Сборка diff --git a/config/locales/models/product_build_list.en.yml b/config/locales/models/product_build_list.en.yml index 1e047e4aa..6f6892274 100644 --- a/config/locales/models/product_build_list.en.yml +++ b/config/locales/models/product_build_list.en.yml @@ -10,7 +10,7 @@ en: '2': 'build in progress' build_failed: Build failed build_started: Build in progress - build_completed: Build + build_completed: Builded ownership: header: Build list ownership diff --git a/config/locales/models/relation.ru.yml b/config/locales/models/relation.ru.yml index 884c03692..51202e88e 100644 --- a/config/locales/models/relation.ru.yml +++ b/config/locales/models/relation.ru.yml @@ -3,5 +3,5 @@ ru: relations: user_owner: Я - владелец group_owner: Я состою в группе-владельце - user: Я участник + user: Я - участник group: Я состою в группе-участнике diff --git a/config/locales/models/repository.en.yml b/config/locales/models/repository.en.yml index 2b6f40dd5..7f8ad732b 100644 --- a/config/locales/models/repository.en.yml +++ b/config/locales/models/repository.en.yml @@ -14,6 +14,9 @@ en: back_to_the_list: ⇐ List of repositories confirm_delete: Are you sure you want to delete this repository? current_repository_header: Current repository + clear: Clear + clear_confirm: Are you sure you want to clear this platform? + clear_warning: Attention! Cleared packages cannot be restored! personal_repositories: settings_header: Settings @@ -32,6 +35,7 @@ en: project_not_added: Project adding error. A project with such name already exists in this repository. Remove the old project first project_removed: Project deleted project_not_removed: Unable to delete project from repository + clear: Platform successfully cleared! activerecord: models: diff --git a/config/locales/models/repository.ru.yml b/config/locales/models/repository.ru.yml index b6c1922c5..b01307e1c 100644 --- a/config/locales/models/repository.ru.yml +++ b/config/locales/models/repository.ru.yml @@ -14,6 +14,9 @@ ru: back_to_the_list: ⇐ К списку репозиториев confirm_delete: Вы уверены, что хотите удалить этот репозиторий? current_repository_header: Текущий репозиторий + clear: Очистить + clear_confirm: Уверены, что хотите очистить платформу? + clear_warning: Внимание! Очищенные пакеты не могут быть восстановлены! personal_repositories: settings_header: Настройки @@ -32,6 +35,7 @@ ru: project_not_added: Не удалось добавить проект. В этом репозитории уже есть проект с таким именем. Сначала нужно удалить старый проект project_removed: Проект удален из репозитория project_not_removed: Не удалось удалить проект из репозитория + clear: Платформа успешно очищена! activerecord: models: diff --git a/config/routes.rb b/config/routes.rb index 385e002e0..35caea079 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -46,6 +46,7 @@ Rosa::Application.routes.draw do resources :platforms do resources :private_users, :except => [:show, :destroy, :update] member do + post :clear get :clone get :members post :remove_members @@ -56,6 +57,9 @@ Rosa::Application.routes.draw do get :mass_builds get :advisories end + collection do + get :failed_builds_list + end get :autocomplete_user_uname, :on => :collection resources :repositories do member do @@ -72,6 +76,7 @@ Rosa::Application.routes.draw do match '/private/:platform_name/*file_path' => 'privates#show' resources :product_build_lists, :only => [:index] + match 'product_status', :to => 'product_build_lists#status_build' end scope :module => 'users' do @@ -115,7 +120,6 @@ Rosa::Application.routes.draw do match 'build_lists/pre_build', :to => "build_lists#pre_build" match 'build_lists/circle_build', :to => "build_lists#circle_build" match 'build_lists/new_bbdt', :to => "build_lists#new_bbdt" - match 'product_status', :to => 'product_build_lists#status_build' resources :build_lists, :only => [:index, :show, :update] do member do @@ -177,31 +181,33 @@ Rosa::Application.routes.draw do get '/sections' => 'projects#sections', :as => :sections_project post '/sections' => 'projects#sections' delete '/remove_user' => 'projects#remove_user', :as => :remove_user_project - # Tree - get '/' => "git/trees#show", :as => :project - get '/tree/:treeish(/*path)' => "git/trees#show", :defaults => {:treeish => :master}, :as => :tree, :format => false - # Commits - get '/commits/:treeish(/*path)' => "git/commits#index", :defaults => {:treeish => :master}, :as => :commits, :format => false - get '/commit/:id(.:format)' => "git/commits#show", :as => :commit - # Commit comments - post '/commit/:commit_id/comments(.:format)' => "comments#create", :as => :project_commit_comments - get '/commit/:commit_id/comments/:id(.:format)' => "comments#edit", :as => :edit_project_commit_comment - put '/commit/:commit_id/comments/:id(.:format)' => "comments#update", :as => :project_commit_comment - delete '/commit/:commit_id/comments/:id(.:format)' => "comments#destroy" - # Commit subscribes - post '/commit/:commit_id/subscribe' => "commit_subscribes#create", :as => :subscribe_commit - delete '/commit/:commit_id/unsubscribe' => "commit_subscribes#destroy", :as => :unsubscribe_commit - # Editing files - get '/blob/:treeish/*path/edit' => "git/blobs#edit", :defaults => {:treeish => :master}, :as => :edit_blob - put '/blob/:treeish/*path' => "git/blobs#update", :defaults => {:treeish => :master}, :format => false - # Blobs - get '/blob/:treeish/*path' => "git/blobs#show", :defaults => {:treeish => :master}, :as => :blob, :format => false - # Blame - get '/blame/:treeish/*path' => "git/blobs#blame", :defaults => {:treeish => :master}, :as => :blame, :format => false - # Raw - get '/raw/:treeish/*path' => "git/blobs#raw", :defaults => {:treeish => :master}, :as => :raw, :format => false - # Archive - get '/archive/:format/tree/:treeish' => "git/trees#archive", :defaults => {:treeish => :master}, :as => :archive, :format => /zip|tar/ + constraints :treeish => /[^\/]+/ do + # Tree + get '/' => "git/trees#show", :as => :project + get '/tree/:treeish(/*path)' => "git/trees#show", :defaults => {:treeish => :master}, :as => :tree, :format => false + # Commits + get '/commits/:treeish(/*path)' => "git/commits#index", :defaults => {:treeish => :master}, :as => :commits, :format => false + get '/commit/:id(.:format)' => "git/commits#show", :as => :commit + # Commit comments + post '/commit/:commit_id/comments(.:format)' => "comments#create", :as => :project_commit_comments + get '/commit/:commit_id/comments/:id(.:format)' => "comments#edit", :as => :edit_project_commit_comment + put '/commit/:commit_id/comments/:id(.:format)' => "comments#update", :as => :project_commit_comment + delete '/commit/:commit_id/comments/:id(.:format)' => "comments#destroy" + # Commit subscribes + post '/commit/:commit_id/subscribe' => "commit_subscribes#create", :as => :subscribe_commit + delete '/commit/:commit_id/unsubscribe' => "commit_subscribes#destroy", :as => :unsubscribe_commit + # Editing files + get '/blob/:treeish/*path/edit' => "git/blobs#edit", :defaults => {:treeish => :master}, :as => :edit_blob + put '/blob/:treeish/*path' => "git/blobs#update", :defaults => {:treeish => :master}, :format => false + # Blobs + get '/blob/:treeish/*path' => "git/blobs#show", :defaults => {:treeish => :master}, :as => :blob, :format => false + # Blame + get '/blame/:treeish/*path' => "git/blobs#blame", :defaults => {:treeish => :master}, :as => :blame, :format => false + # Raw + get '/raw/:treeish/*path' => "git/blobs#raw", :defaults => {:treeish => :master}, :as => :raw, :format => false + # Archive + get '/archive/:format/tree/:treeish' => "git/trees#archive", :defaults => {:treeish => :master}, :as => :archive, :format => /zip|tar/ + end end end diff --git a/db/migrate/20120622092725_add_counters_to_mass_builds.rb b/db/migrate/20120622092725_add_counters_to_mass_builds.rb new file mode 100644 index 000000000..5b0ed2e73 --- /dev/null +++ b/db/migrate/20120622092725_add_counters_to_mass_builds.rb @@ -0,0 +1,10 @@ +class AddCountersToMassBuilds < ActiveRecord::Migration + def change + add_column :mass_builds, :build_lists_count, :integer, :default => 0 + add_column :mass_builds, :build_published_count, :integer, :default => 0 + add_column :mass_builds, :build_pending_count, :integer, :default => 0 + add_column :mass_builds, :build_started_count, :integer, :default => 0 + add_column :mass_builds, :build_publish_count, :integer, :default => 0 + add_column :mass_builds, :build_error_count, :integer, :default => 0 + end +end diff --git a/db/migrate/20120628165702_remove_product_notified_at.rb b/db/migrate/20120628165702_remove_product_notified_at.rb new file mode 100644 index 000000000..fe8ec3436 --- /dev/null +++ b/db/migrate/20120628165702_remove_product_notified_at.rb @@ -0,0 +1,9 @@ +class RemoveProductNotifiedAt < ActiveRecord::Migration + def up + remove_column :product_build_lists, :notified_at + end + + def down + add_column :product_build_lists, :notified_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 535ffe778..47f6661ca 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120609163454) do +ActiveRecord::Schema.define(:version => 20120628165702) do create_table "activity_feeds", :force => true do |t| t.integer "user_id", :null => false @@ -206,11 +206,17 @@ ActiveRecord::Schema.define(:version => 20120609163454) do create_table "mass_builds", :force => true do |t| t.integer "platform_id" t.string "name" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.string "arch_names" t.integer "user_id" - t.boolean "auto_publish", :default => false, :null => false + t.boolean "auto_publish", :default => false, :null => false + t.integer "build_lists_count", :default => 0 + t.integer "build_published_count", :default => 0 + t.integer "build_pending_count", :default => 0 + t.integer "build_started_count", :default => 0 + t.integer "build_publish_count", :default => 0 + t.integer "build_error_count", :default => 0 end create_table "platforms", :force => true do |t| @@ -240,10 +246,9 @@ ActiveRecord::Schema.define(:version => 20120609163454) do create_table "product_build_lists", :force => true do |t| t.integer "product_id" - t.integer "status", :default => 2, :null => false - t.datetime "notified_at" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.integer "status", :default => 2, :null => false + t.datetime "created_at" + t.datetime "updated_at" end add_index "product_build_lists", ["product_id"], :name => "index_product_build_lists_on_product_id" diff --git a/lib/build_server.rb b/lib/build_server.rb index c09e89794..a1214af13 100644 --- a/lib/build_server.rb +++ b/lib/build_server.rb @@ -11,7 +11,7 @@ class BuildServer PROJECT_NOT_FOUND = 3 PROJECT_VERSION_NOT_FOUND = 4 PROJECT_SOURCE_ERROR = 6 - + DEPENDENCY_TEST_FAILED = 21 BINARY_TEST_FAILED = 22 diff --git a/lib/recipes/resque.rb b/lib/recipes/resque.rb index 7f42fd653..8765558d9 100644 --- a/lib/recipes/resque.rb +++ b/lib/recipes/resque.rb @@ -20,12 +20,13 @@ Capistrano::Configuration.instance(:must_exist).load do end def stop_workers - #run "kill -QUIT `ps aux | grep resque | grep -v grep | awk '{ print $2 }'`" - run "kill -QUIT `ps aux | grep resque | grep -v grep | awk '{ print $2 }'` > /dev/null 2>&1 &" + # ps = 'ps aux | grep resque | grep -v grep' + # run "#{ps} && kill -QUIT `#{ps} | awk '{ print $2 }'` || echo 'Workers already stopped!'" + run "cd #{fetch :current_path} && #{rails_env} bundle exec rake resque:stop_workers" end def start_workers - run "cd #{fetch :current_path} && COUNT=#{ workers_count } QUEUE=fork_import,hook,clone_build,notification #{ rails_env } BACKGROUND=yes bundle exec rake resque:workers" + run "cd #{fetch :current_path} && COUNT=#{workers_count} QUEUE=fork_import,hook,clone_build,notification #{rails_env} BACKGROUND=yes bundle exec rake resque:workers" end end end diff --git a/lib/tasks/resque.rake b/lib/tasks/resque.rake new file mode 100644 index 000000000..5cc0e31e0 --- /dev/null +++ b/lib/tasks/resque.rake @@ -0,0 +1,10 @@ +namespace :resque do + desc 'Stop all Resque workers' + task :stop_workers => :environment do + pids = [] + Resque.workers.each do |worker| + pids << worker.to_s.split(/:/).second + end + system("kill -QUIT #{pids.join(' ')}") if pids.size > 0 + end +end diff --git a/public/404.html b/public/404.html index 1b6717f14..a8ce47791 100644 --- a/public/404.html +++ b/public/404.html @@ -13,23 +13,14 @@ @@ -41,7 +32,7 @@ - +
@@ -51,12 +42,12 @@
- +
- +

Error 404

Page not found

@@ -66,9 +57,9 @@ Or use the search.

- +
- +
diff --git a/public/500.html b/public/500.html index f4a948b0a..b94599412 100644 --- a/public/500.html +++ b/public/500.html @@ -13,23 +13,14 @@ @@ -41,7 +32,7 @@ - +
@@ -51,12 +42,12 @@
- +
- +

Error 500

Something went wrong.
We've been notified about this issue
@@ -68,9 +59,9 @@ Or use the search.

- +

- +
diff --git a/spec/controllers/projects/build_lists_controller_spec.rb b/spec/controllers/projects/build_lists_controller_spec.rb index d941b5f02..1431004eb 100644 --- a/spec/controllers/projects/build_lists_controller_spec.rb +++ b/spec/controllers/projects/build_lists_controller_spec.rb @@ -26,7 +26,7 @@ describe Projects::BuildListsController do response.should redirect_to(forbidden_url) end end - + shared_examples_for 'create build list' do before {test_git_commit(@project)} @@ -177,7 +177,7 @@ describe Projects::BuildListsController do before(:each) do @owner_group = FactoryGirl.create(:group) @owner_user = FactoryGirl.create(:user) - @owner_group.actors.create :role => 'reader', :actor_id => @owner_user.id, :actor_type => 'User' + @owner_group.actors.create :role => 'admin', :actor_id => @owner_user.id, :actor_type => 'User' @member_group = FactoryGirl.create(:group) @member_user = FactoryGirl.create(:user) @member_group.actors.create :role => 'reader', :actor_id => @member_user.id, :actor_type => 'User' @@ -317,27 +317,37 @@ describe Projects::BuildListsController do context 'callbacks' do let(:build_list) { FactoryGirl.create(:build_list_core) } + let(:build_list_package) { FactoryGirl.create(:build_list_package, :build_list_id => build_list.id, :platform_id => build_list.project.repositories.first.platform_id, :project_id => build_list.project_id, :version => "4.7.5.3", :release => 1) } before(:each) do mock(controller).authenticate_build_service! {true} end describe 'publish_build' do - before { test_git_commit(build_list.project); build_list.update_attribute :commit_hash, build_list.project.git_repository.commits('master').last.id } + before { + test_git_commit(build_list.project) + build_list.update_attribute :commit_hash, build_list.project.git_repository.commits('master').last.id + build_list.update_attribute(:status, BuildList::BUILD_PUBLISH) + build_list_package + } def do_get(status) get :publish_build, :id => build_list.bs_id, :status => status, :version => '4.7.5.3', :release => '1' build_list.reload end - it { do_get(BuildServer::SUCCESS); response.should be_ok } + it(:passes) { + build_list.update_attribute(:status, BuildServer::BUILD_STARTED) + do_get(BuildServer::SUCCESS) + response.should be_ok + } it 'should create correct git tag for correct commit' do do_get(BuildServer::SUCCESS) build_list.project.git_repository.tags.last.name.should == build_list.package_version build_list.project.git_repository.commits(build_list.package_version).last.id.should == build_list.commit_hash end - it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildList::BUILD_PUBLISHED) } - it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :package_version).to('4.7.5.3-1') } + it(:passes) { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildList::BUILD_PUBLISHED) } + it(:passes) { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :package_version).to("#{ build_list_package.platform.name }-4.7.5.3-1") } it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :status).to(BuildList::FAILED_PUBLISH) } it { lambda{ do_get(BuildServer::ERROR) }.should_not change(build_list, :package_version) } it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :updated_at) } @@ -390,6 +400,10 @@ describe Projects::BuildListsController do end describe 'pre_build' do + before do + build_list.update_attribute :status, BuildList::BUILD_PENDING + end + def do_get get :pre_build, :id => build_list.bs_id build_list.reload @@ -413,15 +427,32 @@ describe Projects::BuildListsController do it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :updated_at) } context 'with auto_publish' do - it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildList::BUILD_PUBLISH) } - it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :status).to(BuildServer::ERROR) } + it(:passes) { + build_list.update_attribute(:started_at, (Time.now - 1.day)) + build_list.update_attribute(:status, BuildServer::BUILD_STARTED) + build_list.reload + lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildList::BUILD_PUBLISH) + } + it(:passes) { + build_list.update_attribute(:started_at, (Time.now - 1.day)) + build_list.update_attribute(:status, BuildServer::BUILD_STARTED) + lambda{ do_get(BuildServer::BUILD_ERROR) }.should change(build_list, :status).to(BuildServer::BUILD_ERROR) + } end context 'without auto_publish' do before { build_list.update_attribute(:auto_publish, false) } - it { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildServer::SUCCESS) } - it { lambda{ do_get(BuildServer::ERROR) }.should change(build_list, :status).to(BuildServer::ERROR) } + it(:passes) { + build_list.update_attribute(:started_at, (Time.now - 1.day)) + build_list.update_attribute(:status, BuildServer::BUILD_STARTED) + lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildServer::SUCCESS) + } + it(:passes) { + build_list.update_attribute(:started_at, (Time.now - 1.day)) + build_list.update_attribute(:status, BuildServer::BUILD_STARTED) + lambda{ do_get(BuildServer::BUILD_ERROR) }.should change(build_list, :status).to(BuildServer::BUILD_ERROR) + } end end diff --git a/spec/controllers/projects/comments_controller_spec.rb b/spec/controllers/projects/comments_controller_spec.rb index c04b09c58..1e0501495 100644 --- a/spec/controllers/projects/comments_controller_spec.rb +++ b/spec/controllers/projects/comments_controller_spec.rb @@ -102,6 +102,8 @@ describe Projects::CommentsController do context 'for project owner user' do before(:each) do @project.update_attribute(:owner, @user) + @project.relations.destroy_all + @project.relations.create :actor_id => @project.owner.id, :actor_type => @project.owner.class.to_s, :role => 'admin' @create_params[:owner_name] = @user.uname; @update_params[:owner_name] = @user.uname end diff --git a/spec/controllers/projects/projects_controller_spec.rb b/spec/controllers/projects/projects_controller_spec.rb index e16d3b55e..a94cced96 100644 --- a/spec/controllers/projects/projects_controller_spec.rb +++ b/spec/controllers/projects/projects_controller_spec.rb @@ -79,6 +79,7 @@ describe Projects::ProjectsController do end it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'user without update rights' end context 'for writer user' do @@ -136,20 +137,115 @@ describe Projects::ProjectsController do response.should redirect_to(forbidden_path) end - it 'should not be able to edit project' do - description = @project.description - put :update, :project=>{:description =>"hack"}, :owner_name => @project.owner.uname, :project_name => @project.name - response.should redirect_to(forbidden_path) - Project.find(@project.id).description.should == description + it_should_behave_like 'user without update rights' + end + + context 'for group' do + before(:each) do + @group = FactoryGirl.create(:group) + @group_user = FactoryGirl.create(:user) + @project.relations.destroy_all + set_session_for(@group_user) end - it 'should not be able to edit project sections' do - has_wiki, has_issues = @project.has_wiki, @project.has_issues - post :sections, :project =>{:has_wiki => !has_wiki, :has_issues => !has_issues}, :owner_name => @project.owner.uname, :project_name => @project.name - response.should redirect_to(forbidden_path) - project = Project.find(@project.id) - project.has_wiki.should == has_wiki - project.has_issues.should == has_issues + context 'owner of the project' do + before(:each) do + @project.update_attribute :owner, @group + @project.relations.create :actor_id => @project.owner.id, :actor_type => @project.owner.class.to_s, :role => 'admin' + end + + context 'reader user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'reader') + end + + it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'user without update rights' + + it 'should has reader role to group project' do + @group_user.best_role(@project).should eql('reader') # Need this? + end + + context 'user should has best role' do + before(:each) do + @project.relations.create :actor_id => @group_user.id, :actor_type => @group_user.class.to_s, :role => 'admin' + end + it_should_behave_like 'projects user with admin rights' + end + end + + context 'admin user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'admin') + end + + it_should_behave_like 'projects user with admin rights' + it_should_behave_like 'projects user with reader rights' + end + end + + context 'member of the project' do + context 'with admin rights' do + before(:each) do + @project.relations.create :actor_id => @group.id, :actor_type => @group.class.to_s, :role => 'admin' + end + + context 'reader user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'reader') + end + + it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'projects user with admin rights' + + context 'user should has best role' do + before(:each) do + @project.relations.create :actor_id => @group_user.id, :actor_type => @group_user.class.to_s, :role => 'reader' + end + it_should_behave_like 'projects user with admin rights' + end + end + + context 'admin user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'admin') + end + + it_should_behave_like 'projects user with admin rights' + it_should_behave_like 'projects user with reader rights' + end + end + + context 'with reader rights' do + before(:each) do + @project.relations.create :actor_id => @group.id, :actor_type => @group.class.to_s, :role => 'reader' + end + + context 'reader user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'reader') + end + + it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'user without update rights' + + context 'user should has best role' do + before(:each) do + @project.relations.create :actor_id => @group_user.id, :actor_type => @group_user.class.to_s, :role => 'admin' + end + it_should_behave_like 'projects user with admin rights' + end + end + + context 'admin user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'admin') + end + + it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'user without update rights' + end + end end end end diff --git a/spec/factories/build_lists.rb b/spec/factories/build_lists.rb index 88dda9c27..0271f50ea 100644 --- a/spec/factories/build_lists.rb +++ b/spec/factories/build_lists.rb @@ -16,4 +16,15 @@ FactoryGirl.define do factory :build_list_core, :parent => :build_list do bs_id { FactoryGirl.generate(:integer) } end + + factory :build_list_package, :class => BuildList::Package do + association :build_list + association :project + association :platform + fullname "test_package" + name "test_package" + version "3.1.12" + release 6 + package_type "source" + end end diff --git a/spec/models/cancan_spec.rb b/spec/models/cancan_spec.rb index c496fbbf9..467b1e275 100644 --- a/spec/models/cancan_spec.rb +++ b/spec/models/cancan_spec.rb @@ -208,6 +208,7 @@ describe CanCan do context 'with owner rights' do before(:each) do @project.update_attribute(:owner, @user) + @project.relations.create!(:actor_id => @user.id, :actor_type => 'User', :role => 'admin') @issue.project.reload end diff --git a/spec/models/product_build_list_spec.rb b/spec/models/product_build_list_spec.rb index 76587112f..43c2abc61 100644 --- a/spec/models/product_build_list_spec.rb +++ b/spec/models/product_build_list_spec.rb @@ -21,7 +21,14 @@ describe ProductBuildList do it { should_not allow_mass_assignment_of(:product_id) } it { should allow_mass_assignment_of(:status) } - it { should allow_mass_assignment_of(:notified_at) } it { should allow_mass_assignment_of(:base_url) } - + + # see app/ability.rb + # can :read, ProductBuildList#, :product => {:platform => {:visibility => 'open'}} # double nested hash don't work + it 'should generate correct sql to get product build lists' do + stub_symlink_methods + user = FactoryGirl.create(:user) + ability = Ability.new user + ProductBuildList.accessible_by(ability).count.should == 0 + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 28b7f9d0d..8e61b75c6 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,6 +1,93 @@ # -*- encoding : utf-8 -*- require 'spec_helper' -#describe User do -# pending "add some examples to (or delete) #{__FILE__}" -#end +describe User do + before { stub_symlink_methods } + before(:each) do + @project = FactoryGirl.create(:project) + @group = FactoryGirl.create(:group) + @user = FactoryGirl.create(:user) + end + + context 'for own project' do + it 'should have admin role' do + @project.owner.best_role(@project).should == 'admin' + end + end + + context 'other user' do + it 'should have not right to project' do + other_user = FactoryGirl.create(:user) + other_user.best_role(@project).should == nil + end + end + + %w(reader writer admin).each do |group_role| + context "for group with #{group_role} role in project" do + before(:each) do + @project.relations.create :actor_id => @group.id, :actor_type => @group.class.to_s, :role => group_role + end + + %w(reader writer admin).each do |role| + context "for user with #{role} role in group" do + before(:each) do + @group.actors.create(:actor_id => @user.id, :actor_type => 'User', :role => role) + end + + it "should have #{group_role} role to project" do + @user.best_role(@project).should == group_role + end + end + end + end + end + + context 'for group project' do + before(:each) do + @project.relations.destroy_all + @project.update_attribute :owner, @group + @project.relations.create :actor_id => @project.owner.id, :actor_type => @project.owner.class.to_s, :role => 'admin' + end + + %w(reader writer admin).each do |role| + context "for user with #{role} role in group" do + before(:each) do + @group.actors.create(:actor_id => @user.id, :actor_type => 'User', :role => role) + end + + it "should have #{role} role to project" do + @user.best_role(@project).should == role + end + end + end + + %w(reader writer admin).each do |role| + context "for user with #{role} role in project" do + before(:each) do + @project.relations.create(:actor_id => @user.id, :actor_type => 'User', :role => role) + end + + it "should have #{role} role to project" do + @user.best_role(@project).should == role + end + end + end + + context "for user with reader role in group and writer role in project" do + it "should have writer best role to project" do + @group.actors.create(:actor_id => @user.id, :actor_type => 'User', :role => 'reader') + @project.relations.create(:actor_id => @user.id, :actor_type => 'User', :role => 'writer') + @user.best_role(@project).should == 'writer' + end + end + + context "for user with admin role in group and reader role in project" do + it "should have admin best role to project" do + @group.actors.create(:actor_id => @user.id, :actor_type => 'User', :role => 'admin') + @project.relations.create(:actor_id => @user.id, :actor_type => 'User', :role => 'reader') + @user.best_role(@project).should == 'admin' + end + end + end + +end diff --git a/spec/routing/projects_routing_spec.rb.rb b/spec/routing/projects_routing_spec.rb.rb index ac8d5d2e2..5bcc65d06 100644 --- a/spec/routing/projects_routing_spec.rb.rb +++ b/spec/routing/projects_routing_spec.rb.rb @@ -36,8 +36,9 @@ describe Projects::Git::TreesController do it "routes to #show" do get("/import/glib2.0-mib").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib') - get("/import/glib2.0-mib/tree/branch").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'branch') - get("/import/glib2.0-mib/tree/branch/some/path.to").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'branch', :path => 'some/path.to') + get("/import/glib2.0-mib/tree/lib2safe-0.03").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'lib2safe-0.03') + get("/import/glib2.0-mib/tree/branch-with.dot/folder_with.dot/path-with.dot").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'branch-with.dot', :path => 'folder_with.dot/path-with.dot') + # get("/import/glib2.0-mib/tree/ветка-с.точкой/папка_с.точкой/путь-с.точкой").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'ветка-с.точкой', :path => 'папка_с.точкой/путь-с.точкой') end # TODO write more specs also with slash in branch name! diff --git a/spec/support/shared_examples/projects_controller.rb b/spec/support/shared_examples/projects_controller.rb index 0562f06d8..0e4b4aff2 100644 --- a/spec/support/shared_examples/projects_controller.rb +++ b/spec/support/shared_examples/projects_controller.rb @@ -1,11 +1,12 @@ # -*- encoding : utf-8 -*- shared_examples_for 'projects user with reader rights' do - it_should_behave_like 'user with rights to view projects' + include_examples 'user with rights to view projects' # nested shared_examples_for dont work it 'should be able to fork project' do post :fork, :owner_name => @project.owner.uname, :project_name => @project.name response.should redirect_to(project_path(Project.last)) end + end shared_examples_for 'projects user with admin rights' do @@ -21,3 +22,21 @@ shared_examples_for 'user with rights to view projects' do response.should render_template(:index) end end + +shared_examples_for 'user without update rights' do + it 'should not be able to edit project' do + description = @project.description + put :update, :project=>{:description =>"hack"}, :owner_name => @project.owner.uname, :project_name => @project.name + Project.find(@project.id).description.should == description + response.should redirect_to(forbidden_path) + end + + it 'should not be able to edit project sections' do + has_wiki, has_issues = @project.has_wiki, @project.has_issues + post :sections, :project =>{:has_wiki => !has_wiki, :has_issues => !has_issues}, :owner_name => @project.owner.uname, :project_name => @project.name + project = Project.find(@project.id) + project.has_wiki.should == has_wiki + project.has_issues.should == has_issues + response.should redirect_to(forbidden_path) + end +end