Merge branch 'master' into 30-social-login-and-open-registration

This commit is contained in:
Vokhmin Alexey V 2013-04-04 15:51:13 +04:00
commit df56f518b3
75 changed files with 798 additions and 300 deletions

View File

@ -0,0 +1,47 @@
$(document).ready(function() {
jQuery(window).bind('hashchange', function(e) {
var hash = location.hash;
if (/^#(diff|discussion)-F[0-9]+(L|R)[0-9]+/.test(hash)) {
highlightDiff(hash);
} else if (/^#L[0-9]+/.test(hash)) {
highlightShow(hash);
}
});
// Since the event is only triggered when the hash changes, we need to trigger
// the event now, to handle the hash the page may have loaded with.
jQuery(window).trigger('hashchange');
});
function highlightShow(id) {
$('.highlight-line').remove();
var from = to = id.substring(2);
if (/[0-9]+\-L[0-9]+$/.test(from)) {
var index = to.indexOf('-');
to = to.substring(index + 2);
from = from.substring(0, index);
}
from = parseInt(from);
to = parseInt(to);
if (from && to) {
if (from > to) {
var x = to; to = from; from = x;
}
var el = $('#L' + from);
$(document).scrollTop( el.offset().top );
while (el.length > 0) {
el.append('<div class="highlight-line"></div>');
if (from == to) { return true; }
from += 1;
el = $('#L' + from);
}
}
}
function highlightDiff(id) {
$('.highlight-line').removeClass('highlight-line');
$(id).parent().find('td.code').addClass('highlight-line');
}

View File

@ -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);
});
});
});

View File

@ -115,60 +115,48 @@ $(document).ready(function() {
return false; return false;
}; };
$('#search_user').live('submit', function() { var isSearchUser = null;
var id = $(this).attr('id'); $('#search_user').on('keyup', function() {
if(id.indexOf('user') != -1) { // FIXME if (isSearchUser != null) { isSearchUser.abort(); }
var which = 'users'; isSearchUser = $.ajax({
}
else if (id.indexOf('labels') != -1) {
var which = 'labels';
}
$.ajax({
type: 'GET', type: 'GET',
url: $(this).attr("action"), url: $('#search_user_path').attr('path'),
data: $(this).serialize(), data: $(this).serialize(),
success: function(data){ success: function(data){
$('#manage_issue_'+ which +'_list').html(data); $('#manage_issue_users_list').html(data);
}, }
error: function(data){
alert('error') // TODO remove
}
}); });
return false; return false;
}); });
function remAssignee(form) { $('#assigned-popup .header .icon-remove-circle').live('click', function() {
var el = form.find('.people.selected.remove_assignee'); $('#assigned-popup').hide();
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');
}); });
$('.remove_assignee.people.selected').live('click', function() { $('#assigned-container .icon-share').live('click', function() {
var form = $('form.issue, form.edit_form issue'); $('#assigned-popup').show();
form.find('#people-span').fadeIn(0);
remAssignee(form);
}); });
function remLabel(form, id) { $('#assigned-popup .people.selected').live('click', function() {
var el = form.find('.label.remove_label'+'#'+id); var form = $('#assigned-popup .edit_assignee');
var label = $('#'+id+'.remove_label.label.selected'); var item = $(this);
label.find('.flag').fadeIn(0); if (form.length == 0) {
label.find('.labeltext.selected').removeClass('selected').attr('style', ''); updateAssignedUser(item);
label.fadeIn('slow'); return false;
el.fadeOut('slow').remove(); }
} $.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() { $('.add_label.label').live('click', function() {
$(this).addClass('selected').removeClass('add_label').addClass('remove_label'); $(this).addClass('selected').removeClass('add_label').addClass('remove_label');
@ -251,12 +239,6 @@ $(document).ready(function() {
return false; 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.manage_labels').live('click', function() {
$('.button.update_labels').fadeIn(0); $('.button.update_labels').fadeIn(0);
$('.current_labels .label .labeltext.selected').parent().addClass('remove_label selected').removeClass('nopointer'); $('.current_labels .label .labeltext.selected').parent().addClass('remove_label selected').removeClass('nopointer');
@ -264,25 +246,6 @@ $(document).ready(function() {
$(this).fadeOut(0); $(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() { $('.button.update_labels').live('click', function() {
var form = $('form.edit_labels.issue'); var form = $('form.edit_labels.issue');
$.ajax({ $.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();
}

View File

@ -325,6 +325,18 @@ article div.file table {
background-color: #DDFFDD; background-color: #DDFFDD;
} }
#repo-wrapper table.diff tr td.code.highlight-line {
background-color: #FFFFCC;
}
.gutter .highlight-line {
background-color: #FF9900;
width: 805px;
height: 12px;
margin: -12px 0 0 50px;
opacity: 0.2;
position: absolute;
}
#repo-wrapper table.diff tr td.code.ins .idiff { #repo-wrapper table.diff tr td.code.ins .idiff {
background-color: #BAFBAD; background-color: #BAFBAD;
} }
@ -1895,4 +1907,103 @@ table#myTable thead tr.search th form.button_to div input {
text-align: center; text-align: center;
padding: 7px 5px 3px; padding: 7px 5px 3px;
} }
} }
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 {
z-index: 1001;
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;
}
}
}

View File

@ -762,7 +762,7 @@ article div.activity div.top div.text {
font-size: 12px; font-size: 12px;
} }
article div.activity div.top div.text span.name { article div.activity div.top span.name {
font-weight: 700; font-weight: 700;
} }

View File

@ -65,7 +65,7 @@ class Api::V1::BaseController < ApplicationController
def update_subject(subject) def update_subject(subject)
class_name = subject.class.name 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" render_json_response subject, "#{class_name} has been updated successfully"
else else
render_validation_error subject, "#{class_name} has not been updated" render_validation_error subject, "#{class_name} has not been updated"

View File

@ -33,6 +33,8 @@ class Api::V1::BuildListsController < Api::V1::BaseController
end end
def publish def publish
@build_list.publisher = current_user
@build_list.save
render_json :publish render_json :publish
end end

View File

@ -27,6 +27,11 @@ class Api::V1::ProductBuildListsController < Api::V1::BaseController
def show def show
end end
def update
params[:product_build_list] = {:not_delete => (params[:product_build_list] || {})[:not_delete]}
update_subject @product_build_list
end
def destroy def destroy
destroy_subject @product_build_list destroy_subject @product_build_list
end end

View File

@ -1,6 +1,7 @@
#class MassBuildsController < ApplicationController #class MassBuildsController < ApplicationController
class Platforms::MassBuildsController < Platforms::BaseController class Platforms::MassBuildsController < Platforms::BaseController
before_filter :authenticate_user! before_filter :authenticate_user!
skip_before_filter :authenticate_user!, :only => [:index, :get_list] if APP_CONFIG['anonymous_access']
load_and_authorize_resource :platform load_and_authorize_resource :platform
load_and_authorize_resource load_and_authorize_resource
@ -29,16 +30,14 @@ class Platforms::MassBuildsController < Platforms::BaseController
def publish def publish
if params[:status] == 'test_failed' if params[:status] == 'test_failed'
@mass_build.publish_test_faild_builds @mass_build.publish_test_faild_builds current_user
else else
@mass_build.publish_success_builds @mass_build.publish_success_builds current_user
end end
redirect_to(platform_mass_builds_path(@mass_build.platform), :notice => t("flash.platform.publish_success")) redirect_to(platform_mass_builds_path(@mass_build.platform), :notice => t("flash.platform.publish_success"))
end end
def index def index
authorize! :local_admin_manage, @platform
@mass_builds = MassBuild.by_platform(@platform).order('created_at DESC').paginate(:page => params[:page], :per_page => 20) @mass_builds = MassBuild.by_platform(@platform).order('created_at DESC').paginate(:page => params[:page], :per_page => 20)
@auto_publish_selected = true @auto_publish_selected = true
end end

View File

@ -6,7 +6,7 @@ class Platforms::ProductBuildListsController < Platforms::BaseController
load_and_authorize_resource :platform, :except => :index load_and_authorize_resource :platform, :except => :index
load_and_authorize_resource :product, :through => :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 :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 def new
product = @product_build_list.product product = @product_build_list.product
@ -23,6 +23,16 @@ class Platforms::ProductBuildListsController < Platforms::BaseController
def show def show
end 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 def cancel
if @product_build_list.cancel if @product_build_list.cancel
notice = t('layout.build_lists.will_be_canceled') notice = t('layout.build_lists.will_be_canceled')

View File

@ -1,5 +1,6 @@
# -*- encoding : utf-8 -*- # -*- encoding : utf-8 -*-
class Platforms::ProductsController < Platforms::BaseController class Platforms::ProductsController < Platforms::BaseController
include GitHelper
before_filter :authenticate_user! before_filter :authenticate_user!
skip_before_filter :authenticate_user!, :only => [:index, :show] if APP_CONFIG['anonymous_access'] 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 search(params[:term]).search_order
items.select! {|e| e.repo.branches.count > 0} items.select! {|e| e.repo.branches.count > 0}
render :json => items.map{ |p| 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 end

View File

@ -5,6 +5,13 @@ class Projects::BaseController < ApplicationController
protected 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 def find_project
@project = Project.find_by_owner_and_name!(params[:owner_name], params[:project_name]) if params[:owner_name] && params[:project_name] @project = Project.find_by_owner_and_name!(params[:owner_name], params[:project_name]) if params[:owner_name] && params[:project_name]
end end

View File

@ -173,6 +173,7 @@ class Projects::BuildListsController < Projects::BaseController
end end
@build_list.publisher = current_user
if @build_list.save && @build_list.can_publish? && @build_list.now_publish if @build_list.save && @build_list.can_publish? && @build_list.now_publish
redirect_to :back, :notice => t('layout.build_lists.publish_success') redirect_to :back, :notice => t('layout.build_lists.publish_success')
else else

View File

@ -6,6 +6,7 @@ class Projects::IssuesController < Projects::BaseController
load_resource :project load_resource :project
load_and_authorize_resource :issue, :through => :project, :find_by => :serial_id, :only => [:show, :edit, :update, :destroy, :new, :create, :index] 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 :load_and_authorize_label, :only => NON_RESTFUL_ACTION
before_filter :find_collaborators, :only => [:new, :create, :show, :search_collaborators]
layout false, :only => [:update, :search_collaborators] layout false, :only => [:update, :search_collaborators]
@ -91,10 +92,6 @@ class Projects::IssuesController < Projects::BaseController
end end
def search_collaborators 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' render :partial => 'search_collaborators'
end end

View File

@ -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_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] 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 def new
to_project = find_destination_project(false) to_project = find_destination_project(false)
@ -37,6 +38,7 @@ class Projects::PullRequestsController < Projects::BaseController
authorize! :read, to_project authorize! :read, to_project
@pull = to_project.pull_requests.new pull_params @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.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_owner_uname = @pull.from_project.owner.uname
@pull.from_project_name = @pull.from_project.name @pull.from_project_name = @pull.from_project.name
@ -90,6 +92,7 @@ class Projects::PullRequestsController < Projects::BaseController
def index(status = 200) def index(status = 200)
@issues_with_pull_request = @project.issues.joins(:pull_request) @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')}/ @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 @opened_issues, @closed_issues = @issues_with_pull_request.not_closed_or_merged.count, @issues_with_pull_request.closed_or_merged.count

View File

@ -52,6 +52,7 @@ module DiffHelper
def prepare(args) def prepare(args)
@url, @diff_counter, @in_discussion = args[:url], args[:diff_counter], args[:in_discussion] @url, @diff_counter, @in_discussion = args[:url], args[:diff_counter], args[:in_discussion]
@filepath, @line_comments = args[:filepath], args[:comments] @filepath, @line_comments = args[:filepath], args[:comments]
@diff_prefix = args[:diff_prefix] || 'diff'
@add_reply_id, @num_line = if @in_discussion @add_reply_id, @num_line = if @in_discussion
[@line_comments[0].id, @line_comments[0].data[:line].to_i - @line_comments[0].data[:strings].lines.count.to_i-1] [@line_comments[0].id, @line_comments[0].data[:line].to_i - @line_comments[0].data[:strings].lines.count.to_i-1]
else else
@ -74,7 +75,7 @@ module DiffHelper
set_line_number set_line_number
"<tr class='changes'> "<tr class='changes'>
<td class='line_numbers'></td> <td class='line_numbers'></td>
#{td_line_link "diff-F#{@diff_counter}R#{line.new_number}", line.new_number} #{td_line_link "#{@diff_prefix}-F#{@diff_counter}R#{line.new_number}", line.new_number}
<td class='code ins'> <td class='code ins'>
#{line_comment} #{line_comment}
<pre>#{render_line(line)}</pre> <pre>#{render_line(line)}</pre>
@ -86,7 +87,7 @@ module DiffHelper
def remline(line) def remline(line)
set_line_number set_line_number
"<tr class='changes'> "<tr class='changes'>
#{td_line_link "diff-F#{@diff_counter}L#{line.old_number}", line.old_number} #{td_line_link "#{@diff_prefix}-F#{@diff_counter}L#{line.old_number}", line.old_number}
<td class='line_numbers'></td> <td class='line_numbers'></td>
<td class='code del'> <td class='code del'>
#{line_comment} #{line_comment}
@ -99,8 +100,8 @@ module DiffHelper
def modline(line) def modline(line)
set_line_number set_line_number
"<tr clas='chanes line'> "<tr clas='chanes line'>
#{td_line_link "diff-F#{@diff_counter}L#{line.old_number}", line.old_number} #{td_line_link "#{@diff_prefix}-F#{@diff_counter}L#{line.old_number}", line.old_number}
#{td_line_link "diff-F#{@diff_counter}R#{line.new_number}", line.new_number} #{td_line_link "#{@diff_prefix}-F#{@diff_counter}R#{line.new_number}", line.new_number}
<td class='code unchanged modline'> <td class='code unchanged modline'>
#{line_comment} #{line_comment}
<pre>#{render_line(line)}</pre> <pre>#{render_line(line)}</pre>
@ -112,8 +113,8 @@ module DiffHelper
def unmodline(line) def unmodline(line)
set_line_number set_line_number
"<tr class='changes unmodline'> "<tr class='changes unmodline'>
#{td_line_link "diff-F#{@diff_counter}L#{line.old_number}", line.old_number} #{td_line_link "#{@diff_prefix}-F#{@diff_counter}L#{line.old_number}", line.old_number}
#{td_line_link "diff-F#{@diff_counter}R#{line.new_number}", line.new_number} #{td_line_link "#{@diff_prefix}-F#{@diff_counter}R#{line.new_number}", line.new_number}
<td class='code unchanged unmodline'> <td class='code unchanged unmodline'>
#{line_comment} #{line_comment}
<pre>#{render_line(line)}</pre> <pre>#{render_line(line)}</pre>
@ -133,8 +134,8 @@ module DiffHelper
def nonewlineline(line) def nonewlineline(line)
set_line_number set_line_number
"<tr class='changes'> "<tr class='changes'>
#{td_line_link "diff-F#{@diff_counter}L#{line.old_number}", line.old_number} #{td_line_link "#{@diff_prefix}-F#{@diff_counter}L#{line.old_number}", line.old_number}
#{td_line_link "diff-F#{@diff_counter}R#{line.new_number}", line.new_number} #{td_line_link "#{@diff_prefix}-F#{@diff_counter}R#{line.new_number}", line.new_number}
<td class='code modline unmodline'> <td class='code modline unmodline'>
#{line_comment} #{line_comment}
<pre>#{render_line(line)}</pre> <pre>#{render_line(line)}</pre>

View File

@ -68,6 +68,7 @@ module GitHelper
end end
def versions_for_group_select(project) def versions_for_group_select(project)
return [] unless project
[ ['Branches', project.repo.branches.map(&:name)], [ ['Branches', project.repo.branches.map(&:name)],
['Tags', project.repo.tags.map(&:name)] ] ['Tags', project.repo.tags.map(&:name)] ]
end end

View File

@ -62,7 +62,7 @@ class UserMailer < ActionMailer::Base
mail( mail(
:to => email_with_name(user, user.email), :to => email_with_name(user, user.email),
:subject => subject, :subject => subject,
:from => email_with_name(build_list.user) :from => email_with_name(build_list.publisher || build_list.user)
) do |format| ) do |format|
format.html format.html
end end

View File

@ -26,6 +26,7 @@ class Ability
# Platforms block # Platforms block
can [:show, :members, :advisories], Platform, :visibility => 'open' can [:show, :members, :advisories], Platform, :visibility => 'open'
can :platforms_for_build, Platform, :visibility => 'open', :platform_type => 'main' can :platforms_for_build, Platform, :visibility => 'open', :platform_type => 'main'
can(:get_list, MassBuild) {|mass_build| mass_build.platform.main? && can?(:show, mass_build.platform) }
can [:read, :projects_list, :projects], Repository, :platform => {:visibility => 'open'} can [:read, :projects_list, :projects], Repository, :platform => {:visibility => 'open'}
can :read, Product, :platform => {:visibility => 'open'} can :read, Product, :platform => {:visibility => 'open'}
@ -98,7 +99,7 @@ class Ability
can([:update, :destroy], Platform) {|platform| owner?(platform) } can([:update, :destroy], Platform) {|platform| owner?(platform) }
can([:local_admin_manage, :members, :add_member, :remove_member, :remove_members] , Platform) {|platform| owner?(platform) || local_admin?(platform) } can([:local_admin_manage, :members, :add_member, :remove_member, :remove_members] , Platform) {|platform| owner?(platform) || local_admin?(platform) }
can([:get_list, :create, :publish], MassBuild) {|mass_build| (owner?(mass_build.platform) || local_admin?(mass_build.platform)) && mass_build.platform.main?} can([:create, :publish], 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(: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} can [:read, :projects_list, :projects], Repository, :platform => {:owner_type => 'User', :owner_id => user.id}
@ -117,7 +118,7 @@ class Ability
can(:read, Product, read_relations_for('products', 'platforms')) {|product| product.platform.main?} 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, :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(:destroy, ProductBuildList) {|pbl| can?(:destroy, pbl.product)}
can [:read, :create], PrivateUser, :platform => {:owner_type => 'User', :owner_id => user.id} can [:read, :create], PrivateUser, :platform => {:owner_type => 'User', :owner_id => user.id}

View File

@ -136,21 +136,32 @@ class ActivityFeedObserver < ActiveRecord::Observer
end end
when 'BuildList' when 'BuildList'
if [BuildList::BUILD_PUBLISHED, if ( record.status_changed? &&
[BuildList::BUILD_PUBLISHED,
BuildList::SUCCESS, BuildList::SUCCESS,
BuildList::BUILD_ERROR, BuildList::BUILD_ERROR,
BuildList::PROJECT_VERSION_NOT_FOUND, BuildList::PROJECT_VERSION_NOT_FOUND,
BuildList::FAILED_PUBLISH, BuildList::FAILED_PUBLISH,
BuildList::TESTS_FAILED BuildList::TESTS_FAILED
].include? record.status or ].include?(record.status)
(record.status == BuildList::BUILD_PENDING && record.bs_id_changed?) ) or (record.status == BuildList::BUILD_PENDING && record.bs_id_changed?)
record.project.admins.each do |recipient| record.project.admins.each do |recipient|
user = record.publisher || record.user
ActivityFeed.create( ActivityFeed.create(
:user => recipient, :user => recipient,
:kind => 'build_list_notification', :kind => 'build_list_notification',
:data => {:task_num => record.bs_id, :build_list_id => record.id, :status => record.status, :updated_at => record.updated_at, :data => {
:project_id => record.project_id, :project_name => record.project.name, :project_owner => record.project.owner.uname, :task_num => record.bs_id,
:user_name => record.user.name, :user_email => record.user.email, :user_id => record.user_id} :build_list_id => record.id,
:status => record.status,
:updated_at => record.updated_at,
:project_id => record.project_id,
:project_name => record.project.name,
:project_owner => record.project.owner.uname,
:user_name => user.name,
:user_email => user.email,
:user_id => user.id
}
) )
end end
end end

View File

@ -10,6 +10,7 @@ class BuildList < ActiveRecord::Base
belongs_to :save_to_repository, :class_name => 'Repository' belongs_to :save_to_repository, :class_name => 'Repository'
belongs_to :build_for_platform, :class_name => 'Platform' belongs_to :build_for_platform, :class_name => 'Platform'
belongs_to :user belongs_to :user
belongs_to :publisher, :class_name => 'User'
belongs_to :advisory belongs_to :advisory
belongs_to :mass_build, :counter_cache => true belongs_to :mass_build, :counter_cache => true
has_many :items, :class_name => "BuildList::Item", :dependent => :destroy has_many :items, :class_name => "BuildList::Item", :dependent => :destroy
@ -156,6 +157,7 @@ class BuildList < ActiveRecord::Base
after_transition :on => :published, after_transition :on => :published,
:do => [:set_version_and_tag, :actualize_packages] :do => [:set_version_and_tag, :actualize_packages]
after_transition :on => :publish, :do => :set_publisher
after_transition :on => :cancel, :do => :cancel_job after_transition :on => :cancel, :do => :cancel_job
after_transition :on => [:published, :fail_publish, :build_error, :tests_failed], :do => :notify_users after_transition :on => [:published, :fail_publish, :build_error, :tests_failed], :do => :notify_users
@ -476,6 +478,11 @@ class BuildList < ActiveRecord::Base
self.use_save_to_repository = true if save_to_platform.main? self.use_save_to_repository = true if save_to_platform.main?
end end
def set_publisher
self.publisher ||= user
save
end
def current_ability def current_ability
@current_ability ||= Ability.new(user) @current_ability ||= Ability.new(user)
end end

View File

@ -55,9 +55,16 @@ class MassBuild < ActiveRecord::Base
def generate_failed_builds_list def generate_failed_builds_list
report = "" report = ""
BuildList.where(:status => BuildList::BUILD_ERROR, :mass_build_id => self.id).each do |build_list| BuildList.select('build_lists.id, projects.name as project_name, arches.name as arch_name').
report << "ID: #{build_list.id}; " where(
report << "PROJECT_NAME: #{build_list.project.name}\n" :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 end
report report
end end
@ -70,20 +77,22 @@ class MassBuild < ActiveRecord::Base
end end
later :cancel_all, :queue => :clone_build later :cancel_all, :queue => :clone_build
def publish_success_builds def publish_success_builds(user)
publish BuildList::SUCCESS, BuildList::FAILED_PUBLISH publish user, BuildList::SUCCESS, BuildList::FAILED_PUBLISH
end end
later :publish_success_builds, :queue => :clone_build later :publish_success_builds, :queue => :clone_build
def publish_test_faild_builds def publish_test_faild_builds(user)
publish BuildList::TESTS_FAILED publish user, BuildList::TESTS_FAILED
end end
later :publish_test_faild_builds, :queue => :clone_build later :publish_test_faild_builds, :queue => :clone_build
private private
def publish(*statuses) def publish(user, *statuses)
build_lists.where(:status => statuses).order(:id).find_in_batches(:batch_size => 50) do |bls| builds = build_lists.where(:status => statuses)
builds.update_all(:publisher_id => user.id)
builds.order(:id).find_in_batches(:batch_size => 50) do |bls|
bls.each{ |bl| bl.can_publish? && bl.now_publish } bls.each{ |bl| bl.can_publish? && bl.now_publish }
end end
end end

View File

@ -182,6 +182,9 @@ class Platform < ActiveRecord::Base
end end
later :destroy, :queue => :clone_build 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 protected
@ -189,9 +192,6 @@ class Platform < ActiveRecord::Base
system("mkdir -p -m 0777 #{build_path([name, 'repository'])}") system("mkdir -p -m 0777 #{build_path([name, 'repository'])}")
end 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) def build_path(dir)
File.join(APP_CONFIG['root_path'], 'platforms', dir) File.join(APP_CONFIG['root_path'], 'platforms', dir)

View File

@ -6,9 +6,22 @@ class Product < ActiveRecord::Base
belongs_to :project belongs_to :project
has_many :product_build_lists, :dependent => :destroy 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 :name, :presence => true, :uniqueness => {:scope => :platform_id}
validates :project_id, :presence => true validates :project_id, :presence => true
validates :main_script, :params, :length => { :maximum => 255 } 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") scope :recent, order("#{table_name}.name ASC")
@ -17,7 +30,9 @@ class Product < ActiveRecord::Base
:project_id, :project_id,
:main_script, :main_script,
:params, :params,
:platform_id :platform_id,
:autostart_status,
:project_version
attr_readonly :platform_id attr_readonly :platform_id
def full_clone(attrs = {}) def full_clone(attrs = {})
@ -30,4 +45,35 @@ class Product < ActiveRecord::Base
end end
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 end

View File

@ -6,6 +6,9 @@ class ProductBuildList < ActiveRecord::Base
include AbfWorker::ModelHelper include AbfWorker::ModelHelper
delegate :url_helpers, to: 'Rails.application.routes' 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_COMPLETED = 0
BUILD_FAILED = 1 BUILD_FAILED = 1
BUILD_PENDING = 2 BUILD_PENDING = 2
@ -35,7 +38,9 @@ class ProductBuildList < ActiveRecord::Base
belongs_to :user belongs_to :user
# see: Issue #6 # 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, validates :product_id,
:status, :status,
:project_id, :project_id,
@ -53,7 +58,8 @@ class ProductBuildList < ActiveRecord::Base
:params, :params,
:project_version, :project_version,
:commit_hash, :commit_hash,
:product_id :product_id,
:not_delete
attr_readonly :product_id attr_readonly :product_id
serialize :results, Array serialize :results, Array
@ -63,6 +69,8 @@ class ProductBuildList < ActiveRecord::Base
scope :for_user, lambda { |user| where(:user_id => user.id) } 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 :scoped_to_product_name, lambda {|product_name| joins(:product).where('products.name LIKE ?', "%#{product_name}%")}
scope :recent, order("#{table_name}.updated_at DESC") 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 after_create :add_job_to_abf_worker_queue
before_destroy :can_destroy? before_destroy :can_destroy?

View File

@ -40,7 +40,13 @@ json.build_list do |json|
:json => json_build_for_platform :json => json_build_for_platform
end end
json.partial! 'api/v1/shared/owner', :owner => @build_list.project.owner json.user do |json_user|
json.partial! 'api/v1/shared/member', :member => @build_list.user, :tag => json_user
end
json.publisher do |json_publisher|
json.partial! 'api/v1/shared/member', :member => @build_list.publisher, :tag => json_publisher
end if @build_list.publisher
inc_repos = Repository.includes(:platform).where(:id => @build_list.include_repos) inc_repos = Repository.includes(:platform).where(:id => @build_list.include_repos)
json.include_repos inc_repos do |json_include_repos, repo| json.include_repos inc_repos do |json_include_repos, repo|

View File

@ -1,6 +1,6 @@
json.product_build_list do |json| json.product_build_list do |json|
json.partial! 'product_build_list', :product_build_list => @product_build_list, :json => 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.product do |json_product|
json.partial! 'api/v1/products/product', json.partial! 'api/v1/products/product',

View File

@ -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) json.url api_v1_product_path(product, :format => :json)

View File

@ -13,7 +13,7 @@
- if can? :show, @platform - if can? :show, @platform
%li{:class => (act == :index && contr == :maintainers) ? 'active' : nil} %li{:class => (act == :index && contr == :maintainers) ? 'active' : nil}
= link_to t("layout.platforms.maintainers"), platform_maintainers_path(@platform) = link_to t("layout.platforms.maintainers"), platform_maintainers_path(@platform)
- if can? :edit, @platform - if can? :show, @platform
%li{:class => (contr == :mass_builds && [:index, :create].include?(act)) ? 'active' : ''} %li{:class => (contr == :mass_builds && [:index, :create].include?(act)) ? 'active' : ''}
= link_to t("layout.platforms.mass_build"), platform_mass_builds_path(@platform) = link_to t("layout.platforms.mass_build"), platform_mass_builds_path(@platform)
- if can? :read, @platform.products.build - if can? :read, @platform.products.build

View File

@ -0,0 +1,17 @@
= form_for :build, :url => platform_mass_builds_path(@platform), :html => { :class => 'form mass_build', :method => :post } do |f|
%section.left
=render 'repos_or_list_choice'
%br
= f.submit t("layout.projects.build_button")
%section.right
%h3= t("activerecord.attributes.build_list.arch")
- Arch.recent.each do |arch|
.lefter
= check_box_tag "arches[]", arch.id, (params[:arches]||[]).include?(arch.id.to_s), :id => "arches_#{arch.id}"
= label_tag "arches_#{arch.id}", arch.name
.both
%h3= t("activerecord.attributes.build_list.preferences")
.both.bottom_20
= check_box_tag :auto_publish, true, @auto_publish_selected, :id => 'auto_publish'
= label_tag :auto_publish, t('activerecord.attributes.build_list.auto_publish')
.both

View File

@ -1,24 +1,7 @@
= render 'platforms/base/submenu' = render 'platforms/base/submenu'
= render 'platforms/base/sidebar' = render 'platforms/base/sidebar'
= form_for :build, :url => platform_mass_builds_path(@platform), :html => { :class => 'form mass_build', :method => :post } do |f| = render 'form' if can? :edit, @platform
%section.left
=render 'repos_or_list_choice'
%br
= f.submit t("layout.projects.build_button")
%section.right
%h3= t("activerecord.attributes.build_list.arch")
- Arch.recent.each do |arch|
.lefter
= check_box_tag "arches[]", arch.id, (params[:arches]||[]).include?(arch.id.to_s), :id => "arches_#{arch.id}"
= label_tag "arches_#{arch.id}", arch.name
.both
%h3= t("activerecord.attributes.build_list.preferences")
.both.bottom_20
= check_box_tag :auto_publish, true, @auto_publish_selected, :id => 'auto_publish'
= label_tag :auto_publish, t('activerecord.attributes.build_list.auto_publish')
%br
%br
%table.tablesorter.unbordered{:cellpadding => "0", :cellspacing => "0"} %table.tablesorter.unbordered{:cellpadding => "0", :cellspacing => "0"}
%thead %thead

View File

@ -9,7 +9,7 @@
.both .both
.leftlist= f.label :project_version, t("activerecord.attributes.product_build_list.project_version"), :class => :label .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 .both
= render 'platforms/products/def_fields', :f => f = render 'platforms/products/def_fields', :f => f

View File

@ -24,12 +24,35 @@
= render 'show_field', :key => :time_living, :value => (pbl.time_living / 60) = 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) = render 'show_field', :key => :notified_at, :value => l(pbl.updated_at, :format => :long)
- if pbl.can_cancel? && can?(:cancel, pbl) - 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), = 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' :method => :put, :confirm => t("layout.confirm"), :class => 'button'
.both .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? - 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) } = render 'shared/log', { :build_started => true, :get_log_path => log_platform_product_product_build_list_path(pbl.product.platform, pbl.product, pbl) }

View File

@ -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' .rightlist= f.text_field :name, :class => 'text_field'
.both .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 .rightlist= f.text_area :description, :class => 'text_field resizable', :cols => 80
.both .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) .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 .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 = 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 .button_block
= submit_tag t("layout.save") = submit_tag t("layout.save")
%span.text_button_padding= t("layout.or") %span.text_button_padding= t("layout.or")

View File

@ -25,6 +25,10 @@
.rightlist .rightlist
= link_to @build_list.user.try(:fullname), @build_list.user = link_to @build_list.user.try(:fullname), @build_list.user
.both .both
.leftlist= t("activerecord.attributes.build_list.publisher")
.rightlist
= link_to @build_list.publisher.try(:fullname), @build_list.publisher if @build_list.publisher
.both
.leftlist= t("activerecord.attributes.build_list.build_for_platform") .leftlist= t("activerecord.attributes.build_list.build_for_platform")
.rightlist .rightlist
- bfp = @build_list.build_for_platform - bfp = @build_list.build_for_platform

View File

@ -10,6 +10,5 @@
:javascript :javascript
$(document).ready(function() { $(document).ready(function() {
var text = $('#code').text().replace(/&amp;/gi, '&'); CodeMirror.runMode($('#code').text().replace(/&amp;/gi, '&'), "#{@blob.raw_mime_type.content_type}", document.getElementById("output"));
CodeMirror.runMode(text, "#{@blob.raw_mime_type.content_type}", document.getElementById("output")); });
});

View File

@ -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'

View File

@ -1,8 +1,7 @@
=render 'title_body', :f => f, :id => 'new' =render 'title_body', :f => f, :id => 'new'
.leftlist= t('activerecord.attributes.issue.assignee') + ':' .leftlist= t('activerecord.attributes.issue.assignee') + ':'
.rightlist #assigned-container.rightlist
%span#people-span.small-text= t('layout.issues.choose_user_on_left') =render 'user_container', :user => @issue.assignee
#issue_assignee
.both .both
.leftlist= t('layout.issues.labels') + ':' .leftlist= t('layout.issues.labels') + ':'
.rightlist .rightlist

View File

@ -1,13 +1,18 @@
%h3.issue_title=@issue.title
.activity .activity
.top .top
.image .image
=image_tag(avatar_url(@issue.user, :medium), :alt => 'avatar') if @issue.user =image_tag(avatar_url(@issue.user, :medium), :alt => 'avatar') if @issue.user
.text .created
%span.name=link_to(@issue.user.fullname, user_path(@issue.user)) if @issue.user %span=@issue.created_at.to_s(:long)
%br/ - if @issue.user
%span.date=@issue.created_at.to_s(:long) %span= t('layout.by')
%br/ %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 .both
.fulltext.view.issue_body.formatted.cm-s-default.md_and_cm=markdown @issue.body .fulltext.view.issue_body.formatted.cm-s-default.md_and_cm=markdown @issue.body
.both .both

View File

@ -1,8 +1,7 @@
-content_for :sidebar do -content_for :sidebar do
- if current_user - if current_user
=form_tag project_issues_path(@project), :id => 'filter_issues', :method => :get do =form_tag project_issues_path(@project), :id => 'filter_issues', :method => :get do
.bordered.nopadding .bordered
%h3=t("layout.issues.accessory")
%table %table
%tr %tr
%td.width18=radio_button_tag :myradio, 'all', !@is_assigned_to_me, {:id => 'myradio1', :class => 'niceRadio', :name => 'filter'} %td.width18=radio_button_tag :myradio, 'all', !@is_assigned_to_me, {:id => 'myradio1', :class => 'niceRadio', :name => 'filter'}

View File

@ -9,32 +9,6 @@
- if can_manage - if can_manage
=form_tag [@project, @issue], :id => 'update_issue_status', :method => :put do =form_tag [@project, @issue], :id => 'update_issue_status', :method => :put do
=hidden_field_tag "issue_status", @issue.closed? ? 'closed' : 'open', :name => "issue[status]" =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 .block
%h3=t('layout.issues.labels') %h3=t('layout.issues.labels')
- if can_manage - if can_manage

View File

@ -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'} .people.selected{:id => "user-#{index}", :class => 'add_assignee'}
.avatar= image_tag(avatar_url(user), :alt => 'avatar') .avatar= image_tag(avatar_url(user), :alt => 'avatar')
.name=user.fullname .name= user.fullname
=hidden_field_tag "user-#{index}", user.id, :name => 'issue[assignee_id]' .container
.image
= image_tag(avatar_url(user, :micro), :alt => 'avatar')
%span.name= link_to(user.fullname, user_path(user))
%span= t('layout.issues.is_assigned')
= hidden_field_tag "user-#{index}", user.id, :name => "issue[assignee_id]"
.both .both
- if users.empty?
.nothing= t('layout.issues.nothing_to_show')

View File

@ -0,0 +1,10 @@
.user-container
- if user
.image
=image_tag(avatar_url(user, :micro), :alt => 'avatar')
%span.name= link_to(user.fullname, 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

View File

@ -3,8 +3,8 @@
-render 'manage_sidebar' -render 'manage_sidebar'
%h3.bpadding10= t("layout.issues.create_header") %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 = render "form", :f => f
=hidden_field_tag :preview_url, project_md_preview_path(@project) =hidden_field_tag :preview_url, project_md_preview_path(@project)
= render "projects/comments/markdown_help" = render "projects/comments/markdown_help"

View File

@ -1,5 +1,6 @@
.hr .hr
-commits_queue = [] - commits_queue = []
- diff_counter = 0
-merge_activity(@comments, @commits).each do |item| # -merge_activity(@comments, @commits).each do |item| #
-if item.is_a? Comment -if item.is_a? Comment
=render 'projects/git/commits/commits_small', :commits => commits_queue if commits_queue.present? =render 'projects/git/commits/commits_small', :commits => commits_queue if commits_queue.present?
@ -16,8 +17,9 @@
=t '.show_outdated_diff' =t '.show_outdated_diff'
%span.data-expander.collapsed{:id => exp_id} &nbsp; %span.data-expander.collapsed{:id => exp_id} &nbsp;
.hidden{:id => "content-#{exp_id}"} .hidden{:id => "content-#{exp_id}"}
=render 'projects/pull_requests/discussion_comments', :item => item, :add_id => nil =render 'projects/pull_requests/discussion_comments', :item => item, :diff_counter => diff_counter
-else -else
=render 'projects/pull_requests/discussion_comments', :item => item, :add_id => nil =render 'projects/pull_requests/discussion_comments', :item => item, :diff_counter => diff_counter
- diff_counter += 1
=render 'projects/git/commits/commits_small', :commits => commits_queue if commits_queue.present? =render 'projects/git/commits/commits_small', :commits => commits_queue if commits_queue.present?

View File

@ -11,5 +11,5 @@
=t'projects.pull_requests.outdated_diff' =t'projects.pull_requests.outdated_diff'
=image_tag 'x.png' =image_tag 'x.png'
.clear .clear
.diff_data=render_diff(comment.inline_diff, :diff_counter => 0, :comments => item[1], :filepath => comment.data[:path]) .diff_data=render_diff(comment.inline_diff, :diff_counter => diff_counter, :comments => item[1], :filepath => comment.data[:path], :diff_prefix => 'discussion')

View File

@ -1,4 +1,16 @@
-content_for :sidebar do -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 =form_tag project_pull_requests_path(@project), :id => 'filter_pull_requests', :method => :get, :class => 'ajax_search_form' do
.bordered.bpadding20 .bordered.bpadding20
- search = params[:search_pull_request].present? ? params[:search_pull_request] : t('layout.pull_requests.search') - search = params[:search_pull_request].present? ? params[:search_pull_request] : t('layout.pull_requests.search')

View File

@ -7,6 +7,7 @@
.tab-content.pull_diff_fix .tab-content.pull_diff_fix
#discussion.tab-pane.active #discussion.tab-pane.active
=hidden_field_tag :update_action, new_project_pull_request_path =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| =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 .leftlist=f.label :from_project, t("#{ar}.from_project"), :class => :label
@ -31,6 +32,11 @@
%div{:class => @pull.ready? ? 'notice' : 'alert'} %div{:class => @pull.ready? ? 'notice' : 'alert'}
=pull_status @pull =pull_status @pull
.both .both
.leftlist.big-list= t('activerecord.attributes.issue.assignee') + ':'
#assigned-container.rightlist
=render 'projects/issues/user_container', :user => @pull.assignee
.both
.leftlist.big-list .leftlist.big-list
.rightlist .rightlist
=f.submit t('.submit'), :class => 'btn btn-primary disabled', 'data-loading-text' => t('layout.processing'), :id => 'create_pull' unless @pull.already? =f.submit t('.submit'), :class => 'btn btn-primary disabled', 'data-loading-text' => t('layout.processing'), :id => 'create_pull' unless @pull.already?

View File

@ -29,6 +29,7 @@ en:
auto_publish: Automated publising auto_publish: Automated publising
project_version: Version project_version: Version
user: User user: User
publisher: Publisher
preferences: Preferences preferences: Preferences
started_at: Build started at started_at: Build started at
duration: Build duration in seconds duration: Build duration in seconds

View File

@ -29,6 +29,7 @@ ru:
auto_publish: Автоматическая публикация auto_publish: Автоматическая публикация
project_version: Версия project_version: Версия
user: Пользователь user: Пользователь
publisher: Публикатор
preferences: Настройки preferences: Настройки
duration: Длительность билда в секундах duration: Длительность билда в секундах
mass_build_id: Массовая сборка mass_build_id: Массовая сборка

View File

@ -11,9 +11,13 @@ en:
layout: layout:
issues: 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 list: List
all: All all: All issues
to_me: Assigned to me to_me: Assigned to me
edit: Edit edit: Edit
search: Find issue... search: Find issue...

View File

@ -11,9 +11,13 @@ ru:
layout: layout:
issues: issues:
accessory: Принадлежность заданий is_assigned: назначен
clear_assignee: Убрать назначение
nothing_to_show: Никто не найден
no_one_is_assigned: Никто не назначен
assign_someone: Назначить кого-либо на задачу
list: Список list: Список
all: Все all: Все задачи
to_me: Назначенные мне to_me: Назначенные мне
edit: Редактировать edit: Редактировать
search: Найти задачу... search: Найти задачу...

View File

@ -11,6 +11,10 @@ en:
new_header: New product new_header: New product
edit_header: Product editing edit_header: Product editing
confirm_delete: Are you sure you want to delete this product? 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: flash:
product: product:
@ -25,8 +29,10 @@ en:
product: Product product: Product
attributes: attributes:
product: product:
autostart_status: Autostart
name: Name name: Name
description: Description description: Description
project_version: Version
platform_id: Platform platform_id: Platform
build_status: Build status build_status: Build status
created_at: Created created_at: Created

View File

@ -11,6 +11,10 @@ ru:
new_header: Новый продукт new_header: Новый продукт
edit_header: Редактирование продукта edit_header: Редактирование продукта
confirm_delete: Вы уверены, что хотите удалить этот продукт? confirm_delete: Вы уверены, что хотите удалить этот продукт?
autostart_statuses:
once_a_12_hours: Раз в 12 часов
once_a_day: Раз в день
once_a_week: Раз в неделю
flash: flash:
product: product:
@ -25,8 +29,10 @@ ru:
product: Продукт product: Продукт
attributes: attributes:
product: product:
autostart_status: Автостарт
name: Название name: Название
description: Описание description: Описание
project_version: Версия
platform_id: Платформа platform_id: Платформа
build_status: Статус последней сборки build_status: Статус последней сборки
created_at: Создан created_at: Создан

View File

@ -1,6 +1,8 @@
en: en:
layout: layout:
product_build_lists: 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) logs: Logs (last 100 lines)
work_env: Work environment work_env: Work environment
iso_builder_folder: folder with contents of the GIT project iso_builder_folder: folder with contents of the GIT project
@ -29,6 +31,8 @@ en:
activerecord: activerecord:
attributes: attributes:
product_build_list: product_build_list:
autostarted: Autostart
not_delete: Not delete
id: Id id: Id
user: User user: User
product: Product product: Product
@ -52,4 +56,6 @@ en:
product_build_list: product_build_list:
no_project: Project for build should be exist no_project: Project for build should be exist
delete: Product build list deleted delete: Product build list deleted
delete_error: Unable to delete product build list delete_error: Unable to delete product build list
updated: Product build list updated
update_error: Unable to update product build list

View File

@ -1,6 +1,8 @@
ru: ru:
layout: layout:
product_build_lists: product_build_lists:
will_be_removed_n_days: Cборочный лист продукта будет удален через %{n} д.
will_be_removed_today: Cборочный лист продукта будет удален в течение дня
logs: Логи (последнии 100 строк) logs: Логи (последнии 100 строк)
work_env: Рабочее пространство work_env: Рабочее пространство
iso_builder_folder: папка с содержимым GIT проекта iso_builder_folder: папка с содержимым GIT проекта
@ -29,6 +31,8 @@ ru:
activerecord: activerecord:
attributes: attributes:
product_build_list: product_build_list:
autostarted: Автоматически запущен
not_delete: Не удалять
id: Id id: Id
user: Пользователь user: Пользователь
product: Продукт product: Продукт
@ -52,4 +56,6 @@ ru:
product_build_list: product_build_list:
no_project: Проект для сборки должен присутствовать no_project: Проект для сборки должен присутствовать
delete: Сборочный лист продукта удален delete: Сборочный лист продукта удален
delete_error: Не удалось удалить cборочный лист продукта delete_error: Не удалось удалить cборочный лист продукта
updated: Cборочный лист продукта успешно обновлен
update_error: Не удалось обновить cборочный лист продукта

View File

@ -56,4 +56,6 @@ en:
layout: layout:
pull_requests: pull_requests:
search: Find pull request... search: Find pull request...
all: All requests
to_me: Assigned to me
view_full_changes: View full changes view_full_changes: View full changes

View File

@ -57,4 +57,6 @@ ru:
layout: layout:
pull_requests: pull_requests:
search: Найти пул реквест... search: Найти пул реквест...
all: Все пул реквесты
to_me: Назначенные мне
view_full_changes: Посмотреть все изменения view_full_changes: Посмотреть все изменения

View File

@ -78,7 +78,7 @@ Rosa::Application.routes.draw do
resources :products, :only => [:show, :update, :create, :destroy] do resources :products, :only => [:show, :update, :create, :destroy] do
resources :product_build_lists, :only => :index resources :product_build_lists, :only => :index
end 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 put :cancel, :on => :member
end end
#resources :ssh_keys, :only => [:index, :create, :destroy] #resources :ssh_keys, :only => [:index, :create, :destroy]
@ -137,7 +137,7 @@ Rosa::Application.routes.draw do
get :members get :members
post :remove_members # fixme: change post to delete post :remove_members # fixme: change post to delete
delete :remove_member delete :remove_member
put :add_member post :add_member
post :make_clone post :make_clone
get :advisories get :advisories
end end
@ -163,7 +163,7 @@ Rosa::Application.routes.draw do
end end
resources :key_pairs, :only => [:create, :index, :destroy] resources :key_pairs, :only => [:create, :index, :destroy]
resources :products do 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 { member {
get :log get :log
put :cancel put :cancel

View File

@ -7,22 +7,40 @@
# runner "Download.parse_and_remove_nginx_log" # runner "Download.parse_and_remove_nginx_log"
#end #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' rake "import:sync:all", :output => 'log/sync.log'
end 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' rake "buildlist:clear:outdated", :output => 'log/build_list_clear.log'
end 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' rake "pull_requests:clear", :output => 'log/pull_requests_clear.log'
end 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' rake "activity_feeds:clear", :output => 'log/activity_feeds.log'
end end
every 3.minute do every 3.minute do
runner 'AbfWorker::BuildListsPublishTaskManager.new.run', :output => 'log/task_manager.log' 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 end

View File

@ -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

View File

@ -0,0 +1,5 @@
class AddProjectVersionToProduct < ActiveRecord::Migration
def change
add_column :products, :project_version, :string
end
end

View File

@ -0,0 +1,5 @@
class AddPublishedUserToBuildList < ActiveRecord::Migration
def change
add_column :build_lists, :publisher_id, :integer
end
end

View File

@ -11,14 +11,14 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130227102900) do ActiveRecord::Schema.define(:version => 20130328112110) do
create_table "activity_feeds", :force => true do |t| create_table "activity_feeds", :force => true do |t|
t.integer "user_id", :null => false t.integer "user_id", :null => false
t.string "kind" t.string "kind"
t.text "data" t.text "data"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
end end
create_table "advisories", :force => true do |t| create_table "advisories", :force => true do |t|
@ -53,8 +53,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
create_table "arches", :force => true do |t| create_table "arches", :force => true do |t|
t.string "name", :null => false t.string "name", :null => false
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
end end
add_index "arches", ["name"], :name => "index_arches_on_name", :unique => true add_index "arches", ["name"], :name => "index_arches_on_name", :unique => true
@ -63,8 +63,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.integer "user_id" t.integer "user_id"
t.string "provider" t.string "provider"
t.string "uid" t.string "uid"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
end end
add_index "authentications", ["provider", "uid"], :name => "index_authentications_on_provider_and_uid", :unique => true add_index "authentications", ["provider", "uid"], :name => "index_authentications_on_provider_and_uid", :unique => true
@ -75,8 +75,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.integer "level" t.integer "level"
t.integer "status" t.integer "status"
t.integer "build_list_id" t.integer "build_list_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.string "version" t.string "version"
end end
@ -110,8 +110,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.integer "project_id" t.integer "project_id"
t.integer "arch_id" t.integer "arch_id"
t.datetime "notified_at" t.datetime "notified_at"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.boolean "is_circle", :default => false t.boolean "is_circle", :default => false
t.text "additional_repos" t.text "additional_repos"
t.string "name" t.string "name"
@ -137,6 +137,7 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.boolean "auto_create_container", :default => false t.boolean "auto_create_container", :default => false
t.text "extra_repositories" t.text "extra_repositories"
t.text "extra_build_lists" t.text "extra_build_lists"
t.integer "publisher_id"
end end
add_index "build_lists", ["advisory_id"], :name => "index_build_lists_on_advisory_id" add_index "build_lists", ["advisory_id"], :name => "index_build_lists_on_advisory_id"
@ -149,8 +150,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.string "commentable_type" t.string "commentable_type"
t.integer "user_id" t.integer "user_id"
t.text "body" t.text "body"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.decimal "commentable_id", :precision => 50, :scale => 0 t.decimal "commentable_id", :precision => 50, :scale => 0
t.integer "project_id" t.integer "project_id"
t.text "data" t.text "data"
@ -168,8 +169,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.string "controller" t.string "controller"
t.string "action" t.string "action"
t.text "message" t.text "message"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
end end
create_table "flash_notifies", :force => true do |t| create_table "flash_notifies", :force => true do |t|
@ -183,8 +184,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
create_table "groups", :force => true do |t| create_table "groups", :force => true do |t|
t.integer "owner_id" t.integer "owner_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.string "uname" t.string "uname"
t.integer "own_projects_count", :default => 0, :null => false t.integer "own_projects_count", :default => 0, :null => false
t.text "description" t.text "description"
@ -201,8 +202,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.string "title" t.string "title"
t.text "body" t.text "body"
t.string "status", :default => "open" t.string "status", :default => "open"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.integer "user_id" t.integer "user_id"
t.datetime "closed_at" t.datetime "closed_at"
t.integer "closed_by" t.integer "closed_by"
@ -279,14 +280,14 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.string "description" t.string "description"
t.string "name", :null => false t.string "name", :null => false
t.integer "parent_platform_id" t.integer "parent_platform_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.boolean "released", :default => false, :null => false t.boolean "released", :default => false, :null => false
t.integer "owner_id" t.integer "owner_id"
t.string "owner_type" t.string "owner_type"
t.string "visibility", :default => "open", :null => false t.string "visibility", :default => "open", :null => false
t.string "platform_type", :default => "main", :null => false t.string "platform_type", :default => "main", :null => false
t.string "distrib_type" t.string "distrib_type", :null => false
end end
add_index "platforms", ["name"], :name => "index_platforms_on_name", :unique => true, :case_sensitive => false add_index "platforms", ["name"], :name => "index_platforms_on_name", :unique => true, :case_sensitive => false
@ -295,16 +296,16 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.integer "platform_id" t.integer "platform_id"
t.string "login" t.string "login"
t.string "password" t.string "password"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.integer "user_id" t.integer "user_id"
end end
create_table "product_build_lists", :force => true do |t| create_table "product_build_lists", :force => true do |t|
t.integer "product_id" t.integer "product_id"
t.integer "status", :default => 3, :null => false t.integer "status", :default => 2, :null => false
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.integer "project_id" t.integer "project_id"
t.string "project_version" t.string "project_version"
t.string "commit_hash" t.string "commit_hash"
@ -314,20 +315,24 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.integer "arch_id" t.integer "arch_id"
t.integer "time_living" t.integer "time_living"
t.integer "user_id" t.integer "user_id"
t.boolean "not_delete", :default => false
t.boolean "autostarted", :default => false
end end
add_index "product_build_lists", ["product_id"], :name => "index_product_build_lists_on_product_id" add_index "product_build_lists", ["product_id"], :name => "index_product_build_lists_on_product_id"
create_table "products", :force => true do |t| create_table "products", :force => true do |t|
t.string "name", :null => false t.string "name", :null => false
t.integer "platform_id", :null => false t.integer "platform_id", :null => false
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.text "description" t.text "description"
t.integer "project_id" t.integer "project_id"
t.string "params" t.string "params"
t.string "main_script" t.string "main_script"
t.integer "time_living" t.integer "time_living"
t.integer "autostart_status"
t.string "project_version"
end end
create_table "project_imports", :force => true do |t| create_table "project_imports", :force => true do |t|
@ -335,8 +340,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.string "name" t.string "name"
t.string "version" t.string "version"
t.datetime "file_mtime" t.datetime "file_mtime"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.integer "platform_id" t.integer "platform_id"
end end
@ -355,27 +360,27 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
create_table "project_to_repositories", :force => true do |t| create_table "project_to_repositories", :force => true do |t|
t.integer "project_id" t.integer "project_id"
t.integer "repository_id" t.integer "repository_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
end end
add_index "project_to_repositories", ["repository_id", "project_id"], :name => "index_project_to_repositories_on_repository_id_and_project_id", :unique => true add_index "project_to_repositories", ["repository_id", "project_id"], :name => "index_project_to_repositories_on_repository_id_and_project_id", :unique => true
create_table "projects", :force => true do |t| create_table "projects", :force => true do |t|
t.string "name" t.string "name"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.integer "owner_id" t.integer "owner_id"
t.string "owner_type" t.string "owner_type"
t.string "visibility", :default => "open" t.string "visibility", :default => "open"
t.text "description" t.text "description"
t.string "ancestry" t.string "ancestry"
t.boolean "has_issues", :default => true t.boolean "has_issues", :default => true
t.boolean "has_wiki", :default => false
t.string "srpm_file_name" t.string "srpm_file_name"
t.string "srpm_content_type"
t.integer "srpm_file_size" t.integer "srpm_file_size"
t.datetime "srpm_updated_at" t.datetime "srpm_updated_at"
t.string "srpm_content_type"
t.boolean "has_wiki", :default => false
t.string "default_branch", :default => "master" t.string "default_branch", :default => "master"
t.boolean "is_package", :default => true, :null => false t.boolean "is_package", :default => true, :null => false
t.integer "average_build_time", :default => 0, :null => false t.integer "average_build_time", :default => 0, :null => false
@ -406,8 +411,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.string "token" t.string "token"
t.boolean "approved", :default => false t.boolean "approved", :default => false
t.boolean "rejected", :default => false t.boolean "rejected", :default => false
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.string "interest" t.string "interest"
t.text "more" t.text "more"
t.string "language" t.string "language"
@ -421,16 +426,16 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.string "actor_type" t.string "actor_type"
t.integer "target_id" t.integer "target_id"
t.string "target_type" t.string "target_type"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.string "role" t.string "role"
end end
create_table "repositories", :force => true do |t| create_table "repositories", :force => true do |t|
t.string "description", :null => false t.string "description", :null => false
t.integer "platform_id", :null => false t.integer "platform_id", :null => false
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.string "name", :null => false t.string "name", :null => false
t.boolean "publish_without_qa", :default => true t.boolean "publish_without_qa", :default => true
end end
@ -444,8 +449,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.boolean "new_comment_reply", :default => true t.boolean "new_comment_reply", :default => true
t.boolean "new_issue", :default => true t.boolean "new_issue", :default => true
t.boolean "issue_assign", :default => true t.boolean "issue_assign", :default => true
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.boolean "new_comment_commit_owner", :default => true t.boolean "new_comment_commit_owner", :default => true
t.boolean "new_comment_commit_repo_owner", :default => true t.boolean "new_comment_commit_repo_owner", :default => true
t.boolean "new_comment_commit_commentor", :default => true t.boolean "new_comment_commit_commentor", :default => true
@ -468,8 +473,8 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
create_table "subscribes", :force => true do |t| create_table "subscribes", :force => true do |t|
t.string "subscribeable_type" t.string "subscribeable_type"
t.integer "user_id" t.integer "user_id"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.boolean "status", :default => true t.boolean "status", :default => true
t.integer "project_id" t.integer "project_id"
t.decimal "subscribeable_id", :precision => 50, :scale => 0 t.decimal "subscribeable_id", :precision => 50, :scale => 0
@ -477,21 +482,18 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
create_table "users", :force => true do |t| create_table "users", :force => true do |t|
t.string "name" t.string "name"
t.string "email", :default => "", :null => false t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "reset_password_token" t.string "reset_password_token"
t.datetime "reset_password_sent_at" t.datetime "reset_password_sent_at"
t.datetime "remember_created_at" t.datetime "remember_created_at"
t.datetime "created_at", :null => false t.datetime "created_at"
t.datetime "updated_at", :null => false t.datetime "updated_at"
t.text "ssh_key" t.text "ssh_key"
t.string "uname" t.string "uname"
t.string "role" t.string "role"
t.string "language", :default => "en" t.string "language", :default => "en"
t.integer "own_projects_count", :default => 0, :null => false t.integer "own_projects_count", :default => 0, :null => false
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.text "professional_experience" t.text "professional_experience"
t.string "site" t.string "site"
t.string "company" t.string "company"
@ -500,11 +502,14 @@ ActiveRecord::Schema.define(:version => 20130227102900) do
t.string "avatar_content_type" t.string "avatar_content_type"
t.integer "avatar_file_size" t.integer "avatar_file_size"
t.datetime "avatar_updated_at" t.datetime "avatar_updated_at"
t.integer "failed_attempts", :default => 0 t.integer "failed_attempts", :default => 0
t.string "unlock_token" t.string "unlock_token"
t.datetime "locked_at" t.datetime "locked_at"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "authentication_token" t.string "authentication_token"
t.integer "build_priority", :default => 50 t.integer "build_priority", :default => 50
end end
add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token" add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token"

View File

@ -7,4 +7,7 @@ end
%w(rosa_system iso_worker_1 file_store).each do |uname| %w(rosa_system iso_worker_1 file_store).each do |uname|
user = User.new uname: uname, email: "#{uname}@rosalinux.ru", password: SecureRandom.base64 user = User.new uname: uname, email: "#{uname}@rosalinux.ru", password: SecureRandom.base64
user.confirmed_at, user.role = Time.now.utc, 'system'; user.save user.confirmed_at, user.role = Time.now.utc, 'system'; user.save
end end
admin = User.new uname: 'admin_user', email: 'admin_user@rosalinux.ru', password: 'admin_user'
admin.confirmed_at, admin.role = Time.now.utc, 'admin'; admin.save

View File

View File

@ -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

View File

@ -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, params = {:product_id => @product_build_list.product_id, :arch_id => Arch.last.id,
:commit_hash => commit_hash, :main_script => @product_build_list.main_script} :commit_hash => commit_hash, :main_script => @product_build_list.main_script}
@create_params = {:product_build_list =>{:time_living => 150}.merge(params)} @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 end
it 'should be able to perform show action' do 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) lambda { put :destroy, :id => @product_build_list.id, :format => :json }.should change{ ProductBuildList.count }.by(-1)
end end
it "should not be able to perform update action" do it "should be able to perform update action" do
put :update, :id => @product_build_list.id, :format => :json put :update, @update_params.merge(:id => @product_build_list.id), :format => :json
response.should_not be_success response.should be_success
end 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 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.reload.time_living.should == 150*60 # in seconds
@product_build_list.not_delete.should be_true
end end
it 'ensures that return correct answer for wrong creating action' do it 'ensures that return correct answer for wrong creating action' do

View File

@ -42,6 +42,11 @@ shared_examples_for 'mass_build platform owner' do
lambda { post :create, @create_params }.should change{ MassBuild.count }.by(1) lambda { post :create, @create_params }.should change{ MassBuild.count }.by(1)
end end
it 'should be able to perform get_list action' do
get :get_list, :platform_id => @platform, :id => @mass_build, :kind => 'failed_builds_list'
response.should be_success
end
context 'for personal platform' do context 'for personal platform' do
before(:each) do before(:each) do
Platform.update_all(:platform_type => 'personal') Platform.update_all(:platform_type => 'personal')
@ -57,14 +62,22 @@ shared_examples_for 'mass_build platform owner' do
end end
shared_examples_for 'mass_build platform reader' do shared_examples_for 'mass_build platform reader' do
[:index, :create].each do |action| it 'should be able to perform index action' do
it "should not be able to perform #{ action } action" do get :index, :platform_id => @platform
get action, :platform_id => @platform response.should render_template(:index)
response.should redirect_to(forbidden_path)
end
end end
[:cancel, :get_list, :publish].each do |action| it 'should be able to perform get_list action' do
get :get_list, :platform_id => @platform, :id => @mass_build, :kind => 'failed_builds_list'
response.should be_success
end
it "should not be able to perform create action" do
get :create, :platform_id => @platform
response.should redirect_to(forbidden_path)
end
[:cancel, :publish].each do |action|
it "should not be able to perform #{ action } action" do it "should not be able to perform #{ action } action" do
get action, :platform_id => @platform, :id => @mass_build.id get action, :platform_id => @platform, :id => @mass_build.id
response.should redirect_to(forbidden_path) response.should redirect_to(forbidden_path)
@ -111,15 +124,29 @@ describe Platforms::MassBuildsController do
end end
context 'for guest' do context 'for guest' do
[:index, :create].each do |action|
it "should not be able to perform #{ action } action" do it 'should be able to perform index action', :anonymous_access => true do
get action, :platform_id => @platform get :index, :platform_id => @platform
response.should redirect_to(new_user_session_path) response.should render_template(:index)
end
end end
it "should not be able to get failed builds list" do it 'should not be able to perform index action', :anonymous_access => false do
get :index, :platform_id => @platform
response.should redirect_to(new_user_session_path)
end
it 'should be able to perform get_list action', :anonymous_access => true do
get :get_list, :platform_id => @platform, :id => @mass_build, :kind => 'failed_builds_list' get :get_list, :platform_id => @platform, :id => @mass_build, :kind => 'failed_builds_list'
response.should be_success
end
it "should not be able to get failed builds list", :anonymous_access => false do
get :get_list, :platform_id => @platform, :id => @mass_build, :kind => 'failed_builds_list'
response.should redirect_to(new_user_session_path)
end
it "should not be able to perform create action" do
get :create, :platform_id => @platform
response.should redirect_to(new_user_session_path) response.should redirect_to(new_user_session_path)
end end

View File

@ -35,6 +35,18 @@ shared_examples_for 'product build list admin' do
response.should render_template(:show) response.should render_template(:show)
end 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 it 'should be able to perform log action' do
get :log, valid_attributes_for_show get :log, valid_attributes_for_show
response.should be_success response.should be_success

View File

@ -9,8 +9,5 @@ FactoryGirl.define do
params 'ENV=i586' params 'ENV=i586'
time_living 150 time_living 150
project_version 'master' project_version 'master'
# see: before_validation in ProductBuildList model
before(:create) { Arch.find_or_create_by_name('x86_64') }
end end
end end

View File

@ -5,5 +5,8 @@ FactoryGirl.define do
association :platform, :factory => :platform association :platform, :factory => :platform
association :project, :factory => :project_with_commit association :project, :factory => :project_with_commit
time_living 150 time_living 150
# see: before_validation in ProductBuildList model
before(:create) { Arch.find_or_create_by_name('x86_64') }
end end
end end

View File

@ -2,8 +2,10 @@
require 'spec_helper' require 'spec_helper'
describe ProductBuildList do describe ProductBuildList do
before(:all) do before do
stub_symlink_methods stub_symlink_methods
stub_redis
FactoryGirl.create(:product_build_list)
end end
it { should belong_to(:product) } it { should belong_to(:product) }
@ -29,9 +31,8 @@ describe ProductBuildList do
# see app/ability.rb # see app/ability.rb
# can :read, ProductBuildList#, :product => {:platform => {:visibility => 'open'}} # double nested hash don't work # can :read, ProductBuildList#, :product => {:platform => {:visibility => 'open'}} # double nested hash don't work
it 'should generate correct sql to get product build lists' do it 'should generate correct sql to get product build lists' do
stub_symlink_methods
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
ability = Ability.new user ability = Ability.new user
ProductBuildList.accessible_by(ability).count.should == 0 ProductBuildList.accessible_by(ability).count.should == 1
end end
end end

View File

@ -2,15 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Product do describe Product do
before(:all) do let!(:product) { FactoryGirl.create(:product) }
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
it { should belong_to(:platform) } it { should belong_to(:platform) }
it { should have_many(:product_build_lists)} 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(:platform_id) }
it { should_not allow_mass_assignment_of(:product_build_lists) } it { should_not allow_mass_assignment_of(:product_build_lists) }
after(:all) do
Platform.delete_all context '#autostart_iso_builds' do
User.delete_all
Product.delete_all Product::HUMAN_AUTOSTART_STATUSES.each do |autostart_status, human_autostart_status|
clear_test_root 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
end end

View File

@ -834,4 +834,10 @@ a.badge:hover {
} }
.icon-chevron-down { .icon-chevron-down {
background-position: -313px -119px; background-position: -313px -119px;
}
.icon-share {
background-position: -120px -72px;
}
.icon-remove-circle {
background-position: -168px -96px;
} }