Merge branch 'master' into 19-attach_issue_to_issue
Conflicts: app/assets/stylesheets/design/custom.scss db/schema.rb
This commit is contained in:
commit
70e37925c6
|
@ -0,0 +1,14 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
$('#product_project').bind('railsAutocomplete.select', function(event, data){
|
||||
var ppv = $("#product_project_version").empty().append('<option value=""></option>');
|
||||
$(data.item.project_versions).each(function(k, i) {
|
||||
var optgroup = $('<optgroup label="' + i[0] + '"></optgroup>');
|
||||
$(i[1]).each(function(k, b) {
|
||||
optgroup.append('<option value="' + b + '">' + b + '</option>');
|
||||
});
|
||||
ppv.append(optgroup);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
|
@ -115,60 +115,48 @@ $(document).ready(function() {
|
|||
return false;
|
||||
};
|
||||
|
||||
$('#search_user').live('submit', function() {
|
||||
var id = $(this).attr('id');
|
||||
if(id.indexOf('user') != -1) { // FIXME
|
||||
var which = 'users';
|
||||
}
|
||||
else if (id.indexOf('labels') != -1) {
|
||||
var which = 'labels';
|
||||
}
|
||||
$.ajax({
|
||||
var isSearchUser = null;
|
||||
$('#search_user').on('keyup', function() {
|
||||
if (isSearchUser != null) { isSearchUser.abort(); }
|
||||
isSearchUser = $.ajax({
|
||||
type: 'GET',
|
||||
url: $(this).attr("action"),
|
||||
url: $('#search_user_path').attr('path'),
|
||||
data: $(this).serialize(),
|
||||
success: function(data){
|
||||
$('#manage_issue_'+ which +'_list').html(data);
|
||||
},
|
||||
error: function(data){
|
||||
alert('error') // TODO remove
|
||||
}
|
||||
$('#manage_issue_users_list').html(data);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
function remAssignee(form) {
|
||||
var el = form.find('.people.selected.remove_assignee');
|
||||
var id = el.attr('id');
|
||||
$('#manage_issue_users_list .add_assignee.people.selected').removeClass('select');
|
||||
el.remove();
|
||||
}
|
||||
|
||||
$('.add_assignee.people.selected').live('click', function() {
|
||||
var form_new = $('form.issue');
|
||||
var form_edit = $('form.edit_form.issue');
|
||||
form_new.find('#people-span').fadeOut(0);
|
||||
remAssignee(form_new);
|
||||
var clone = $(this).clone().removeClass('add_assignee').addClass('remove_assignee');
|
||||
form_new.find('#issue_assignee').html(clone);
|
||||
$('.current_assignee').html(clone.removeClass('select'));
|
||||
$(this).addClass('select');
|
||||
$('#assigned-popup .header .icon-remove-circle').live('click', function() {
|
||||
$('#assigned-popup').hide();
|
||||
});
|
||||
|
||||
$('.remove_assignee.people.selected').live('click', function() {
|
||||
var form = $('form.issue, form.edit_form issue');
|
||||
form.find('#people-span').fadeIn(0);
|
||||
remAssignee(form);
|
||||
$('#assigned-container .icon-share').live('click', function() {
|
||||
$('#assigned-popup').show();
|
||||
});
|
||||
|
||||
function remLabel(form, id) {
|
||||
var el = form.find('.label.remove_label'+'#'+id);
|
||||
var label = $('#'+id+'.remove_label.label.selected');
|
||||
label.find('.flag').fadeIn(0);
|
||||
label.find('.labeltext.selected').removeClass('selected').attr('style', '');
|
||||
label.fadeIn('slow');
|
||||
el.fadeOut('slow').remove();
|
||||
}
|
||||
$('#assigned-popup .people.selected').live('click', function() {
|
||||
var form = $('#assigned-popup .edit_assignee');
|
||||
var item = $(this);
|
||||
if (form.length == 0) {
|
||||
updateAssignedUser(item);
|
||||
return false;
|
||||
}
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
url: form.attr("action"),
|
||||
data: $(this).find('input').serialize(),
|
||||
success: function(data){
|
||||
updateAssignedUser(item);
|
||||
},
|
||||
error: function(data){
|
||||
alert('error'); // TODO remove
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.add_label.label').live('click', function() {
|
||||
$(this).addClass('selected').removeClass('add_label').addClass('remove_label');
|
||||
|
@ -251,12 +239,6 @@ $(document).ready(function() {
|
|||
return false;
|
||||
});
|
||||
|
||||
$('.button.manage_assignee').live('click', function() {
|
||||
$('form#search_user, .button.update_assignee').fadeIn(0);
|
||||
$('.current_assignee .people').addClass('remove_assignee selected').removeClass('nopointer');
|
||||
$(this).fadeOut(0);
|
||||
});
|
||||
|
||||
$('.button.manage_labels').live('click', function() {
|
||||
$('.button.update_labels').fadeIn(0);
|
||||
$('.current_labels .label .labeltext.selected').parent().addClass('remove_label selected').removeClass('nopointer');
|
||||
|
@ -264,25 +246,6 @@ $(document).ready(function() {
|
|||
$(this).fadeOut(0);
|
||||
});
|
||||
|
||||
$('.button.update_assignee').live('click', function() {
|
||||
var form = $('form.edit_assignee.issue');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: form.attr("action"),
|
||||
data: form.serialize(),
|
||||
success: function(data){
|
||||
$('.current_assignee .people').removeClass('remove_assignee selected').addClass('nopointer');
|
||||
$('form#search_user, .button.update_assignee').fadeOut(0);
|
||||
$('.button.manage_assignee').fadeIn(0);
|
||||
$('#manage_issue_users_list').html('');
|
||||
},
|
||||
error: function(data){
|
||||
alert('error'); // TODO remove
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.button.update_labels').live('click', function() {
|
||||
var form = $('form.edit_labels.issue');
|
||||
$.ajax({
|
||||
|
@ -303,3 +266,18 @@ $(document).ready(function() {
|
|||
});
|
||||
|
||||
});
|
||||
|
||||
function updateAssignedUser(item) {
|
||||
$('#assigned-popup').hide();
|
||||
var container = item.find('.container').clone();
|
||||
$('#assigned-container .user-container').empty().append(container.html()).append('<span class="icon-share"></span>');
|
||||
}
|
||||
|
||||
function remLabel(form, id) {
|
||||
var el = form.find('.label.remove_label'+'#'+id);
|
||||
var label = $('#'+id+'.remove_label.label.selected');
|
||||
label.find('.flag').fadeIn(0);
|
||||
label.find('.labeltext.selected').removeClass('selected').attr('style', '');
|
||||
label.fadeIn('slow');
|
||||
el.fadeOut('slow').remove();
|
||||
}
|
|
@ -1898,10 +1898,107 @@ table#myTable thead tr.search th form.button_to div input {
|
|||
}
|
||||
|
||||
.activity .state {
|
||||
float: right;
|
||||
padding: 3px 10px;
|
||||
margin: 3px 0;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
border-radius: 2px;
|
||||
float: right;
|
||||
padding: 3px 10px;
|
||||
margin: 3px 0;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
article .activity .top {
|
||||
|
||||
.created {
|
||||
margin-left: 50px;
|
||||
span, a {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
.issue_title.text {
|
||||
max-width: none;
|
||||
float: none;
|
||||
margin-left: 50px;
|
||||
padding: 0;
|
||||
}
|
||||
h3.issue_title {
|
||||
margin: 5px 0 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
.assigned-header {
|
||||
padding: 10px 20px;
|
||||
border: 1px solid #D6D6D6;
|
||||
margin: 10px -7px;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
#assigned-container {
|
||||
.icon-share {
|
||||
cursor: pointer;
|
||||
}
|
||||
.image {
|
||||
float: left;
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: -1px 5px 0 0;
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
.name {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
#assigned-popup {
|
||||
position: absolute;
|
||||
margin: 5px 0 0 130px;
|
||||
display: none;
|
||||
min-width: 240px;
|
||||
border: 1px solid #b3cce0;
|
||||
background: #FFF;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 5px;
|
||||
.header .icon-remove-circle {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
}
|
||||
.header {
|
||||
padding: 10px;
|
||||
background: #dcecfa;
|
||||
border-bottom: 1px solid #D6D6D6;
|
||||
font-weight: bold;
|
||||
.title { display: inline-block; }
|
||||
}
|
||||
.search-container {
|
||||
padding: 10px 15px 10px 10px;
|
||||
border-bottom: 1px solid #D6D6D6;
|
||||
input {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
.edit_assignee {
|
||||
display: none;
|
||||
}
|
||||
#manage_issue_users_list {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
max-height: 280px;
|
||||
.people, .nothing {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
padding: 10px 20px 10px 10px;
|
||||
}
|
||||
.clear, .nothing {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -762,7 +762,7 @@ article div.activity div.top div.text {
|
|||
font-size: 12px;
|
||||
}
|
||||
|
||||
article div.activity div.top div.text span.name {
|
||||
article div.activity div.top span.name {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class Api::V1::BaseController < ApplicationController
|
|||
|
||||
def update_subject(subject)
|
||||
class_name = subject.class.name
|
||||
if subject.update_attributes(params[class_name.downcase.to_sym] || {})
|
||||
if subject.update_attributes(params[class_name.underscore.to_sym] || {})
|
||||
render_json_response subject, "#{class_name} has been updated successfully"
|
||||
else
|
||||
render_validation_error subject, "#{class_name} has not been updated"
|
||||
|
|
|
@ -27,6 +27,11 @@ class Api::V1::ProductBuildListsController < Api::V1::BaseController
|
|||
def show
|
||||
end
|
||||
|
||||
def update
|
||||
params[:product_build_list] = {:not_delete => (params[:product_build_list] || {})[:not_delete]}
|
||||
update_subject @product_build_list
|
||||
end
|
||||
|
||||
def destroy
|
||||
destroy_subject @product_build_list
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@ class Platforms::ProductBuildListsController < Platforms::BaseController
|
|||
load_and_authorize_resource :platform, :except => :index
|
||||
load_and_authorize_resource :product, :through => :platform, :except => :index
|
||||
load_and_authorize_resource :product_build_list, :through => :product, :except => :index
|
||||
load_and_authorize_resource :only => [:index, :show, :log, :cancel]
|
||||
load_and_authorize_resource :only => [:index, :show, :log, :cancel, :update]
|
||||
|
||||
def new
|
||||
product = @product_build_list.product
|
||||
|
@ -23,6 +23,16 @@ class Platforms::ProductBuildListsController < Platforms::BaseController
|
|||
def show
|
||||
end
|
||||
|
||||
def update
|
||||
if @product_build_list.update_attributes(:not_delete => (params[:product_build_list] || {})[:not_delete])
|
||||
flash[:notice] = t('flash.product_build_list.updated')
|
||||
else
|
||||
flash[:error] = t('flash.product_build_list.update_error')
|
||||
flash[:warning] = @product_build_list.errors.full_messages.join('. ')
|
||||
end
|
||||
redirect_to platform_product_product_build_list_path(@platform, @product, @product_build_list)
|
||||
end
|
||||
|
||||
def cancel
|
||||
if @product_build_list.cancel
|
||||
notice = t('layout.build_lists.will_be_canceled')
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class Platforms::ProductsController < Platforms::BaseController
|
||||
include GitHelper
|
||||
before_filter :authenticate_user!
|
||||
skip_before_filter :authenticate_user!, :only => [:index, :show] if APP_CONFIG['anonymous_access']
|
||||
|
||||
|
@ -55,7 +56,12 @@ class Platforms::ProductsController < Platforms::BaseController
|
|||
search(params[:term]).search_order
|
||||
items.select! {|e| e.repo.branches.count > 0}
|
||||
render :json => items.map{ |p|
|
||||
{:id => p.id, :label => p.name_with_owner, :value => p.name_with_owner}
|
||||
{
|
||||
:id => p.id,
|
||||
:label => p.name_with_owner,
|
||||
:value => p.name_with_owner,
|
||||
:project_versions => versions_for_group_select(p)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -5,6 +5,13 @@ class Projects::BaseController < ApplicationController
|
|||
|
||||
protected
|
||||
|
||||
def find_collaborators
|
||||
search = "%#{params[:search_user]}%"
|
||||
users = User.joins(:groups => :projects).where(:projects => {:id => @project.id}).where("users.uname ILIKE ?", search)
|
||||
users2 = @project.collaborators.where("users.uname ILIKE ?", search)
|
||||
@users = (users + users2).uniq.sort {|x,y| x.uname <=> y.uname}.first(10)
|
||||
end
|
||||
|
||||
def find_project
|
||||
@project = Project.find_by_owner_and_name!(params[:owner_name], params[:project_name]) if params[:owner_name] && params[:project_name]
|
||||
end
|
||||
|
|
|
@ -6,6 +6,7 @@ class Projects::IssuesController < Projects::BaseController
|
|||
load_resource :project
|
||||
load_and_authorize_resource :issue, :through => :project, :find_by => :serial_id, :only => [:show, :edit, :update, :destroy, :new, :create, :index]
|
||||
before_filter :load_and_authorize_label, :only => NON_RESTFUL_ACTION
|
||||
before_filter :find_collaborators, :only => [:new, :create, :show, :search_collaborators]
|
||||
|
||||
layout false, :only => [:update, :search_collaborators]
|
||||
|
||||
|
@ -91,10 +92,6 @@ class Projects::IssuesController < Projects::BaseController
|
|||
end
|
||||
|
||||
def search_collaborators
|
||||
search = "%#{params[:search_user]}%"
|
||||
users = User.joins(:groups => :projects).where(:projects => {:id => @project.id}).where("users.uname ILIKE ?", search)
|
||||
users2 = @project.collaborators.where("users.uname ILIKE ?", search)
|
||||
@users = (users + users2).uniq.sort {|x,y| x.uname <=> y.uname}.first(10)
|
||||
render :partial => 'search_collaborators'
|
||||
end
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ class Projects::PullRequestsController < Projects::BaseController
|
|||
|
||||
load_resource :issue, :through => :project, :find_by => :serial_id, :parent => false, :except => [:index, :autocomplete_to_project]
|
||||
load_and_authorize_resource :instance_name => :pull, :through => :issue, :singleton => true, :except => [:index, :autocomplete_to_project]
|
||||
before_filter :find_collaborators, :only => [:new, :create, :show]
|
||||
|
||||
def new
|
||||
to_project = find_destination_project(false)
|
||||
|
@ -37,6 +38,7 @@ class Projects::PullRequestsController < Projects::BaseController
|
|||
authorize! :read, to_project
|
||||
|
||||
@pull = to_project.pull_requests.new pull_params
|
||||
@pull.issue.assignee_id = (params[:issue] || {})[:assignee_id]
|
||||
@pull.issue.user, @pull.issue.project, @pull.from_project = current_user, to_project, @project
|
||||
@pull.from_project_owner_uname = @pull.from_project.owner.uname
|
||||
@pull.from_project_name = @pull.from_project.name
|
||||
|
@ -90,6 +92,7 @@ class Projects::PullRequestsController < Projects::BaseController
|
|||
|
||||
def index(status = 200)
|
||||
@issues_with_pull_request = @project.issues.joins(:pull_request)
|
||||
@issues_with_pull_request = @issues_with_pull_request.where(:assignee_id => current_user.id) if @is_assigned_to_me = params[:filter] == 'to_me'
|
||||
@issues_with_pull_request = @issues_with_pull_request.search(params[:search_pull_request]) if params[:search_pull_request] !~ /#{t('layout.pull_requests.search')}/
|
||||
|
||||
@opened_issues, @closed_issues = @issues_with_pull_request.not_closed_or_merged.count, @issues_with_pull_request.closed_or_merged.count
|
||||
|
|
|
@ -68,6 +68,7 @@ module GitHelper
|
|||
end
|
||||
|
||||
def versions_for_group_select(project)
|
||||
return [] unless project
|
||||
[ ['Branches', project.repo.branches.map(&:name)],
|
||||
['Tags', project.repo.tags.map(&:name)] ]
|
||||
end
|
||||
|
|
|
@ -117,7 +117,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, :cancel], ProductBuildList) {|pbl| can?(:update, pbl.product)}
|
||||
can([:create, :cancel, :update], 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}
|
||||
|
|
|
@ -55,9 +55,16 @@ class MassBuild < ActiveRecord::Base
|
|||
|
||||
def generate_failed_builds_list
|
||||
report = ""
|
||||
BuildList.where(:status => BuildList::BUILD_ERROR, :mass_build_id => self.id).each do |build_list|
|
||||
report << "ID: #{build_list.id}; "
|
||||
report << "PROJECT_NAME: #{build_list.project.name}\n"
|
||||
BuildList.select('build_lists.id, projects.name as project_name, arches.name as arch_name').
|
||||
where(
|
||||
:status => BuildList::BUILD_ERROR,
|
||||
:mass_build_id => self.id
|
||||
).joins(:project, :arch).find_in_batches(:batch_size => 100) do |build_lists|
|
||||
build_lists.each do |build_list|
|
||||
report << "ID: #{build_list.id}; "
|
||||
report << "PROJECT_NAME: #{build_list.project_name}; "
|
||||
report << "ARCH: #{build_list.arch_name}\n"
|
||||
end
|
||||
end
|
||||
report
|
||||
end
|
||||
|
|
|
@ -182,6 +182,9 @@ class Platform < ActiveRecord::Base
|
|||
end
|
||||
later :destroy, :queue => :clone_build
|
||||
|
||||
def default_host
|
||||
EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
|
@ -189,9 +192,6 @@ class Platform < ActiveRecord::Base
|
|||
system("mkdir -p -m 0777 #{build_path([name, 'repository'])}")
|
||||
end
|
||||
|
||||
def default_host
|
||||
EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
|
||||
end
|
||||
|
||||
def build_path(dir)
|
||||
File.join(APP_CONFIG['root_path'], 'platforms', dir)
|
||||
|
|
|
@ -6,9 +6,22 @@ class Product < ActiveRecord::Base
|
|||
belongs_to :project
|
||||
has_many :product_build_lists, :dependent => :destroy
|
||||
|
||||
ONCE_A_12_HOURS = 0
|
||||
ONCE_A_DAY = 1
|
||||
ONCE_A_WEEK = 2
|
||||
|
||||
AUTOSTART_STATUSES = [ONCE_A_12_HOURS, ONCE_A_DAY, ONCE_A_WEEK]
|
||||
HUMAN_AUTOSTART_STATUSES = {
|
||||
ONCE_A_12_HOURS => :once_a_12_hours,
|
||||
ONCE_A_DAY => :once_a_day,
|
||||
ONCE_A_WEEK => :once_a_week
|
||||
}
|
||||
|
||||
validates :name, :presence => true, :uniqueness => {:scope => :platform_id}
|
||||
validates :project_id, :presence => true
|
||||
validates :main_script, :params, :length => { :maximum => 255 }
|
||||
validates :autostart_status, :numericality => true,
|
||||
:inclusion => {:in => AUTOSTART_STATUSES}, :allow_blank => true
|
||||
|
||||
scope :recent, order("#{table_name}.name ASC")
|
||||
|
||||
|
@ -17,7 +30,9 @@ class Product < ActiveRecord::Base
|
|||
:project_id,
|
||||
:main_script,
|
||||
:params,
|
||||
:platform_id
|
||||
:platform_id,
|
||||
:autostart_status,
|
||||
:project_version
|
||||
attr_readonly :platform_id
|
||||
|
||||
def full_clone(attrs = {})
|
||||
|
@ -30,4 +45,35 @@ class Product < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def human_autostart_status
|
||||
self.class.human_autostart_status(autostart_status)
|
||||
end
|
||||
|
||||
def self.human_autostart_status(autostart_status)
|
||||
I18n.t("layout.products.autostart_statuses.#{HUMAN_AUTOSTART_STATUSES[autostart_status]}")
|
||||
end
|
||||
|
||||
class << self
|
||||
HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
|
||||
define_method "autostart_iso_builds_#{human_autostart_status}" do
|
||||
autostart_iso_builds autostart_status
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.autostart_iso_builds(autostart_status)
|
||||
Product.where(:autostart_status => autostart_status).each do |product|
|
||||
pbl = product.product_build_lists.new
|
||||
[:params, :main_script, :project, :project_version].each do |k|
|
||||
pbl.send "#{k}=", product.send(k)
|
||||
end
|
||||
owner = product.platform.owner
|
||||
pbl.user = owner.is_a?(User) ? owner : owner.owner
|
||||
pbl.autostarted = true
|
||||
pbl.base_url = "http://#{product.platform.default_host}"
|
||||
pbl.time_living = product.time_living / 60
|
||||
pbl.save
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -6,6 +6,9 @@ class ProductBuildList < ActiveRecord::Base
|
|||
include AbfWorker::ModelHelper
|
||||
delegate :url_helpers, to: 'Rails.application.routes'
|
||||
|
||||
LIVE_TIME = 2.week # for autostart
|
||||
MAX_LIVE_TIME = 3.month # for manual start;
|
||||
|
||||
BUILD_COMPLETED = 0
|
||||
BUILD_FAILED = 1
|
||||
BUILD_PENDING = 2
|
||||
|
@ -35,7 +38,9 @@ class ProductBuildList < ActiveRecord::Base
|
|||
belongs_to :user
|
||||
|
||||
# see: Issue #6
|
||||
before_validation lambda { self.arch_id = Arch.find_by_name('x86_64').id }
|
||||
before_validation lambda { self.arch_id = Arch.find_by_name('x86_64').id }, :on => :create
|
||||
# field "not_delete" can be changed only if build has been completed
|
||||
before_validation lambda { self.not_delete = false unless build_completed?; true }
|
||||
validates :product_id,
|
||||
:status,
|
||||
:project_id,
|
||||
|
@ -53,7 +58,8 @@ class ProductBuildList < ActiveRecord::Base
|
|||
:params,
|
||||
:project_version,
|
||||
:commit_hash,
|
||||
:product_id
|
||||
:product_id,
|
||||
:not_delete
|
||||
attr_readonly :product_id
|
||||
serialize :results, Array
|
||||
|
||||
|
@ -63,6 +69,8 @@ class ProductBuildList < ActiveRecord::Base
|
|||
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}%")}
|
||||
scope :recent, order("#{table_name}.updated_at DESC")
|
||||
scope :outdated, where(:not_delete => false).
|
||||
where("(#{table_name}.created_at < ? AND #{table_name}.autostarted is TRUE) OR #{table_name}.created_at < ?", Time.now - LIVE_TIME, Time.now - MAX_LIVE_TIME)
|
||||
|
||||
after_create :add_job_to_abf_worker_queue
|
||||
before_destroy :can_destroy?
|
||||
|
|
|
@ -87,7 +87,7 @@ class PullRequest < ActiveRecord::Base
|
|||
system("git reset --hard HEAD^") # for diff maybe FIXME
|
||||
|
||||
if old_commit.id == to_project.repo.commits(to_ref).first.id
|
||||
raise "merge result pull_request #{id}: #{res}; #{res2}"
|
||||
raise "merge result pull_request #{id}: #{$?.exitstatus}; #{res2}; #{res}"
|
||||
end
|
||||
set_user_and_time who
|
||||
merging
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
json.product_build_list do |json|
|
||||
json.partial! 'product_build_list', :product_build_list => @product_build_list, :json => json
|
||||
json.(@product_build_list, :commit_hash, :main_script, :params)
|
||||
json.(@product_build_list, :commit_hash, :main_script, :params, :not_delete, :autostarted)
|
||||
|
||||
json.product do |json_product|
|
||||
json.partial! 'api/v1/products/product',
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
json.(product, :id, :name, :description, :main_script, :params, :time_living)
|
||||
json.(product, :id, :name, :description, :main_script, :params, :time_living, :autostart_status)
|
||||
json.url api_v1_product_path(product, :format => :json)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
.both
|
||||
|
||||
.leftlist= f.label :project_version, t("activerecord.attributes.product_build_list.project_version"), :class => :label
|
||||
.rightlist= f.select :project_version, versions_for_group_select(pbl.project), :selected => params[:product_build_lists].try(:fetch, :project_version) || pbl.project.default_branch
|
||||
.rightlist= f.select :project_version, versions_for_group_select(pbl.project), :selected => params[:product_build_lists].try(:fetch, :project_version) || @product.project_version || pbl.project.default_branch
|
||||
.both
|
||||
|
||||
= render 'platforms/products/def_fields', :f => f
|
||||
|
|
|
@ -24,12 +24,35 @@
|
|||
|
||||
= render 'show_field', :key => :time_living, :value => (pbl.time_living / 60)
|
||||
|
||||
= render 'show_field', :key => :autostarted, :value => t("layout.#{pbl.autostarted}_")
|
||||
|
||||
= 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
|
||||
%br
|
||||
|
||||
- if pbl.build_completed? && can?(:update, pbl)
|
||||
= form_for pbl, :url => platform_product_product_build_list_path(pbl.product.platform, pbl.product, pbl) do |f|
|
||||
.leftlist= f.label :not_delete
|
||||
.rightlist
|
||||
= f.select :not_delete, [false, true].collect{|status| [t("layout.#{status}_"), status]}, {:selected => pbl.not_delete}
|
||||
.both
|
||||
%br
|
||||
= submit_tag t('layout.update')
|
||||
.both
|
||||
- unless pbl.not_delete
|
||||
.flash_notify
|
||||
.alert.alert-error
|
||||
- days = pbl.autostarted? ? ProductBuildList::LIVE_TIME : ProductBuildList::MAX_LIVE_TIME
|
||||
- days = (pbl.created_at.to_date - days.ago.to_date).to_i
|
||||
- if days > 1
|
||||
= t('layout.product_build_lists.will_be_removed_n_days', :n => days)
|
||||
- else
|
||||
= t('layout.product_build_lists.will_be_removed_today')
|
||||
.both
|
||||
|
||||
- if pbl.build_started? || pbl.build_canceling?
|
||||
= render 'shared/log', { :build_started => true, :get_log_path => log_platform_product_product_build_list_path(pbl.product.platform, pbl.product, pbl) }
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
.leftlist= f.label :name, t("activerecord.attributes.product.name"), :class => :label
|
||||
.leftlist= f.label :name
|
||||
.rightlist= f.text_field :name, :class => 'text_field'
|
||||
.both
|
||||
|
||||
.leftlist= f.label :description, t("activerecord.attributes.product.description"), :class => :label
|
||||
.leftlist= f.label :description
|
||||
.rightlist= f.text_area :description, :class => 'text_field resizable', :cols => 80
|
||||
.both
|
||||
|
||||
.leftlist= f.label :project, t("activerecord.attributes.product.project"), :class => :label
|
||||
.leftlist= f.label :project
|
||||
.rightlist= f.autocomplete_field :project, autocomplete_project_platform_products_path(@platform), :id_element => 'src_project_id', :name => 'src_project', :value => @product.project.try(:name_with_owner)
|
||||
.both
|
||||
|
||||
.leftlist= f.label :project_version
|
||||
.rightlist= f.select :project_version, versions_for_group_select(@product.project), {:selected => params[:products].try(:fetch, :project_version) || @product.project_version, :include_blank => true}
|
||||
.both
|
||||
|
||||
= render 'def_fields', :f => f
|
||||
|
||||
.leftlist= f.label :autostart_status
|
||||
.rightlist= f.select :autostart_status, Product::AUTOSTART_STATUSES.collect{|status| [Product.human_autostart_status(status), status]}, {:include_blank => true, :selected => @product.autostart_status}
|
||||
.both
|
||||
|
||||
.button_block
|
||||
= submit_tag t("layout.save")
|
||||
%span.text_button_padding= t("layout.or")
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#assigned-popup
|
||||
.header
|
||||
.title= t('layout.issues.assign_someone')
|
||||
%span.icon-remove-circle
|
||||
.search-container
|
||||
#search_user_path{:path => search_collaborators_project_issues_path(@project)}
|
||||
= tracker_search_field(:search_user, t('layout.issues.search_user'))
|
||||
|
||||
|
||||
- unless [:new, :create].include?(action_name.to_sym)
|
||||
= form_for :issue, :url => [@project, @issue], :method => :put, :html => { :class => 'edit_assignee issue'} do |f|
|
||||
= hidden_field_tag "user-default_assignee", nil, :name => 'issue[assignee_id]'
|
||||
#manage_issue_users_list
|
||||
= render 'projects/issues/search_collaborators'
|
|
@ -1,8 +1,7 @@
|
|||
=render 'title_body', :f => f, :id => 'new'
|
||||
.leftlist= t('activerecord.attributes.issue.assignee') + ':'
|
||||
.rightlist
|
||||
%span#people-span.small-text= t('layout.issues.choose_user_on_left')
|
||||
#issue_assignee
|
||||
#assigned-container.rightlist
|
||||
=render 'user_container', :user => @issue.assignee
|
||||
.both
|
||||
.leftlist= t('layout.issues.labels') + ':'
|
||||
.rightlist
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
%h3.issue_title=@issue.title
|
||||
.activity
|
||||
.top
|
||||
.image
|
||||
=image_tag(avatar_url(@issue.user, :medium), :alt => 'avatar') if @issue.user
|
||||
.text
|
||||
%span.name=link_to(@issue.user.fullname, user_path(@issue.user)) if @issue.user
|
||||
%br/
|
||||
%span.date=@issue.created_at.to_s(:long)
|
||||
%br/
|
||||
.created
|
||||
%span=@issue.created_at.to_s(:long)
|
||||
- if @issue.user
|
||||
%span= t('layout.by')
|
||||
%span.name=link_to(@issue.user.fullname, user_path(@issue.user))
|
||||
.text.issue_title
|
||||
%h3.issue_title=@issue.title
|
||||
.both
|
||||
#assigned-container.assigned-header
|
||||
=render 'projects/issues/user_container', :user => @issue.assignee
|
||||
=render 'projects/issues/assigned_popup'
|
||||
.both
|
||||
.fulltext.view.issue_body.formatted.cm-s-default.md_and_cm=markdown @issue.body
|
||||
.both
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
-content_for :sidebar do
|
||||
- if current_user
|
||||
=form_tag project_issues_path(@project), :id => 'filter_issues', :method => :get do
|
||||
.bordered.nopadding
|
||||
%h3=t("layout.issues.accessory")
|
||||
.bordered
|
||||
%table
|
||||
%tr
|
||||
%td.width18=radio_button_tag :myradio, 'all', !@is_assigned_to_me, {:id => 'myradio1', :class => 'niceRadio', :name => 'filter'}
|
||||
|
|
|
@ -9,32 +9,6 @@
|
|||
- if can_manage
|
||||
=form_tag [@project, @issue], :id => 'update_issue_status', :method => :put do
|
||||
=hidden_field_tag "issue_status", @issue.closed? ? 'closed' : 'open', :name => "issue[status]"
|
||||
.bordered.nopadding
|
||||
%h3=t('layout.issues.assignee')
|
||||
- if @issue.persisted?
|
||||
-if can_manage
|
||||
=form_for :issue, :url => [@project, @issue], :method => :put, :html => { :class => 'edit_assignee issue'} do |f|
|
||||
=hidden_field_tag "user-default_assignee", nil, :name => 'issue[assignee_id]'
|
||||
.current_assignee
|
||||
- if @issue.assignee
|
||||
#user-0.people.nopointer
|
||||
.avatar=image_tag avatar_url(@issue.assignee), :alt => 'avatar'
|
||||
.name=@issue.assignee.fullname
|
||||
=hidden_field_tag "user-0", @issue.assignee.id, :name => 'issue[assignee_id]'
|
||||
.both
|
||||
- elsif @issue.assignee
|
||||
.people.nopointer
|
||||
.avatar=image_tag avatar_url(@issue.assignee), :alt => 'avatar'
|
||||
.name=@issue.assignee.fullname
|
||||
.both
|
||||
=link_to(t('layout.issues.assignee_manage'), '#', :class => "button tmargin10 manage_assignee") if can_manage
|
||||
- if can_manage
|
||||
=form_tag search_collaborators_project_issues_path(@project), :id => 'search_user', :method => :get, :style => @issue.persisted? ? 'display:none' : '' do
|
||||
=tracker_search_field(:search_user, t('layout.issues.search_user'))
|
||||
#manage_issue_users_list
|
||||
=render 'search_collaborators'
|
||||
=link_to(t('layout.issues.done'), '#', :class => "button tmargin10 update_assignee", :style => 'display:none') if can_manage
|
||||
|
||||
.block
|
||||
%h3=t('layout.issues.labels')
|
||||
- if can_manage
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
- (@users || []).each_with_index do |user, index|
|
||||
.people.clear.selected
|
||||
%span.icon-remove-circle
|
||||
= t('layout.issues.clear_assignee')
|
||||
.container
|
||||
%span= t('layout.issues.no_one_is_assigned')
|
||||
= hidden_field_tag "user-nil", nil, :name => "issue[assignee_id]"
|
||||
|
||||
- users = (@users || [])
|
||||
- users.each_with_index do |user, index|
|
||||
.people.selected{:id => "user-#{index}", :class => 'add_assignee'}
|
||||
.avatar= image_tag(avatar_url(user), :alt => 'avatar')
|
||||
.name=user.fullname
|
||||
=hidden_field_tag "user-#{index}", user.id, :name => 'issue[assignee_id]'
|
||||
.name= user.fullname
|
||||
.container
|
||||
.image
|
||||
= image_tag(avatar_url(user, :micro), :alt => 'avatar')
|
||||
%span.name= link_to(user.uname, user_path(user))
|
||||
%span= t('layout.issues.is_assigned')
|
||||
= hidden_field_tag "user-#{index}", user.id, :name => "issue[assignee_id]"
|
||||
.both
|
||||
- if users.empty?
|
||||
.nothing= t('layout.issues.nothing_to_show')
|
|
@ -0,0 +1,10 @@
|
|||
.user-container
|
||||
- if user
|
||||
.image
|
||||
=image_tag(avatar_url(user, :micro), :alt => 'avatar')
|
||||
%span.name= link_to(user.uname, user_path(user))
|
||||
%span= t('layout.issues.is_assigned')
|
||||
- else
|
||||
%span= t('layout.issues.no_one_is_assigned')
|
||||
-if can?(:update, @issue) || @issue.new_record?
|
||||
%span.icon-share
|
|
@ -3,8 +3,8 @@
|
|||
-render 'manage_sidebar'
|
||||
|
||||
%h3.bpadding10= t("layout.issues.create_header")
|
||||
= form_for :issue, :url => project_issues_path(@project), :html => { :class => 'form issue' } do |f|
|
||||
=render 'projects/issues/assigned_popup'
|
||||
= form_for :issue, :url => project_issues_path(@project), :html => { :class => 'form issue new' } do |f|
|
||||
= render "form", :f => f
|
||||
=hidden_field_tag :preview_url, project_md_preview_path(@project)
|
||||
= render "projects/comments/markdown_help"
|
||||
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
-content_for :sidebar do
|
||||
- if current_user
|
||||
=form_tag project_pull_requests_path(@project), :id => 'filter_issues', :method => :get do
|
||||
.bordered
|
||||
%table
|
||||
%tr
|
||||
%td.width18=radio_button_tag :myradio, 'all', !@is_assigned_to_me, {:id => 'myradio1', :class => 'niceRadio', :name => 'filter'}
|
||||
%td.width135=t("layout.pull_requests.all")
|
||||
%td.width30.right=@project.issues.joins(:pull_request).count
|
||||
%tr
|
||||
%td=radio_button_tag :myradio, 'to_me', @is_assigned_to_me, {:id => 'myradio1', :class => 'niceRadio', :name => 'filter'}
|
||||
%td=t("layout.pull_requests.to_me")
|
||||
%td.width30.right=@project.issues.joins(:pull_request).where(:assignee_id => current_user.id).count
|
||||
=form_tag project_pull_requests_path(@project), :id => 'filter_pull_requests', :method => :get, :class => 'ajax_search_form' do
|
||||
.bordered.bpadding20
|
||||
- search = params[:search_pull_request].present? ? params[:search_pull_request] : t('layout.pull_requests.search')
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
.tab-content.pull_diff_fix
|
||||
#discussion.tab-pane.active
|
||||
=hidden_field_tag :update_action, new_project_pull_request_path
|
||||
=render 'projects/issues/assigned_popup'
|
||||
=form_for @pull, :url => (@pull.already? ? new_project_pull_request_path : project_pull_requests_path), :html => {:class => 'well well-large', :method => (@pull.already? ? :get : :post)} do |f|
|
||||
|
||||
.leftlist=f.label :from_project, t("#{ar}.from_project"), :class => :label
|
||||
|
@ -31,6 +32,11 @@
|
|||
%div{:class => @pull.ready? ? 'notice' : 'alert'}
|
||||
=pull_status @pull
|
||||
.both
|
||||
|
||||
.leftlist.big-list= t('activerecord.attributes.issue.assignee') + ':'
|
||||
#assigned-container.rightlist
|
||||
=render 'projects/issues/user_container', :user => @pull.assignee
|
||||
.both
|
||||
.leftlist.big-list
|
||||
.rightlist
|
||||
=f.submit t('.submit'), :class => 'btn btn-primary disabled', 'data-loading-text' => t('layout.processing'), :id => 'create_pull' unless @pull.already?
|
||||
|
|
|
@ -11,9 +11,13 @@ en:
|
|||
|
||||
layout:
|
||||
issues:
|
||||
accessory: Accessory issues
|
||||
is_assigned: is assigned
|
||||
clear_assignee: Clear assignee
|
||||
nothing_to_show: Nothing to show
|
||||
no_one_is_assigned: No one is assigned
|
||||
assign_someone: Assign someone to this issue
|
||||
list: List
|
||||
all: All
|
||||
all: All issues
|
||||
to_me: Assigned to me
|
||||
edit: Edit
|
||||
search: Find issue...
|
||||
|
|
|
@ -11,9 +11,13 @@ ru:
|
|||
|
||||
layout:
|
||||
issues:
|
||||
accessory: Принадлежность заданий
|
||||
is_assigned: назначен
|
||||
clear_assignee: Убрать назначение
|
||||
nothing_to_show: Никто не найден
|
||||
no_one_is_assigned: Никто не назначен
|
||||
assign_someone: Назначить кого-либо на задачу
|
||||
list: Список
|
||||
all: Все
|
||||
all: Все задачи
|
||||
to_me: Назначенные мне
|
||||
edit: Редактировать
|
||||
search: Найти задачу...
|
||||
|
|
|
@ -11,6 +11,10 @@ en:
|
|||
new_header: New product
|
||||
edit_header: Product editing
|
||||
confirm_delete: Are you sure you want to delete this product?
|
||||
autostart_statuses:
|
||||
once_a_12_hours: Once a 12 hours
|
||||
once_a_day: Once a day
|
||||
once_a_week: Once a week
|
||||
|
||||
flash:
|
||||
product:
|
||||
|
@ -25,8 +29,10 @@ en:
|
|||
product: Product
|
||||
attributes:
|
||||
product:
|
||||
autostart_status: Autostart
|
||||
name: Name
|
||||
description: Description
|
||||
project_version: Version
|
||||
platform_id: Platform
|
||||
build_status: Build status
|
||||
created_at: Created
|
||||
|
|
|
@ -11,6 +11,10 @@ ru:
|
|||
new_header: Новый продукт
|
||||
edit_header: Редактирование продукта
|
||||
confirm_delete: Вы уверены, что хотите удалить этот продукт?
|
||||
autostart_statuses:
|
||||
once_a_12_hours: Раз в 12 часов
|
||||
once_a_day: Раз в день
|
||||
once_a_week: Раз в неделю
|
||||
|
||||
flash:
|
||||
product:
|
||||
|
@ -25,8 +29,10 @@ ru:
|
|||
product: Продукт
|
||||
attributes:
|
||||
product:
|
||||
autostart_status: Автостарт
|
||||
name: Название
|
||||
description: Описание
|
||||
project_version: Версия
|
||||
platform_id: Платформа
|
||||
build_status: Статус последней сборки
|
||||
created_at: Создан
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
en:
|
||||
layout:
|
||||
product_build_lists:
|
||||
will_be_removed_n_days: Product build list will be removed through %{n} d.
|
||||
will_be_removed_today: Product build list will be removed today
|
||||
logs: Logs (last 100 lines)
|
||||
work_env: Work environment
|
||||
iso_builder_folder: folder with contents of the GIT project
|
||||
|
@ -29,6 +31,8 @@ en:
|
|||
activerecord:
|
||||
attributes:
|
||||
product_build_list:
|
||||
autostarted: Autostart
|
||||
not_delete: Not delete
|
||||
id: Id
|
||||
user: User
|
||||
product: Product
|
||||
|
@ -53,3 +57,5 @@ en:
|
|||
no_project: Project for build should be exist
|
||||
delete: Product build list deleted
|
||||
delete_error: Unable to delete product build list
|
||||
updated: Product build list updated
|
||||
update_error: Unable to update product build list
|
|
@ -1,6 +1,8 @@
|
|||
ru:
|
||||
layout:
|
||||
product_build_lists:
|
||||
will_be_removed_n_days: Cборочный лист продукта будет удален через %{n} д.
|
||||
will_be_removed_today: Cборочный лист продукта будет удален в течение дня
|
||||
logs: Логи (последнии 100 строк)
|
||||
work_env: Рабочее пространство
|
||||
iso_builder_folder: папка с содержимым GIT проекта
|
||||
|
@ -29,6 +31,8 @@ ru:
|
|||
activerecord:
|
||||
attributes:
|
||||
product_build_list:
|
||||
autostarted: Автоматически запущен
|
||||
not_delete: Не удалять
|
||||
id: Id
|
||||
user: Пользователь
|
||||
product: Продукт
|
||||
|
@ -53,3 +57,5 @@ ru:
|
|||
no_project: Проект для сборки должен присутствовать
|
||||
delete: Сборочный лист продукта удален
|
||||
delete_error: Не удалось удалить cборочный лист продукта
|
||||
updated: Cборочный лист продукта успешно обновлен
|
||||
update_error: Не удалось обновить cборочный лист продукта
|
|
@ -56,4 +56,6 @@ en:
|
|||
layout:
|
||||
pull_requests:
|
||||
search: Find pull request...
|
||||
all: All requests
|
||||
to_me: Assigned to me
|
||||
view_full_changes: View full changes
|
||||
|
|
|
@ -57,4 +57,6 @@ ru:
|
|||
layout:
|
||||
pull_requests:
|
||||
search: Найти пул реквест...
|
||||
all: Все пул реквесты
|
||||
to_me: Назначенные мне
|
||||
view_full_changes: Посмотреть все изменения
|
||||
|
|
|
@ -78,7 +78,7 @@ Rosa::Application.routes.draw do
|
|||
resources :products, :only => [:show, :update, :create, :destroy] do
|
||||
resources :product_build_lists, :only => :index
|
||||
end
|
||||
resources :product_build_lists, :only => [:index, :show, :destroy, :create] do
|
||||
resources :product_build_lists, :only => [:index, :show, :destroy, :create, :update] do
|
||||
put :cancel, :on => :member
|
||||
end
|
||||
#resources :ssh_keys, :only => [:index, :create, :destroy]
|
||||
|
@ -163,7 +163,7 @@ Rosa::Application.routes.draw do
|
|||
end
|
||||
resources :key_pairs, :only => [:create, :index, :destroy]
|
||||
resources :products do
|
||||
resources :product_build_lists, :only => [:create, :destroy, :new, :show] do
|
||||
resources :product_build_lists, :only => [:create, :destroy, :new, :show, :update] do
|
||||
member {
|
||||
get :log
|
||||
put :cancel
|
||||
|
|
|
@ -7,22 +7,40 @@
|
|||
# runner "Download.parse_and_remove_nginx_log"
|
||||
#end
|
||||
|
||||
every 1.day, :at => '4:00 am' do
|
||||
# TODO: Uncomment when all needed product build lists will be updated.
|
||||
# every :day, :at => '4:10 am' do
|
||||
# rake "product_build_list:clear:outdated", :output => 'log/product_build_list_clear.log'
|
||||
# end
|
||||
|
||||
every :day, :at => '4:00 am' do
|
||||
rake "import:sync:all", :output => 'log/sync.log'
|
||||
end
|
||||
|
||||
every 1.day, :at => '3:50 am' do
|
||||
every :day, :at => '3:50 am' do
|
||||
rake "buildlist:clear:outdated", :output => 'log/build_list_clear.log'
|
||||
end
|
||||
|
||||
every 1.day, :at => '3:30 am' do
|
||||
every :day, :at => '3:30 am' do
|
||||
rake "pull_requests:clear", :output => 'log/pull_requests_clear.log'
|
||||
end
|
||||
|
||||
every 1.day, :at => '3:00 am' do
|
||||
every :day, :at => '3:00 am' do
|
||||
rake "activity_feeds:clear", :output => 'log/activity_feeds.log'
|
||||
end
|
||||
|
||||
every 3.minute do
|
||||
runner 'AbfWorker::BuildListsPublishTaskManager.new.run', :output => 'log/task_manager.log'
|
||||
end
|
||||
|
||||
every :day, :at => '4am' do
|
||||
runner 'Product.autostart_iso_builds_once_a_12_hours', :output => 'log/autostart_iso_builds.log'
|
||||
runner 'Product.autostart_iso_builds_once_a_day', :output => 'log/autostart_iso_builds.log'
|
||||
end
|
||||
|
||||
every :day, :at => '4pm' do
|
||||
runner 'Product.autostart_iso_builds_once_a_12_hours', :output => 'log/autostart_iso_builds.log'
|
||||
end
|
||||
|
||||
every :sunday, :at => '4am' do
|
||||
runner 'Product.autostart_iso_builds_once_a_week', :output => 'log/autostart_iso_builds.log'
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
class AutostartIsoBuildOnRegularBasis < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :products, :autostart_status, :integer, :default => nil
|
||||
add_column :product_build_lists, :not_delete, :boolean, :default => false
|
||||
add_column :product_build_lists, :autostarted, :boolean, :default => false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class AddProjectVersionToProduct < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :products, :project_version, :string
|
||||
end
|
||||
end
|
28
db/schema.rb
28
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20130326165628) do
|
||||
ActiveRecord::Schema.define(:version => 20130327120129) do
|
||||
|
||||
create_table "activity_feeds", :force => true do |t|
|
||||
t.integer "user_id", :null => false
|
||||
|
@ -149,14 +149,12 @@ ActiveRecord::Schema.define(:version => 20130326165628) do
|
|||
t.string "commentable_type"
|
||||
t.integer "user_id"
|
||||
t.text "body"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.decimal "commentable_id", :precision => 50, :scale => 0
|
||||
t.integer "project_id"
|
||||
t.text "data"
|
||||
t.boolean "automatic", :default => false
|
||||
t.boolean "automatic", :default => false
|
||||
t.decimal "created_from_commit_hash", :precision => 50, :scale => 0
|
||||
t.integer "created_from_issue_id"
|
||||
end
|
||||
|
@ -313,9 +311,9 @@ ActiveRecord::Schema.define(:version => 20130326165628) do
|
|||
|
||||
create_table "product_build_lists", :force => true do |t|
|
||||
t.integer "product_id"
|
||||
t.integer "status", :default => 3, :null => false
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "status", :default => 3, :null => false
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "project_id"
|
||||
t.string "project_version"
|
||||
t.string "commit_hash"
|
||||
|
@ -325,20 +323,24 @@ ActiveRecord::Schema.define(:version => 20130326165628) do
|
|||
t.integer "arch_id"
|
||||
t.integer "time_living"
|
||||
t.integer "user_id"
|
||||
t.boolean "not_delete", :default => false
|
||||
t.boolean "autostarted", :default => false
|
||||
end
|
||||
|
||||
add_index "product_build_lists", ["product_id"], :name => "index_product_build_lists_on_product_id"
|
||||
|
||||
create_table "products", :force => true do |t|
|
||||
t.string "name", :null => false
|
||||
t.integer "platform_id", :null => false
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.string "name", :null => false
|
||||
t.integer "platform_id", :null => false
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.text "description"
|
||||
t.integer "project_id"
|
||||
t.string "params"
|
||||
t.string "main_script"
|
||||
t.integer "time_living"
|
||||
t.integer "autostart_status"
|
||||
t.string "project_version"
|
||||
end
|
||||
|
||||
create_table "project_imports", :force => true do |t|
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
namespace :product_build_list do
|
||||
|
||||
namespace :clear do
|
||||
desc 'Remove outdated ProductBuildLists'
|
||||
task :outdated => :environment do
|
||||
say "[#{Time.zone.now}] Removing outdated ProductBuildLists"
|
||||
say "[#{Time.zone.now}] There are #{ProductBuildList.outdated.count} outdated ProductBuildLists"
|
||||
ProductBuildList.outdated.destroy_all
|
||||
say "[#{Time.zone.now}] Outdated BuildLists have been removed"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
|
@ -64,7 +64,7 @@ shared_examples_for 'api user with admin rights' do
|
|||
params = {:product_id => @product_build_list.product_id, :arch_id => Arch.last.id,
|
||||
:commit_hash => commit_hash, :main_script => @product_build_list.main_script}
|
||||
@create_params = {:product_build_list =>{:time_living => 150}.merge(params)}
|
||||
@update_params = {:product_build_list =>{:time_living => 250}}
|
||||
@update_params = {:product_build_list =>{:time_living => 250, :not_delete => true}}
|
||||
end
|
||||
|
||||
it 'should be able to perform show action' do
|
||||
|
@ -96,14 +96,15 @@ shared_examples_for 'api user with admin rights' do
|
|||
lambda { put :destroy, :id => @product_build_list.id, :format => :json }.should change{ ProductBuildList.count }.by(-1)
|
||||
end
|
||||
|
||||
it "should not be able to perform update action" do
|
||||
put :update, :id => @product_build_list.id, :format => :json
|
||||
response.should_not be_success
|
||||
it "should be able to perform update action" do
|
||||
put :update, @update_params.merge(:id => @product_build_list.id), :format => :json
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
it "ensures that product has not been updated" do
|
||||
it "ensures that only not_delete field of product build list has been updated" do
|
||||
put :update, @update_params.merge(:id => @product_build_list.id), :format => :json
|
||||
@product_build_list.reload.time_living.should == 150*60 # in seconds
|
||||
@product_build_list.not_delete.should be_true
|
||||
end
|
||||
|
||||
it 'ensures that return correct answer for wrong creating action' do
|
||||
|
|
|
@ -35,6 +35,18 @@ shared_examples_for 'product build list admin' do
|
|||
response.should render_template(:show)
|
||||
end
|
||||
|
||||
it 'should be able to perform update action' do
|
||||
put :update, valid_attributes_for_show.merge(:product_build_list => {:time_living => 100,:not_delete => true})
|
||||
response.should redirect_to(platform_product_product_build_list_path(@product.platform, @product, @pbl))
|
||||
end
|
||||
|
||||
it "ensures that only not_delete field of product build list has been updated" do
|
||||
put :update, valid_attributes_for_show.merge(:product_build_list => {:time_living => 100,:not_delete => true})
|
||||
time_living = @pbl.time_living
|
||||
@pbl.reload.time_living.should == time_living
|
||||
@pbl.not_delete.should be_true
|
||||
end
|
||||
|
||||
it 'should be able to perform log action' do
|
||||
get :log, valid_attributes_for_show
|
||||
response.should be_success
|
||||
|
|
|
@ -5,5 +5,8 @@ FactoryGirl.define do
|
|||
association :platform, :factory => :platform
|
||||
association :project, :factory => :project_with_commit
|
||||
time_living 150
|
||||
|
||||
# see: before_validation in ProductBuildList model
|
||||
before(:create) { Arch.find_or_create_by_name('x86_64') }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ProductBuildList do
|
||||
before(:all) do
|
||||
before do
|
||||
stub_symlink_methods
|
||||
FactoryGirl.create(:product_build_list)
|
||||
end
|
||||
|
||||
it { should belong_to(:product) }
|
||||
|
@ -29,9 +30,8 @@ describe ProductBuildList do
|
|||
# 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
|
||||
ProductBuildList.accessible_by(ability).count.should == 1
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,15 +2,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Product do
|
||||
before(:all) do
|
||||
stub_symlink_methods
|
||||
Platform.delete_all
|
||||
User.delete_all
|
||||
Product.delete_all
|
||||
init_test_root
|
||||
# Need for validate_uniqueness_of check
|
||||
FactoryGirl.create(:product)
|
||||
end
|
||||
let!(:product) { FactoryGirl.create(:product) }
|
||||
|
||||
it { should belong_to(:platform) }
|
||||
it { should have_many(:product_build_lists)}
|
||||
|
@ -27,11 +19,35 @@ describe Product do
|
|||
#it { should_not allow_mass_assignment_of(:platform_id) }
|
||||
it { should_not allow_mass_assignment_of(:product_build_lists) }
|
||||
|
||||
after(:all) do
|
||||
Platform.delete_all
|
||||
User.delete_all
|
||||
Product.delete_all
|
||||
clear_test_root
|
||||
|
||||
context '#autostart_iso_builds' do
|
||||
|
||||
Product::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
|
||||
it "new product_build_lists should not be created if no products which should be autostarted #{human_autostart_status}" do
|
||||
lambda { Product.autostart_iso_builds(autostart_status) }.should_not change{ ProductBuildList.count }
|
||||
end
|
||||
end
|
||||
|
||||
context 'by autostart_status = once_a_12_hours' do
|
||||
before do
|
||||
stub_symlink_methods
|
||||
stub_redis
|
||||
params = {:main_script => 'text.sh', :project_version => product.project.default_branch}
|
||||
product.update_attributes params.merge(:autostart_status => Product::ONCE_A_12_HOURS)
|
||||
FactoryGirl.create :product, params.merge(:autostart_status => Product::ONCE_A_DAY)
|
||||
end
|
||||
|
||||
it 'should be created only one product_build_list' do
|
||||
lambda { Product.autostart_iso_builds(Product::ONCE_A_12_HOURS) }.should change{ ProductBuildList.count }.by(1)
|
||||
end
|
||||
|
||||
it 'product should has product_build_list' do
|
||||
Product.autostart_iso_builds Product::ONCE_A_12_HOURS
|
||||
product.product_build_lists.should have(1).item
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -835,3 +835,9 @@ a.badge:hover {
|
|||
.icon-chevron-down {
|
||||
background-position: -313px -119px;
|
||||
}
|
||||
.icon-share {
|
||||
background-position: -120px -72px;
|
||||
}
|
||||
.icon-remove-circle {
|
||||
background-position: -168px -96px;
|
||||
}
|
Loading…
Reference in New Issue