#755: merge master into the branch
This commit is contained in:
commit
0fe74f17ac
|
@ -57,7 +57,7 @@ class Admin::UsersController < Admin::BaseController
|
|||
@users = @users.where('users.name ILIKE ? or users.uname ILIKE ? or users.email ILIKE ?', search, search, search)
|
||||
end
|
||||
@filter = params[:filter] || 'all'
|
||||
@users = @users.send(@filter) if ['real', 'admin', 'banned'].include? @filter
|
||||
@users = @users.send(@filter) if ['real', 'admin', 'banned', 'tester'].include? @filter
|
||||
@users = @users.order(order)
|
||||
|
||||
render :partial => 'users_ajax', :layout => false
|
||||
|
|
|
@ -12,7 +12,8 @@ class Platforms::MassBuildsController < Platforms::BaseController
|
|||
def create
|
||||
mass_build = @platform.mass_builds.new(:repositories => params[:repositories],
|
||||
:arches => params[:arches],
|
||||
:auto_publish => params[:auto_publish] || false)
|
||||
:auto_publish => params[:auto_publish] || false,
|
||||
:projects_list => params[:projects_list])
|
||||
mass_build.user = current_user
|
||||
authorize! :create, mass_build
|
||||
|
||||
|
@ -40,7 +41,12 @@ class Platforms::MassBuildsController < Platforms::BaseController
|
|||
redirect_to platform_mass_builds_path(@mass_build.platform)
|
||||
end
|
||||
|
||||
def failed_builds_list
|
||||
render :text => @mass_build.generate_failed_builds_list
|
||||
def get_list
|
||||
text = if params[:kind] == 'failed_builds_list'
|
||||
@mass_build.generate_failed_builds_list
|
||||
elsif ['projects_list', 'missed_projects_list'].include? params[:kind]
|
||||
@mass_build.send params[:kind]
|
||||
end
|
||||
render :text => text
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ class Platforms::ProductBuildListsController < Platforms::BaseController
|
|||
load_and_authorize_resource :platform, :except => [:index, :status_build]
|
||||
load_and_authorize_resource :product, :through => :platform, :except => [:index, :status_build]
|
||||
load_and_authorize_resource :product_build_list, :through => :product, :except => [:index, :status_build]
|
||||
load_and_authorize_resource :only => [:index, :show, :log, :stop]
|
||||
load_and_authorize_resource :only => [:index, :show, :log, :cancel]
|
||||
|
||||
before_filter :authenticate_product_builder!, :only => [:status_build]
|
||||
before_filter :find_product_build_list, :only => [:status_build]
|
||||
|
@ -25,15 +25,18 @@ class Platforms::ProductBuildListsController < Platforms::BaseController
|
|||
def show
|
||||
end
|
||||
|
||||
def stop
|
||||
@product_build_list.stop
|
||||
flash[:notice] = t('flash.product_build_list.will_be_stopped')
|
||||
redirect_to platform_product_product_build_list_path(@platform, @product, @product_build_list)
|
||||
def cancel
|
||||
if @product_build_list.cancel
|
||||
notice = t('layout.build_lists.will_be_canceled')
|
||||
else
|
||||
notice = t('layout.build_lists.cancel_fail')
|
||||
end
|
||||
redirect_to :back, :notice => notice
|
||||
end
|
||||
|
||||
def log
|
||||
render :json => {
|
||||
:log => @product_build_list.log,
|
||||
:log => @product_build_list.abf_worker_log,
|
||||
:building => @product_build_list.build_started?
|
||||
}
|
||||
end
|
||||
|
|
|
@ -55,7 +55,7 @@ class Projects::BuildListsController < Projects::BaseController
|
|||
build_for_platforms = Repository.select(:platform_id).
|
||||
where(:id => params[:build_list][:include_repos]).group(:platform_id).map(&:platform_id)
|
||||
|
||||
new_core = current_user.admin? && params[:build_list][:new_core] == '1'
|
||||
new_core = BuildList.has_access_to_new_core?(current_user) && params[:build_list][:new_core] == '1'
|
||||
params[:build_list][:auto_publish] = false if new_core
|
||||
Arch.where(:id => params[:arches]).each do |arch|
|
||||
Platform.main.where(:id => build_for_platforms).each do |build_for_platform|
|
||||
|
@ -101,10 +101,13 @@ class Projects::BuildListsController < Projects::BaseController
|
|||
|
||||
def cancel
|
||||
if @build_list.cancel
|
||||
redirect_to :back, :notice => t('layout.build_lists.cancel_success')
|
||||
notice = @build_list.new_core? ?
|
||||
t('layout.build_lists.will_be_canceled') :
|
||||
t('layout.build_lists.cancel_success')
|
||||
else
|
||||
redirect_to :back, :notice => t('layout.build_lists.cancel_fail')
|
||||
notice = t('layout.build_lists.cancel_fail')
|
||||
end
|
||||
redirect_to :back, :notice => notice
|
||||
end
|
||||
|
||||
def log
|
||||
|
|
|
@ -13,6 +13,13 @@ module BuildListsHelper
|
|||
'nocolor'
|
||||
end
|
||||
|
||||
def build_list_options_for_new_core
|
||||
[
|
||||
[I18n.t("layout.true_"), 1],
|
||||
[I18n.t("layout.false_"), 0]
|
||||
]
|
||||
end
|
||||
|
||||
def build_list_item_status_color(status)
|
||||
if BuildServer::SUCCESS == status
|
||||
return 'success'
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
module MassBuildHelper
|
||||
def link_to_list platform, mass_build, which
|
||||
link_to t("layout.mass_builds.#{which}"),
|
||||
get_list_platform_mass_build_path(@platform, mass_build, :kind => which, :format => :txt),
|
||||
:target => "_blank" if can?(:get_list, mass_build)
|
||||
end
|
||||
end
|
|
@ -95,7 +95,7 @@ class Ability
|
|||
can([:update, :members], Platform) {|platform| local_admin? platform}
|
||||
can([:destroy, :members, :add_member, :remove_member, :remove_members] , Platform) {|platform| owner?(platform) || local_admin?(platform) }
|
||||
|
||||
can([:failed_builds_list, :create], MassBuild) {|mass_build| (owner?(mass_build.platform) || local_admin?(mass_build.platform)) && mass_build.platform.main? }
|
||||
can([:get_list, :create], MassBuild) {|mass_build| (owner?(mass_build.platform) || local_admin?(mass_build.platform)) && mass_build.platform.main?}
|
||||
can(:cancel, MassBuild) {|mass_build| (owner?(mass_build.platform) || local_admin?(mass_build.platform)) && !mass_build.stop_build && mass_build.platform.main?}
|
||||
|
||||
can [:read, :projects_list, :projects], Repository, :platform => {:owner_type => 'User', :owner_id => user.id}
|
||||
|
@ -114,7 +114,7 @@ class Ability
|
|||
can(:read, Product, read_relations_for('products', 'platforms')) {|product| product.platform.main?}
|
||||
can([:create, :update, :destroy, :clone], Product) {|product| local_admin? product.platform and product.platform.main?}
|
||||
|
||||
can([:create, :stop], ProductBuildList) {|pbl| can?(:update, pbl.product)}
|
||||
can([:create, :cancel], ProductBuildList) {|pbl| can?(:update, pbl.product)}
|
||||
can(:destroy, ProductBuildList) {|pbl| can?(:destroy, pbl.product)}
|
||||
|
||||
can [:read, :create], PrivateUser, :platform => {:owner_type => 'User', :owner_id => user.id}
|
||||
|
@ -151,7 +151,7 @@ class Ability
|
|||
cannot [:create, :update, :destroy, :clone], Product, :platform => {:platform_type => 'personal'}
|
||||
cannot [:clone], Platform, :platform_type => 'personal'
|
||||
|
||||
cannot([:failed_builds_list, :create], MassBuild) {|mass_build| mass_build.platform.personal?}
|
||||
cannot([:get_list, :create], MassBuild) {|mass_build| mass_build.platform.personal?}
|
||||
cannot(:cancel, MassBuild) {|mass_build| mass_build.platform.personal? || mass_build.stop_build}
|
||||
|
||||
can :create, Subscribe do |subscribe|
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class BuildList < ActiveRecord::Base
|
||||
include Modules::Models::CommitAndVersion
|
||||
include AbfWorker::ModelHelper
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :arch
|
||||
|
@ -49,11 +50,13 @@ class BuildList < ActiveRecord::Base
|
|||
BUILD_PUBLISH = 7000
|
||||
FAILED_PUBLISH = 8000
|
||||
REJECTED_PUBLISH = 9000
|
||||
BUILD_CANCELING = 10000
|
||||
|
||||
STATUSES = [ WAITING_FOR_RESPONSE,
|
||||
BUILD_CANCELED,
|
||||
BUILD_PENDING,
|
||||
BUILD_PUBLISHED,
|
||||
BUILD_CANCELING,
|
||||
BUILD_PUBLISH,
|
||||
FAILED_PUBLISH,
|
||||
REJECTED_PUBLISH,
|
||||
|
@ -70,6 +73,7 @@ class BuildList < ActiveRecord::Base
|
|||
|
||||
HUMAN_STATUSES = { WAITING_FOR_RESPONSE => :waiting_for_response,
|
||||
BUILD_CANCELED => :build_canceled,
|
||||
BUILD_CANCELING => :build_canceling,
|
||||
BUILD_PENDING => :build_pending,
|
||||
BUILD_PUBLISHED => :build_published,
|
||||
BUILD_PUBLISH => :build_publish,
|
||||
|
@ -108,6 +112,7 @@ class BuildList < ActiveRecord::Base
|
|||
s
|
||||
}
|
||||
scope :scoped_to_project_name, lambda {|project_name| joins(:project).where('projects.name LIKE ?', "%#{project_name}%")}
|
||||
scope :scoped_to_new_core, lambda {|new_core| where(:new_core => new_core)}
|
||||
scope :outdated, where('created_at < ? AND status <> ? OR created_at < ?', Time.now - LIVE_TIME, BUILD_PUBLISHED, Time.now - MAX_LIVE_TIME)
|
||||
|
||||
serialize :additional_repos
|
||||
|
@ -137,6 +142,8 @@ class BuildList < ActiveRecord::Base
|
|||
end
|
||||
|
||||
after_transition :on => :published, :do => [:set_version_and_tag, :actualize_packages]
|
||||
after_transition :on => :cancel, :do => [:cancel_job],
|
||||
:if => lambda { |build_list| build_list.new_core? }
|
||||
|
||||
after_transition :on => [:published, :fail_publish, :build_error], :do => :notify_users
|
||||
after_transition :on => :build_success, :do => :notify_users,
|
||||
|
@ -169,7 +176,18 @@ class BuildList < ActiveRecord::Base
|
|||
|
||||
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
|
||||
!build_list.new_core? && build_list.can_cancel? && BuildServer.delete_build_list(build_list.bs_id) == BuildServer::SUCCESS
|
||||
}
|
||||
transition [:build_pending, :build_started] => :build_canceling, :if => lambda { |build_list|
|
||||
build_list.new_core?
|
||||
}
|
||||
end
|
||||
|
||||
# :build_canceling => :build_canceled - canceling from UI
|
||||
# :build_started => :build_canceled - canceling from worker by time-out (time_living has been expired)
|
||||
event :build_canceled do
|
||||
transition [:build_canceling, :build_started] => :build_canceled, :if => lambda { |build_list|
|
||||
build_list.new_core?
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -197,7 +215,7 @@ class BuildList < ActiveRecord::Base
|
|||
end
|
||||
|
||||
event :build_error do
|
||||
transition [:build_started, :build_canceled] => :build_error
|
||||
transition [:build_started, :build_canceled, :build_canceling] => :build_error
|
||||
end
|
||||
|
||||
HUMAN_STATUSES.each do |code,name|
|
||||
|
@ -226,7 +244,11 @@ class BuildList < ActiveRecord::Base
|
|||
|
||||
#TODO: Share this checking on product owner.
|
||||
def can_cancel?
|
||||
[BUILD_PENDING, BuildServer::PLATFORM_PENDING].include?(status) && bs_id
|
||||
if new_core?
|
||||
build_started? || build_pending?
|
||||
else
|
||||
[BUILD_PENDING, BuildServer::PLATFORM_PENDING].include?(status) && bs_id
|
||||
end
|
||||
end
|
||||
|
||||
def can_publish?
|
||||
|
@ -237,57 +259,6 @@ class BuildList < ActiveRecord::Base
|
|||
can_publish? and not save_to_repository.publish_without_qa
|
||||
end
|
||||
|
||||
def add_to_abf_worker_queue
|
||||
include_repos_hash = {}.tap do |h|
|
||||
include_repos.each do |r|
|
||||
repo = Repository.find r
|
||||
path = repo.platform.public_downloads_url(nil, arch.name, repo.name)
|
||||
# path = path.gsub(/^http:\/\/0\.0\.0\.0\:3000/, 'https://abf.rosalinux.ru')
|
||||
# Path looks like:
|
||||
# http://abf.rosalinux.ru/downloads/rosa-server2012/repository/x86_64/base/
|
||||
# so, we should append:
|
||||
# /release
|
||||
# /updates
|
||||
h["#{repo.name}_release"] = path + 'release'
|
||||
h["#{repo.name}_updates"] = path + 'updates'
|
||||
end
|
||||
end
|
||||
# mdv example:
|
||||
# https://abf.rosalinux.ru/import/plasma-applet-stackfolder.git
|
||||
# bfe6d68cc607238011a6108014bdcfe86c69456a
|
||||
|
||||
# rhel example:
|
||||
# https://abf.rosalinux.ru/server/gnome-settings-daemon.git
|
||||
# fbb2549e44d97226fea6748a4f95d1d82ffb8726
|
||||
|
||||
options = {
|
||||
:id => id,
|
||||
:arch => arch.name,
|
||||
:time_living => 2880, # 2 days
|
||||
:distrib_type => build_for_platform.distrib_type,
|
||||
# :git_project_address => 'https://abf.rosalinux.ru/server/gnome-settings-daemon.git',
|
||||
:git_project_address => project.git_project_address,
|
||||
# :commit_hash => 'fbb2549e44d97226fea6748a4f95d1d82ffb8726',
|
||||
:commit_hash => commit_hash,
|
||||
:build_requires => build_requires,
|
||||
:include_repos => include_repos_hash,
|
||||
:bplname => build_for_platform.name
|
||||
# :project_version => project_version,
|
||||
# :plname => save_to_platform.name,
|
||||
# :bplname => (save_to_platform_id == build_for_platform_id ? '' : build_for_platform.name),
|
||||
# :update_type => update_type,
|
||||
# :priority => priority,
|
||||
}
|
||||
unless @status
|
||||
Resque.push(
|
||||
'rpm_worker',
|
||||
'class' => 'AbfWorker::RpmWorker',
|
||||
'args' => [options]
|
||||
)
|
||||
end
|
||||
@status ||= BUILD_PENDING
|
||||
end
|
||||
|
||||
def publish_container
|
||||
type = save_to_platform.distrib_type
|
||||
Resque.push(
|
||||
|
@ -300,7 +271,9 @@ class BuildList < ActiveRecord::Base
|
|||
|
||||
def add_to_queue
|
||||
if new_core?
|
||||
add_to_abf_worker_queue
|
||||
# TODO: Investigate: why 2 tasks will be created without checking @state
|
||||
add_job_to_abf_worker_queue unless @status
|
||||
@status ||= BUILD_PENDING
|
||||
else
|
||||
# XML-RPC params:
|
||||
# - project_name
|
||||
|
@ -331,6 +304,10 @@ class BuildList < ActiveRecord::Base
|
|||
@status
|
||||
end
|
||||
|
||||
def self.has_access_to_new_core?(user)
|
||||
user && (user.admin? || user.tester?)
|
||||
end
|
||||
|
||||
def self.human_status(status)
|
||||
I18n.t("layout.build_lists.statuses.#{HUMAN_STATUSES[status]}")
|
||||
end
|
||||
|
@ -400,16 +377,54 @@ class BuildList < ActiveRecord::Base
|
|||
|
||||
def log(load_lines)
|
||||
if new_core?
|
||||
log = Resque.redis.get("abfworker::rpm-worker-#{id}")
|
||||
abf_worker_log
|
||||
else
|
||||
log = `tail -n #{load_lines.to_i} #{Rails.root + 'public' + fs_log_path}`
|
||||
log = nil unless $?.success?
|
||||
$?.success? ? log : I18n.t('layout.build_lists.log.not_available')
|
||||
end
|
||||
log || I18n.t('layout.build_lists.log.not_available')
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def abf_worker_args
|
||||
include_repos_hash = {}.tap do |h|
|
||||
include_repos.each do |r|
|
||||
repo = Repository.find r
|
||||
path = repo.platform.public_downloads_url(nil, arch.name, repo.name)
|
||||
# path = path.gsub(/^http:\/\/0\.0\.0\.0\:3000/, 'https://abf.rosalinux.ru')
|
||||
# Path looks like:
|
||||
# http://abf.rosalinux.ru/downloads/rosa-server2012/repository/x86_64/base/
|
||||
# so, we should append:
|
||||
# /release
|
||||
# /updates
|
||||
h["#{repo.name}_release"] = path + 'release'
|
||||
h["#{repo.name}_updates"] = path + 'updates'
|
||||
end
|
||||
end
|
||||
# mdv example:
|
||||
# https://abf.rosalinux.ru/import/plasma-applet-stackfolder.git
|
||||
# bfe6d68cc607238011a6108014bdcfe86c69456a
|
||||
|
||||
# rhel example:
|
||||
# https://abf.rosalinux.ru/server/gnome-settings-daemon.git
|
||||
# fbb2549e44d97226fea6748a4f95d1d82ffb8726
|
||||
|
||||
{
|
||||
:id => id,
|
||||
:arch => arch.name,
|
||||
:time_living => 43200, # 12 hours
|
||||
:distrib_type => build_for_platform.distrib_type,
|
||||
# :git_project_address => 'https://abf.rosalinux.ru/server/gnome-settings-daemon.git',
|
||||
:git_project_address => project.git_project_address,
|
||||
# :commit_hash => 'fbb2549e44d97226fea6748a4f95d1d82ffb8726',
|
||||
:commit_hash => commit_hash,
|
||||
:build_requires => build_requires,
|
||||
:include_repos => include_repos_hash,
|
||||
:bplname => build_for_platform.name,
|
||||
:user => {:uname => user.uname, :email => user.email}
|
||||
}
|
||||
end
|
||||
|
||||
def notify_users
|
||||
unless mass_build_id
|
||||
users = []
|
||||
|
|
|
@ -13,6 +13,7 @@ class BuildList::Filter
|
|||
build_lists = build_lists.where(:bs_id => @options[:bs_id])
|
||||
else
|
||||
build_lists = build_lists.accessible_by(::Ability.new(@user), @options[:ownership].to_sym) if @options[:ownership]
|
||||
build_lists = build_lists.scoped_to_new_core(@options[:new_core] == '0' ? nil : true) if @options[:new_core].present?
|
||||
build_lists = build_lists.for_status(@options[:status]) if @options[:status]
|
||||
build_lists = build_lists.scoped_to_arch(@options[:arch_id]) if @options[:arch_id]
|
||||
build_lists = build_lists.scoped_to_save_platform(@options[:platform_id]) if @options[:platform_id]
|
||||
|
@ -49,7 +50,8 @@ class BuildList::Filter
|
|||
:project_version => nil,
|
||||
:bs_id => nil,
|
||||
:project_name => nil,
|
||||
:mass_build_id => nil
|
||||
:mass_build_id => nil,
|
||||
:new_core => nil
|
||||
}))
|
||||
|
||||
@options[:ownership] = @options[:ownership].presence || (@project || !@user ? 'everything' : 'owned')
|
||||
|
@ -65,6 +67,7 @@ class BuildList::Filter
|
|||
@options[:bs_id] = @options[:bs_id].presence
|
||||
@options[:project_name] = @options[:project_name].presence
|
||||
@options[:mass_build_id] = @options[:mass_build_id].presence
|
||||
@options[:new_core] = @options[:new_core].presence
|
||||
end
|
||||
|
||||
def build_date_from_params(field_name, params)
|
||||
|
|
|
@ -7,14 +7,15 @@ class BuildList::Item < ActiveRecord::Base
|
|||
|
||||
GIT_ERROR = 5
|
||||
|
||||
STATUSES = [BuildServer::SUCCESS, BuildServer::DEPENDENCIES_ERROR, BuildServer::BUILD_ERROR, BuildServer::BUILD_STARTED, GIT_ERROR]
|
||||
STATUSES = [BuildServer::SUCCESS, BuildServer::DEPENDENCIES_ERROR, BuildServer::BUILD_ERROR, BuildServer::BUILD_STARTED, GIT_ERROR, BuildList::BUILD_CANCELED]
|
||||
HUMAN_STATUSES = {
|
||||
nil => :unknown,
|
||||
GIT_ERROR => :git_error,
|
||||
BuildServer::DEPENDENCIES_ERROR => :dependencies_error,
|
||||
BuildServer::SUCCESS => :success,
|
||||
BuildServer::BUILD_STARTED => :build_started,
|
||||
BuildServer::BUILD_ERROR => :build_error
|
||||
BuildServer::BUILD_ERROR => :build_error,
|
||||
BuildList::BUILD_CANCELED => :build_canceled
|
||||
}
|
||||
|
||||
scope :recent, order("level ASC, name ASC")
|
||||
|
|
|
@ -4,9 +4,12 @@ class BuildListObserver < ActiveRecord::Observer
|
|||
def before_update(record)
|
||||
if record.status_changed?
|
||||
record.started_at = Time.now if record.status == BuildServer::BUILD_STARTED
|
||||
if [BuildServer::BUILD_ERROR, BuildServer::SUCCESS].include? record.status
|
||||
if [BuildServer::BUILD_ERROR,
|
||||
BuildServer::SUCCESS,
|
||||
BuildList::BUILD_CANCELING,
|
||||
BuildList::BUILD_CANCELED].include? record.status
|
||||
# stores time interval beetwin build start and finish in seconds
|
||||
record.duration = record.current_duration
|
||||
record.duration = record.current_duration if record.started_at
|
||||
|
||||
if record.status == BuildServer::SUCCESS
|
||||
# Update project average build time
|
||||
|
|
|
@ -7,9 +7,10 @@ class MassBuild < ActiveRecord::Base
|
|||
scope :outdated, where('created_at < ?', Time.now + 1.day - BuildList::MAX_LIVE_TIME)
|
||||
|
||||
attr_accessor :repositories, :arches
|
||||
attr_accessible :repositories, :arches, :auto_publish
|
||||
attr_accessible :repositories, :arches, :auto_publish, :projects_list
|
||||
|
||||
validates :platform_id, :arch_names, :name, :user_id, :repositories, :rep_names, :presence => true
|
||||
validates :platform_id, :arch_names, :name, :user_id, :presence => true
|
||||
validate :rep_names, :repositories, :presence => true, :if => Proc.new {|mb| mb.projects_list.blank?}
|
||||
validates_inclusion_of :auto_publish, :in => [true, false]
|
||||
|
||||
after_create :build_all
|
||||
|
@ -26,13 +27,23 @@ class MassBuild < ActiveRecord::Base
|
|||
|
||||
# ATTENTION: repositories and arches must be set before calling this method!
|
||||
def build_all
|
||||
platform.build_all(
|
||||
:mass_build_id => self.id,
|
||||
:user => self.user,
|
||||
:repositories => self.repositories,
|
||||
:arches => self.arches,
|
||||
:auto_publish => self.auto_publish
|
||||
) # later with resque
|
||||
# later with resque
|
||||
if projects_list.present?
|
||||
platform.build_from_list(
|
||||
:mass_build_id => self.id,
|
||||
:user => self.user,
|
||||
:arches => self.arches,
|
||||
:auto_publish => self.auto_publish
|
||||
)
|
||||
else
|
||||
platform.build_all(
|
||||
:mass_build_id => self.id,
|
||||
:user => self.user,
|
||||
:repositories => self.repositories,
|
||||
:arches => self.arches,
|
||||
:auto_publish => self.auto_publish
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def generate_failed_builds_list
|
||||
|
|
|
@ -205,6 +205,39 @@ class Platform < ActiveRecord::Base
|
|||
end
|
||||
later :build_all, :loner => true, :queue => :clone_build
|
||||
|
||||
def build_from_list(opts={})
|
||||
mass_build = MassBuild.find opts[:mass_build_id]
|
||||
arches = opts[:arches] ? Arch.where(:id => opts[:arches]) : Arch.all
|
||||
auto_publish = opts[:auto_publish] || false
|
||||
user = opts[:user]
|
||||
|
||||
mass_build.projects_list.lines.each do |name|
|
||||
name.chomp!; name.strip!
|
||||
|
||||
project = ""
|
||||
Project.where(:name => name).each do |pr|
|
||||
project = pr if (pr.repository_ids & self.repository_ids).present?
|
||||
end
|
||||
|
||||
if project
|
||||
begin
|
||||
return if mass_build.reload.stop_build
|
||||
arches.map(&:name).each do |arch|
|
||||
rep = (project.repositories & self.repositories).first
|
||||
project.build_for(self, rep.id, user, arch, auto_publish, mass_build.id)
|
||||
end
|
||||
rescue RuntimeError, Exception
|
||||
end
|
||||
else
|
||||
MassBuild.increment_counter :missed_projects_count, mass_build.id
|
||||
list = (mass_build.missed_projects_list || '') << "#{name}\n"
|
||||
mass_build.update_column :missed_projects_list, list
|
||||
end
|
||||
sleep 1
|
||||
end
|
||||
end
|
||||
later :build_from_list, :loner => true, :queue => :clone_build
|
||||
|
||||
def destroy
|
||||
with_skip {super} # avoid cascade XML RPC requests
|
||||
end
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Product < ActiveRecord::Base
|
||||
include Modules::Models::TimeLiving
|
||||
|
||||
belongs_to :platform
|
||||
belongs_to :project
|
||||
has_many :product_build_lists, :dependent => :destroy
|
||||
|
@ -13,8 +15,7 @@ class Product < ActiveRecord::Base
|
|||
:description,
|
||||
:project_id,
|
||||
:main_script,
|
||||
:params,
|
||||
:time_living
|
||||
:params
|
||||
attr_readonly :platform_id
|
||||
|
||||
def full_clone(attrs = {})
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class ProductBuildList < ActiveRecord::Base
|
||||
include Modules::Models::CommitAndVersion
|
||||
include Modules::Models::TimeLiving
|
||||
include AbfWorker::ModelHelper
|
||||
delegate :url_helpers, to: 'Rails.application.routes'
|
||||
|
||||
BUILD_COMPLETED = 0
|
||||
BUILD_FAILED = 1
|
||||
BUILD_PENDING = 2
|
||||
BUILD_STARTED = 3
|
||||
BUILD_CANCELED = 4
|
||||
BUILD_CANCELING = 5
|
||||
BUILD_COMPLETED = 0
|
||||
BUILD_FAILED = 1
|
||||
BUILD_PENDING = 2
|
||||
BUILD_STARTED = 3
|
||||
BUILD_CANCELED = 4
|
||||
BUILD_CANCELING = 5
|
||||
|
||||
STATUSES = [ BUILD_STARTED,
|
||||
BUILD_COMPLETED,
|
||||
|
@ -35,7 +37,6 @@ class ProductBuildList < ActiveRecord::Base
|
|||
:status,
|
||||
:project_id,
|
||||
:main_script,
|
||||
:time_living,
|
||||
:arch_id, :presence => true
|
||||
validates :status, :inclusion => { :in => STATUSES }
|
||||
|
||||
|
@ -48,7 +49,6 @@ class ProductBuildList < ActiveRecord::Base
|
|||
:params,
|
||||
:project_version,
|
||||
:commit_hash,
|
||||
:time_living,
|
||||
:arch_id
|
||||
attr_readonly :product_id
|
||||
serialize :results, Array
|
||||
|
@ -60,10 +60,40 @@ class ProductBuildList < ActiveRecord::Base
|
|||
scope :scoped_to_product_name, lambda {|product_name| joins(:product).where('products.name LIKE ?', "%#{product_name}%")}
|
||||
scope :recent, order("#{table_name}.updated_at DESC")
|
||||
|
||||
after_create :xml_rpc_create
|
||||
after_create :add_job_to_abf_worker_queue
|
||||
before_destroy :can_destroy?
|
||||
after_destroy :xml_delete_iso_container
|
||||
|
||||
state_machine :status, :initial => :build_pending do
|
||||
|
||||
event :start_build do
|
||||
transition :build_pending => :build_started
|
||||
end
|
||||
|
||||
event :cancel do
|
||||
transition [:build_pending, :build_started] => :build_canceling
|
||||
end
|
||||
after_transition :on => :cancel, :do => [:cancel_job]
|
||||
|
||||
# :build_canceling => :build_canceled - canceling from UI
|
||||
# :build_started => :build_canceled - canceling from worker by time-out (time_living has been expired)
|
||||
event :build_canceled do
|
||||
transition [:build_canceling, :build_started] => :build_canceled
|
||||
end
|
||||
|
||||
event :build_success do
|
||||
transition :build_started => :build_completed
|
||||
end
|
||||
|
||||
event :build_error do
|
||||
transition [:build_started, :build_canceled, :build_canceling] => :build_failed
|
||||
end
|
||||
|
||||
HUMAN_STATUSES.each do |code,name|
|
||||
state name, :value => code
|
||||
end
|
||||
end
|
||||
|
||||
def build_started?
|
||||
status == BUILD_STARTED
|
||||
end
|
||||
|
@ -72,6 +102,10 @@ class ProductBuildList < ActiveRecord::Base
|
|||
status == BUILD_CANCELING
|
||||
end
|
||||
|
||||
def can_cancel?
|
||||
[BUILD_STARTED, BUILD_PENDING].include? status
|
||||
end
|
||||
|
||||
def container_path
|
||||
"/downloads/#{product.platform.name}/product/#{id}/"
|
||||
end
|
||||
|
@ -92,22 +126,9 @@ class ProductBuildList < ActiveRecord::Base
|
|||
[BUILD_COMPLETED, BUILD_FAILED, BUILD_CANCELED].include? status
|
||||
end
|
||||
|
||||
def log
|
||||
Resque.redis.get("abfworker::iso-worker-#{id}") || ''
|
||||
end
|
||||
|
||||
def stop
|
||||
update_attributes({:status => BUILD_CANCELING})
|
||||
Resque.redis.setex(
|
||||
"abfworker::iso-worker-#{id}::live-inspector",
|
||||
120, # Data will be removed from Redis after 120 sec.
|
||||
'USR1' # Immediately kill child but don't exit
|
||||
)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def xml_rpc_create
|
||||
def abf_worker_args
|
||||
file_name = "#{project.owner.uname}-#{project.name}-#{commit_hash}"
|
||||
srcpath = url_helpers.archive_url(
|
||||
project.owner,
|
||||
|
@ -116,7 +137,7 @@ class ProductBuildList < ActiveRecord::Base
|
|||
'tar.gz',
|
||||
:host => ActionMailer::Base.default_url_options[:host]
|
||||
)
|
||||
options = {
|
||||
{
|
||||
:id => id,
|
||||
# TODO: remove comment
|
||||
# :srcpath => 'http://dl.dropbox.com/u/945501/avokhmin-test-iso-script-5d9b463d4e9c06ea8e7c89e1b7ff5cb37e99e27f.tar.gz',
|
||||
|
@ -127,13 +148,7 @@ class ProductBuildList < ActiveRecord::Base
|
|||
:arch => arch.name,
|
||||
:distrib_type => product.platform.distrib_type
|
||||
}
|
||||
Resque.push(
|
||||
'iso_worker',
|
||||
'class' => 'AbfWorker::IsoWorker',
|
||||
'args' => [options]
|
||||
)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
def xml_delete_iso_container
|
||||
# TODO: write new worker for delete
|
||||
|
|
|
@ -30,6 +30,7 @@ class Project < ActiveRecord::Base
|
|||
validates :maintainer_id, :presence => true, :unless => :new_record?
|
||||
validates :visibility, :presence => true, :inclusion => {:in => VISIBILITIES}
|
||||
validate { errors.add(:base, :can_have_less_or_equal, :count => MAX_OWN_PROJECTS) if owner.projects.size >= MAX_OWN_PROJECTS }
|
||||
validate :check_default_branch
|
||||
|
||||
attr_accessible :name, :description, :visibility, :srpm, :is_package, :default_branch, :has_issues, :has_wiki, :maintainer_id
|
||||
attr_readonly :name, :owner_id, :owner_type
|
||||
|
@ -57,6 +58,7 @@ class Project < ActiveRecord::Base
|
|||
before_validation :truncate_name, :on => :create
|
||||
before_create :set_maintainer
|
||||
after_save :attach_to_personal_repository
|
||||
after_update :set_new_git_head
|
||||
|
||||
has_ancestry :orphan_strategy => :rootify #:adopt not available yet
|
||||
|
||||
|
@ -126,7 +128,7 @@ class Project < ActiveRecord::Base
|
|||
# Select main and project platform repository(contrib, non-free and etc)
|
||||
# If main does not exist, will connect only project platform repository
|
||||
# If project platform repository is main, only main will be connect
|
||||
main_rep_id = platform.repositories.find_by_name('main').id
|
||||
main_rep_id = platform.repositories.find_by_name('main').try(:id)
|
||||
build_reps_ids = [main_rep_id, repository_id].compact.uniq
|
||||
|
||||
arch = Arch.find_by_name(arch) if arch.acts_like?(:string)
|
||||
|
@ -204,4 +206,13 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def set_new_git_head
|
||||
`cd #{path} && git symbolic-ref HEAD refs/heads/#{self.default_branch}` if self.default_branch_changed? && self.repo.branches.map(&:name).include?(self.default_branch)
|
||||
end
|
||||
|
||||
def check_default_branch
|
||||
if self.repo.branches.count > 0 && self.repo.branches.map(&:name).exclude?(self.default_branch)
|
||||
errors.add :default_branch, I18n.t('activerecord.errors.project.default_branch')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class User < Avatar
|
||||
ROLES = ['', 'admin', 'banned']
|
||||
ROLES = ['', 'admin', 'banned', 'tester']
|
||||
LANGUAGES_FOR_SELECT = [['Russian', 'ru'], ['English', 'en']]
|
||||
LANGUAGES = LANGUAGES_FOR_SELECT.map(&:last)
|
||||
|
||||
|
@ -42,6 +42,7 @@ class User < Avatar
|
|||
scope :opened, where('1=1')
|
||||
scope :banned, where(:role => 'banned')
|
||||
scope :admin, where(:role => 'admin')
|
||||
scope :tester, where(:role => 'tester')
|
||||
scope :real, where(:role => ['', nil])
|
||||
|
||||
scope :member_of_project, lambda {|item|
|
||||
|
@ -66,6 +67,10 @@ class User < Avatar
|
|||
new_record?
|
||||
end
|
||||
|
||||
def tester?
|
||||
role == 'tester'
|
||||
end
|
||||
|
||||
def access_locked?
|
||||
role == 'banned'
|
||||
end
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
.both
|
||||
= check_box_tag "repositories[]", rep.id, (params[:repositories]||[]).include?(rep.id.to_s), :id => "repositories_#{rep.id}"
|
||||
= label_tag "repositories_#{rep.id}", rep.name
|
||||
%h3= t("layout.mass_builds.projects_list")
|
||||
= text_area_tag :projects_list, nil
|
||||
%br
|
||||
= f.submit t("layout.projects.build_button")
|
||||
%section.right
|
||||
|
@ -43,11 +45,18 @@
|
|||
= link_to t("layout.build_lists.statuses.#{status}") + ": ", build_lists_path(:filter => {:mass_build_id => mass_build.id, :ownership => 'everything'}.merge(status != :build_lists ? {:status => BuildList.status_by_human(status)} : {}))
|
||||
= mass_build.read_attribute "#{status}_count"
|
||||
.both
|
||||
%td= link_to t("layout.mass_builds.failed_builds_list"), failed_builds_list_platform_mass_build_path(@platform, mass_build.id, :format => :txt), :target => "_blank" if can?(:failed_builds_list, mass_build)
|
||||
%td
|
||||
=link_to_list @platform, mass_build, 'failed_builds_list'
|
||||
-if mass_build.projects_list.present?
|
||||
%br
|
||||
=link_to_list @platform, mass_build, 'missed_projects_list'
|
||||
%td= link_to image_tag('x.png'), cancel_platform_mass_build_path(@platform, mass_build.id), :method => :post, :confirm => t("layout.mass_builds.cancel_confirm") if can?(:cancel, mass_build)
|
||||
%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 }"}
|
||||
-if mass_build.projects_list.present?
|
||||
= link_to_list @platform, mass_build, 'projects_list'
|
||||
.both
|
||||
= t('activerecord.attributes.mass_build.arch_names') + ": "
|
||||
= mass_build.arch_names
|
||||
.both
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
%tr
|
||||
- sha1 = item['sha1']
|
||||
- filename = item['file_name']
|
||||
- url = 'http://file-store.rosalinux.ru/api/v1/file_stores/'
|
||||
- url << sha1
|
||||
- url = "#{APP_CONFIG['file_store_url']}/#{sha1}"
|
||||
- url << '.log?show=true' if filename =~ /.*\.(log|txt)$/
|
||||
%td= link_to filename, url
|
||||
%td= sha1
|
||||
|
|
|
@ -18,16 +18,19 @@
|
|||
= render 'show_field', :key => :project_version, :value => product_build_list_version_link(pbl, true)
|
||||
|
||||
= render 'show_field', :key => :arch, :value => pbl.arch.name
|
||||
- [:main_script, :params, :time_living].each do |el|
|
||||
- [:main_script, :params].each do |el|
|
||||
= render 'show_field', :key => el, :value => pbl.send(el)
|
||||
|
||||
= render 'show_field', :key => :time_living, :value => (pbl.time_living / 60)
|
||||
|
||||
= render 'show_field', :key => :notified_at, :value => l(pbl.updated_at, :format => :long)
|
||||
|
||||
- if pbl.can_cancel? && can?(:cancel, pbl)
|
||||
= link_to t("layout.build_lists.cancel"), cancel_platform_product_product_build_list_path(pbl.product.platform, pbl.product, pbl),
|
||||
:method => :put, :confirm => t("layout.confirm"), :class => 'button'
|
||||
.both
|
||||
|
||||
- if pbl.build_started? || pbl.build_canceling?
|
||||
- if can? :stop, pbl
|
||||
.leftlist= t("layout.product_build_lists.action")
|
||||
.rightlist= link_to t("layout.product_build_lists.stop"), stop_platform_product_product_build_list_path(pbl.product.platform, pbl.product, pbl)
|
||||
.both
|
||||
= render 'shared/log', { :build_started => true, :get_log_path => log_platform_product_product_build_list_path(pbl.product.platform, pbl.product, pbl) }
|
||||
|
||||
= render 'results', :pbl => pbl
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
- [:main_script, :params, :time_living].each do |el|
|
||||
- [:main_script, :params].each do |el|
|
||||
.leftlist= f.label el, t("activerecord.attributes.product_build_list.#{el}"), :class => :label
|
||||
.rightlist= f.text_field el
|
||||
.both
|
||||
.both
|
||||
|
||||
.leftlist= f.label :time_living, t("activerecord.attributes.product_build_list.time_living"), :class => :label
|
||||
.rightlist= f.text_field :time_living, :value => (@product.time_living / 60)
|
||||
.both
|
|
@ -37,6 +37,8 @@
|
|||
%br
|
||||
= f.submit t("layout.search.header")
|
||||
.block
|
||||
%h3.small= t("activerecord.attributes.build_list.new_core")
|
||||
.lineForm.aside= f.select :new_core, build_list_options_for_new_core, {:include_blank => true, :selected => @filter.new_core}, {:class => 'sel80 aside', :id => 'new_core', :tabindex => 2}
|
||||
%h3.small= t("activerecord.attributes.build_list.status")
|
||||
.lineForm.aside= f.select :status, BuildList::STATUSES.collect{|status| [BuildList.human_status(status), status]}, {:include_blank => true, :selected => @filter.status}, {:class => 'sel80 aside', :id => 'status', :tabindex => 2}
|
||||
%h3.small= t("activerecord.models.platform")
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
.both
|
||||
= f.check_box :build_requires
|
||||
= f.label :build_requires
|
||||
- if current_user.admin?
|
||||
- if BuildList.has_access_to_new_core?(current_user)
|
||||
.both
|
||||
= f.check_box :new_core
|
||||
= f.label :new_core
|
||||
|
|
|
@ -9,7 +9,7 @@ old_sources = if File.exist? abf_yml
|
|||
[]
|
||||
end
|
||||
#MAX_SIZE = 2 * 1024 * 1024 # 2.megabytes
|
||||
url = 'http://file-store.rosalinux.ru/api/v1/file_stores.json'
|
||||
url = "#{APP_CONFIG['file_store_url']}.json"
|
||||
#url = 'http://localhost:3001/api/v1/file_stores.json'
|
||||
rclient = RestClient::Resource.new(url, :user => ARGF.argv[0]) # user auth token
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ en:
|
|||
show: Show
|
||||
cancel: Cancel build
|
||||
cancel_success: 'Build canceled'
|
||||
will_be_canceled: 'Build will be canceled...'
|
||||
publish_success: 'Build published'
|
||||
cancel_fail: 'Errors during build cancelation!'
|
||||
publish_fail: 'Errors during build publishing!'
|
||||
|
@ -100,6 +101,7 @@ en:
|
|||
success: Build complete
|
||||
unknown: Build is waiting
|
||||
git_error: Git error
|
||||
build_canceled: Build canceled
|
||||
|
||||
statuses:
|
||||
build_lists: All
|
||||
|
@ -111,6 +113,7 @@ en:
|
|||
dependencies_fail: Dependences not found
|
||||
waiting_for_response: Waiting for response
|
||||
build_pending: Build pending
|
||||
build_canceling: Build is canceling
|
||||
dependency_test_failed: Dependency test failed
|
||||
binary_test_failed: Binary test failed
|
||||
build_canceled: Build canceled
|
||||
|
|
|
@ -60,6 +60,7 @@ ru:
|
|||
no_items_data: Данных нет
|
||||
show: Просмотр
|
||||
cancel: Отменить сборку
|
||||
will_be_canceled: 'Сборка будет отменена...'
|
||||
cancel_success: 'Сборка отменена.'
|
||||
cancel_fail: 'При отмене сборки произошла ошибка!'
|
||||
publish_success: 'Сборка поставлена в очередь на публикацию.'
|
||||
|
@ -97,6 +98,7 @@ ru:
|
|||
success: собран
|
||||
unknown: ожидает сборки
|
||||
git_error: проблема с гит
|
||||
build_canceled: сборка отменена
|
||||
|
||||
statuses:
|
||||
build_lists: Всего
|
||||
|
@ -111,6 +113,7 @@ ru:
|
|||
dependency_test_failed: тестирование зависимостей не пройдено
|
||||
binary_test_failed: тестирование бинарной совместимости не пройдено
|
||||
build_canceled: сборка отменена
|
||||
build_canceling: сборка отменяется
|
||||
success: собран
|
||||
build_started: собирается
|
||||
platform_not_found: платформа не найдена
|
||||
|
|
|
@ -7,6 +7,8 @@ en:
|
|||
statuses: Statuses
|
||||
cancel_mass_build: Cancel
|
||||
cancel_confirm: Are you sure you want to cancel mass build?
|
||||
projects_list: Projects list
|
||||
missed_projects_list: Missed projects list
|
||||
activerecord:
|
||||
models:
|
||||
mass_build: Mass Build
|
||||
|
|
|
@ -7,6 +7,8 @@ ru:
|
|||
statuses: Статусы
|
||||
cancel_mass_build: Отмена
|
||||
cancel_confirm: Вы уверены, что хотите отменить массовую сборку?
|
||||
projects_list: Список проектов
|
||||
missed_projects_list: Список несуществующих проектов
|
||||
activerecord:
|
||||
models:
|
||||
mass_build: Массовая Сборка
|
||||
|
|
|
@ -31,4 +31,5 @@ en:
|
|||
build_status: Build status
|
||||
created_at: Created
|
||||
updated_at: Updated
|
||||
project: Project
|
||||
project: Project
|
||||
time_living: Max time for building (in minutes)
|
|
@ -31,4 +31,5 @@ ru:
|
|||
build_status: Статус последней сборки
|
||||
created_at: Создан
|
||||
updated_at: Обновлен
|
||||
project: Проект
|
||||
project: Проект
|
||||
time_living: Максимальное время сборки (в минутах)
|
|
@ -8,7 +8,6 @@ en:
|
|||
results_folder: all files from this folder will be uploaded into the file-store
|
||||
archives_folder: this folder will be archived and uploaded into the file-store
|
||||
delete: Delete
|
||||
stop: Stop
|
||||
action: Action
|
||||
id_search: 'Id search'
|
||||
new: New build
|
||||
|
@ -52,5 +51,4 @@ en:
|
|||
product_build_list:
|
||||
no_project: Project for build should be exist
|
||||
delete: Product build list deleted
|
||||
delete_error: Unable to delete product build list
|
||||
will_be_stopped: Build will be stopped
|
||||
delete_error: Unable to delete product build list
|
|
@ -8,7 +8,6 @@ ru:
|
|||
results_folder: все файлы из этой папки будут загружены на file-store
|
||||
archives_folder: эта папка будет заархивирована и загружена на file-store
|
||||
delete: Удалить
|
||||
stop: Остановить
|
||||
action: Действие
|
||||
id_search: 'Поиск по Id'
|
||||
new: Новая сборка
|
||||
|
@ -52,5 +51,4 @@ ru:
|
|||
product_build_list:
|
||||
no_project: Проект для сборки должен присутствовать
|
||||
delete: Сборочный лист продукта удален
|
||||
delete_error: Не удалось удалить cборочный лист продукта
|
||||
will_be_stopped: Сборка будет остановлена
|
||||
delete_error: Не удалось удалить cборочный лист продукта
|
|
@ -99,3 +99,4 @@ en:
|
|||
errors:
|
||||
project:
|
||||
uname: The name can only use lower case Latin letters (a-z), numbers (0-9) and underscore (_)
|
||||
default_branch: Wrong branch
|
||||
|
|
|
@ -99,3 +99,4 @@ ru:
|
|||
errors:
|
||||
project:
|
||||
uname: В имени можно использовать только строчные символы латинского алфавита (a-z), цифры (0-9) и символ нижнего подчеркивания (_)
|
||||
default_branch: Указана несуществующая ветка
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
en:
|
||||
flash:
|
||||
time_living:
|
||||
numericality_error: must be 2 to 720 minutes
|
|
@ -0,0 +1,4 @@
|
|||
ru:
|
||||
flash:
|
||||
time_living:
|
||||
numericality_error: должно быть от 2 до 720 минут
|
|
@ -26,6 +26,7 @@ en:
|
|||
admin: Admins
|
||||
real: Real
|
||||
banned: Banned
|
||||
tester: Testers
|
||||
register_request:
|
||||
list_header: Register requests
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ ru:
|
|||
admin: Админы
|
||||
real: Обычные
|
||||
banned: Забаненные
|
||||
tester: Тестеры
|
||||
register_request:
|
||||
list_header: Заявки на регистрацию
|
||||
|
||||
|
|
|
@ -131,8 +131,8 @@ Rosa::Application.routes.draw do
|
|||
|
||||
resources :mass_builds, :only => [:create, :index] do
|
||||
member do
|
||||
get :failed_builds_list
|
||||
post :cancel
|
||||
get '/:kind.:format' => "mass_builds#get_list", :as => :get_list, :kind => /failed_builds_list|missed_projects_list|projects_list/
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -151,7 +151,7 @@ Rosa::Application.routes.draw do
|
|||
resources :product_build_lists, :only => [:create, :destroy, :new, :show] do
|
||||
member {
|
||||
get :log
|
||||
get :stop
|
||||
put :cancel
|
||||
}
|
||||
end
|
||||
collection { get :autocomplete_project }
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
class AddListToMassBuild < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :mass_builds, :projects_list, :text
|
||||
add_column :mass_builds, :missed_projects_count, :integer, :default => 0, :null => false
|
||||
add_column :mass_builds, :missed_projects_list, :text
|
||||
end
|
||||
end
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20121203142727) do
|
||||
ActiveRecord::Schema.define(:version => 20121206143724) do
|
||||
|
||||
create_table "activity_feeds", :force => true do |t|
|
||||
t.integer "user_id", :null => false
|
||||
|
@ -252,6 +252,9 @@ ActiveRecord::Schema.define(:version => 20121203142727) do
|
|||
t.integer "build_error_count", :default => 0, :null => false
|
||||
t.string "rep_names"
|
||||
t.boolean "stop_build", :default => false, :null => false
|
||||
t.text "projects_list"
|
||||
t.integer "missed_projects_count", :default => 0, :null => false
|
||||
t.text "missed_projects_list"
|
||||
end
|
||||
|
||||
create_table "platforms", :force => true do |t|
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
module AbfWorker
|
||||
class IsoWorkerObserver
|
||||
BUILD_COMPLETED = 0
|
||||
BUILD_FAILED = 1
|
||||
BUILD_PENDING = 2
|
||||
BUILD_STARTED = 3
|
||||
BUILD_CANCELED = 4
|
||||
@queue = :iso_worker_observer
|
||||
|
||||
def self.perform(options)
|
||||
status = options['status'].to_i
|
||||
pbl = ProductBuildList.find options['id']
|
||||
pbl.status = status
|
||||
pbl.results = options['results'] if status != ProductBuildList::BUILD_STARTED
|
||||
pbl.save!
|
||||
case status
|
||||
when BUILD_COMPLETED
|
||||
pbl.build_success
|
||||
when BUILD_FAILED
|
||||
pbl.build_error
|
||||
when BUILD_STARTED
|
||||
pbl.start_build
|
||||
when BUILD_CANCELED
|
||||
pbl.build_canceled
|
||||
end
|
||||
if status != BUILD_STARTED
|
||||
pbl.results = options['results']
|
||||
pbl.save!
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
module AbfWorker
|
||||
module ModelHelper
|
||||
# In model which contains this helper should be:
|
||||
# - #abf_worker_args
|
||||
# - #build_canceled
|
||||
|
||||
def abf_worker_log
|
||||
q = 'abfworker::'
|
||||
q << worker_queue('-')
|
||||
q << '-'
|
||||
q << id.to_s
|
||||
Resque.redis.get(q) || I18n.t('layout.build_lists.log.not_available')
|
||||
end
|
||||
|
||||
def add_job_to_abf_worker_queue
|
||||
Resque.push(
|
||||
worker_queue,
|
||||
'class' => worker_queue_class,
|
||||
'args' => [abf_worker_args]
|
||||
)
|
||||
end
|
||||
|
||||
def cancel_job
|
||||
deleted = Resque::Job.destroy(
|
||||
worker_queue,
|
||||
worker_queue_class,
|
||||
abf_worker_args
|
||||
)
|
||||
if deleted == 1
|
||||
build_canceled
|
||||
else
|
||||
send_stop_signal
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def send_stop_signal
|
||||
Resque.redis.setex(
|
||||
live_inspector_queue,
|
||||
240, # Data will be removed from Redis after 240 sec.
|
||||
'USR1' # Immediately kill child but don't exit
|
||||
)
|
||||
end
|
||||
|
||||
def live_inspector_queue
|
||||
q = 'abfworker::'
|
||||
q << worker_queue('-')
|
||||
q << '-'
|
||||
q << id.to_s
|
||||
q << '::live-inspector'
|
||||
q
|
||||
end
|
||||
|
||||
def worker_queue(delimiter = '_')
|
||||
a = []
|
||||
a << (is_a?(BuildList) ? 'rpm' : 'iso')
|
||||
a << 'worker'
|
||||
a.join(delimiter)
|
||||
end
|
||||
|
||||
def worker_queue_class
|
||||
is_a?(BuildList) ? 'AbfWorker::RpmWorker' : 'AbfWorker::IsoWorker'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,5 +1,11 @@
|
|||
module AbfWorker
|
||||
class RpmWorkerObserver
|
||||
BUILD_COMPLETED = 0
|
||||
BUILD_FAILED = 1
|
||||
BUILD_PENDING = 2
|
||||
BUILD_STARTED = 3
|
||||
BUILD_CANCELED = 4
|
||||
|
||||
@queue = :rpm_worker_observer
|
||||
|
||||
def self.perform(options)
|
||||
|
@ -7,18 +13,21 @@ module AbfWorker
|
|||
status = options['status'].to_i
|
||||
item = find_or_create_item(bl)
|
||||
case status
|
||||
when 0
|
||||
when BUILD_COMPLETED
|
||||
bl.build_success
|
||||
item.update_attributes({:status => BuildServer::SUCCESS})
|
||||
when 1
|
||||
when BUILD_FAILED
|
||||
bl.build_error
|
||||
item.update_attributes({:status => BuildServer::BUILD_ERROR})
|
||||
when 3
|
||||
when BUILD_STARTED
|
||||
bl.bs_id = bl.id
|
||||
bl.save!
|
||||
bl.start_build
|
||||
when BUILD_CANCELED
|
||||
bl.build_canceled
|
||||
item.update_attributes({:status => BuildList::BUILD_CANCELED})
|
||||
end
|
||||
if status != 3
|
||||
if status != BUILD_STARTED
|
||||
fill_container_data bl, options
|
||||
end
|
||||
end
|
||||
|
@ -49,7 +58,7 @@ module AbfWorker
|
|||
select{ |r| r['file_name'] !~ /.*\.log$/ }.first
|
||||
sha1 = container ? container['sha1'] : nil
|
||||
bl.results = options['results']
|
||||
bl.container_path = "http://file-store.rosalinux.ru/api/v1/file_stores/#{sha1}" if sha1
|
||||
bl.container_path = "#{APP_CONFIG['file_store_url']}/#{sha1}" if sha1
|
||||
bl.save!
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
module Modules
|
||||
module Models
|
||||
module TimeLiving
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
|
||||
validates :time_living, :numericality => {
|
||||
:only_integer => true
|
||||
}, :presence => true
|
||||
|
||||
validate lambda {
|
||||
# 2 min <= time_living <= 12 hours
|
||||
if 120 > time_living || time_living > 43200
|
||||
errors.add(:time_living, I18n.t('flash.time_living.numericality_error'))
|
||||
end
|
||||
}
|
||||
|
||||
before_validation :convert_time_living
|
||||
|
||||
attr_accessible :time_living
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def convert_time_living
|
||||
self.time_living = time_living.to_i * 60 if time_living_was.to_i != time_living.to_i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
namespace :project do
|
||||
|
||||
desc 'Change HEAD at projects where default branch is not master'
|
||||
task :git_change_head => :environment do
|
||||
projects = Project.where("default_branch <> 'master'")
|
||||
say "Find #{projects.count} project(s) without master HEAD"
|
||||
say "Start working..."
|
||||
projects.each do |project|
|
||||
`cd #{project.path} && git symbolic-ref HEAD refs/heads/#{project.default_branch}` if project.repo.branches.map(&:name).include?(project.default_branch)
|
||||
end
|
||||
say 'Done!'
|
||||
end
|
||||
end
|
|
@ -23,8 +23,8 @@ shared_examples_for 'product build list admin' do
|
|||
response.should render_template(:index)
|
||||
end
|
||||
|
||||
it 'should be able to perform stop action' do
|
||||
get :stop, valid_attributes_for_show
|
||||
it 'should be able to perform cancel action' do
|
||||
put :cancel, valid_attributes_for_show
|
||||
response.should redirect_to(platform_product_product_build_list_path(@product.platform, @product, @pbl))
|
||||
end
|
||||
|
||||
|
@ -56,8 +56,8 @@ shared_examples_for 'product build list user without admin rights' do
|
|||
response.should_not be_success
|
||||
end
|
||||
|
||||
it 'should not be able to perform stop action' do
|
||||
get :stop, valid_attributes_for_show
|
||||
it 'should not be able to perform cancel action' do
|
||||
put :cancel, valid_attributes_for_show
|
||||
response.should_not redirect_to(platform_product_product_build_list_path(@product.platform, @product, @pbl))
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue