build list creation

This commit is contained in:
Timothy N. Tsvetkov 2011-04-11 20:37:09 +04:00
parent 3895defa45
commit 1a6330956b
16 changed files with 235 additions and 14 deletions

View File

@ -50,5 +50,6 @@ gem "hoptoad_notifier", "~> 2.3"
gem "russian" gem "russian"
gem "grit" gem "grit"
gem 'unicorn' gem 'unicorn'
gem 'delayed_job'
gem 'jammit' gem 'jammit'

View File

@ -42,6 +42,10 @@ GEM
closure-compiler (1.1.1) closure-compiler (1.1.1)
compass (0.10.6) compass (0.10.6)
haml (>= 3.0.4) haml (>= 3.0.4)
daemons (1.1.0)
delayed_job (2.1.4)
activesupport (~> 3.0)
daemons
devise (1.1.7) devise (1.1.7)
bcrypt-ruby (~> 2.1.2) bcrypt-ruby (~> 2.1.2)
warden (~> 1.0.2) warden (~> 1.0.2)
@ -142,6 +146,7 @@ DEPENDENCIES
capistrano capistrano
capistrano-ext capistrano-ext
compass (>= 0.10.6) compass (>= 0.10.6)
delayed_job
devise devise
factory_girl_rails factory_girl_rails
grit grit

View File

@ -2,7 +2,7 @@ class ProjectsController < ApplicationController
before_filter :authenticate_user! before_filter :authenticate_user!
before_filter :find_platform before_filter :find_platform
before_filter :find_repository before_filter :find_repository
before_filter :find_project, :only => [:show, :destroy] before_filter :find_project, :only => [:show, :destroy, :build, :process_build]
def new def new
@project = @repository.projects.new @project = @repository.projects.new
@ -12,6 +12,37 @@ class ProjectsController < ApplicationController
@current_build_lists = @project.build_lists.current.recent.paginate :page => params[:page] @current_build_lists = @project.build_lists.current.recent.paginate :page => params[:page]
end end
def build
@branches = @project.git_repository.branches
@arches = Arch.recent
end
def process_build
@arch_ids = params[:build][:arches].select{|_,v| v == "1"}.collect{|x| x[0].to_i }
@arches = Arch.where(:id => @arch_ids)
@branches = @project.git_repository.branches
@branch = @branches.select{|branch| branch.name == params[:build][:branch] }.first
if !check_arches || !check_branches
@arches = Arch.recent
render :action => "build"
else
flash[:notice], flash[:error] = "", ""
@arches.each do |arch|
build_list = @project.build_lists.new(:arch => arch, :branch_name => @branch.name)
if build_list.save
flash[:notice] += t("flash.build_list.saved", :branch_name => @branch.name, :arch => arch.name)
else
flash[:error] += t("flash.build_list.save_error", :branch_name => @branch.name, :arch => arch.name)
end
end
redirect_to platform_repository_project_path(@platform, @repository, @project)
end
end
def create def create
@project = @repository.projects.new params[:project] @project = @repository.projects.new params[:project]
if @project.save if @project.save
@ -43,4 +74,28 @@ class ProjectsController < ApplicationController
def find_project def find_project
@project = @repository.projects.find params[:id] @project = @repository.projects.find params[:id]
end end
def check_arches
if @arch_ids.blank?
flash[:error] = t("flash.build_list.no_arch_selected")
false
elsif @arch_ids.length != @arches.length
flash[:error] = t("flash.build_list.no_arch_found")
false
else
true
end
end
def check_branches
if @branch.blank?
flash[:error] = t("flash.build_list.no_branch_selected")
false
elsif !@branches.include?(@branch)
flash[:error] = t("flash.build_list.no_branch_found")
false
else
true
end
end
end end

View File

@ -6,18 +6,36 @@ class BuildList < ActiveRecord::Base
validates :project_id, :presence => true validates :project_id, :presence => true
validates :branch_name, :presence => true validates :branch_name, :presence => true
BUILD_PENDING = 2 WAITING_FOR_RESPONSE = 4000
BUILD_STARTED = 3 BUILD_PENDING = 2000
BUILD_STARTED = 3000
STATUSES = [WAITING_FOR_RESPONSE,
BuildServer::SUCCESS,
BUILD_PENDING,
BUILD_STARTED,
BuildServer::BUILD_ERROR,
BuildServer::PLATFORM_NOT_FOUND,
BuildServer::PLATFORM_PENDING,
BuildServer::PROJECT_NOT_FOUND,
BuildServer::BRANCH_NOT_FOUND]
STATUSES = [BuildServer::SUCCESS, BUILD_PENDING, BUILD_STARTED, BuildServer::BUILD_ERROR]
HUMAN_STATUSES = { BuildServer::BUILD_ERROR => :build_error, HUMAN_STATUSES = { BuildServer::BUILD_ERROR => :build_error,
BUILD_PENDING => :build_pending, BUILD_PENDING => :build_pending,
BUILD_STARTED => :build_started, BUILD_STARTED => :build_started,
BuildServer::SUCCESS => :success BuildServer::SUCCESS => :success,
WAITING_FOR_RESPONSE => :waiting_for_response,
BuildServer::PLATFORM_NOT_FOUND => :platform_not_found,
BuildServer::PLATFORM_PENDING => :platform_pending,
BuildServer::PROJECT_NOT_FOUND => :project_not_found,
BuildServer::BRANCH_NOT_FOUND => :branch_not_found
} }
scope :recent, order("created_at DESC") scope :recent, order("created_at DESC")
scope :current, lambda { where(["status in (?) OR (status in (?) AND notified_at >= ?)", [BUILD_PENDING, BUILD_STARTED], [BuildServer::SUCCESS, BuildServer::ERROR], Time.now - 2.days]) } scope :current, lambda {
outdatable_statuses = [BuildServer::SUCCESS, BuildServer::ERROR, BuildServer::PLATFORM_NOT_FOUND, BuildServer::PLATFORM_PENDING, BuildServer::PROJECT_NOT_FOUND, BuildServer::BRANCH_NOT_FOUND]
where(["status in (?) OR (status in (?) AND notified_at >= ?)", [WAITING_FOR_RESPONSE, BUILD_PENDING, BUILD_STARTED], outdatable_statuses, Time.now - 2.days])
}
scope :for_status, lambda {|status| where(:status => status) } scope :for_status, lambda {|status| where(:status => status) }
scope :scoped_to_arch, lambda {|arch| where(:arch_id => arch) } scope :scoped_to_arch, lambda {|arch| where(:arch_id => arch) }
scope :scoped_to_branch, lambda {|branch| where(:branch_name => branch) } scope :scoped_to_branch, lambda {|branch| where(:branch_name => branch) }
@ -42,6 +60,9 @@ class BuildList < ActiveRecord::Base
} }
serialize :additional_repos serialize :additional_repos
before_create :set_default_status
after_create :place_build
def self.human_status(status) def self.human_status(status)
I18n.t("layout.build_lists.statuses.#{HUMAN_STATUSES[status]}") I18n.t("layout.build_lists.statuses.#{HUMAN_STATUSES[status]}")
@ -61,4 +82,16 @@ class BuildList < ActiveRecord::Base
end end
end end
private
def set_default_status
self.status = WAITING_FOR_RESPONSE unless self.status.present?
end
def place_build
self.status = BuildServer.add_build_list project.name, branch_name, project.platform.name, arch.name
self.status = BUILD_PENDING if self.status == 0
save
end
handle_asynchronously :place_build
end end

View File

@ -10,12 +10,12 @@
- build_lists.each do |build_list| - build_lists.each do |build_list|
%tr{:class => cycle("odd", "even")} %tr{:class => cycle("odd", "even")}
%td= link_to build_list.bs_id, platform_repository_project_build_list_path(@platform, @repository, @project, build_list) %td= link_to (build_list.bs_id.present? ? build_list.bs_id : t("layout.build_lists.bs_id_not_set")), platform_repository_project_build_list_path(@platform, @repository, @project, build_list)
%td= build_list.human_status %td= build_list.human_status
%td= link_to build_list.branch_name, "#" %td= link_to build_list.branch_name, "#"
%td= link_to build_list.project.name, platform_repository_project_path(@platform, @repository, @project) %td= link_to build_list.project.name, platform_repository_project_path(@platform, @repository, @project)
%td= build_list.arch.name %td= build_list.arch.name
%td= build_list.is_circle? %td= t("layout.#{build_list.is_circle?}_")
%td.last= build_list.notified_at %td.last= build_list.notified_at
= will_paginate build_lists = will_paginate build_lists

View File

@ -0,0 +1,14 @@
.block.notice
%h3= t("layout.platforms.current_platform_header")
.content
%p= link_to @platform.name, platform_path(@platform)
.block.notice
%h3= t("layout.repositories.current_repository_header")
.content
%p= link_to @repository.name + repository_name_postfix(@platform), platform_repository_path(@platform, @repository)
.block.notice
%h3= t("layout.projects.current_project_header")
.content
%p= link_to @project.name, platform_repository_path(@platform, @repository) + "#projects"

View File

@ -12,4 +12,4 @@
.inner .inner
= render :partial => "build_lists/build_lists", :object => @build_lists = render :partial => "build_lists/build_lists", :object => @build_lists
-#- content_for :sidebar, render(:partial => 'sidebar') - content_for :sidebar, render(:partial => 'sidebar')

View File

@ -3,6 +3,7 @@
%ul.wat-cf %ul.wat-cf
%li.first= link_to t("layout.build_lists.current"), platform_repository_project_path(@platform, @repository, @project) + "#build_lists" %li.first= link_to t("layout.build_lists.current"), platform_repository_project_path(@platform, @repository, @project) + "#build_lists"
%li= link_to t("layout.build_lists.all"), platform_repository_project_build_lists_path(@platform, @repository, @project) %li= link_to t("layout.build_lists.all"), platform_repository_project_build_lists_path(@platform, @repository, @project)
%li.active= link_to t("layout.build_lists.show"), platform_repository_project_build_list_path(@platform, @repository, @project, @build_list)
.content .content
.inner .inner
@ -50,7 +51,7 @@
%b %b
= t("activerecord.attributes.build_list.is_circle") = t("activerecord.attributes.build_list.is_circle")
\: \:
= @build_list.is_circle = t("layout.#{@build_list.is_circle?}_")
%p %p
%b %b
@ -60,7 +61,12 @@
.block .block
.content .content
%h2= t("layout.build_lists.items_header")
.inner .inner
- if @item_groups.blank?
= t("layout.build_lists.no_items_data")
- @item_groups.each_with_index do |group, level| - @item_groups.each_with_index do |group, level|
%h3.title Level ##{level} %h3.title Level ##{level}
%table.table %table.table
@ -73,4 +79,4 @@
%td= item.name %td= item.name
%td.last= item.human_status %td.last= item.human_status
-#- content_for :sidebar, render(:partial => 'sidebar') - content_for :sidebar, render(:partial => 'sidebar')

View File

@ -0,0 +1,37 @@
.block
.secondary-navigation
%ul.wat-cf
%li.first= link_to t("layout.projects.list"), platform_repository_path(@platform, @repository) + "#projects"
%li= link_to t("layout.projects.new"), new_platform_repository_project_path(@platform, @repository)
%li= link_to t("layout.projects.show"), platform_repository_project_path(@platform, @repository, @project)
%li= link_to "git-repo", platform_repository_project_repo_path(@platform, @repository, @project)
%li.active= link_to t("layout.projects.build"), build_platform_repository_project_path(@platform, @repository, @project)
.content
%h2.title= t("layout.projects.new_build")
.inner
= form_for :build, :url => process_build_platform_repository_project_path(@platform, @repository, @project), :html => { :class => :form, :method => :post } do |f|
.columns.wat-cf
.column.left
.group
= f.label :branch, "Branch", :class => :label
= f.select :branch, @branches.collect{|branch| [branch.name, branch.name]}
.column.right
.group
= f.label :arches, t("activerecord.attributes.build_list.arch"), :class => :label
- @arches.each do |arch|
= f.check_box "arches[#{arch.id}]"
= arch.name
%br
.group.navform.wat-cf
%button.button{:type => "submit"}
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.projects.build_button"))
= t("layout.projects.build_button")
%span.text_button_padding= t("layout.or")
= link_to t("layout.cancel"), platform_repository_path(@platform, @repository), :class => "text_button_padding link_button"
- content_for :sidebar, render(:partial => 'sidebar')

View File

@ -3,6 +3,9 @@
%ul.wat-cf %ul.wat-cf
%li.first= link_to t("layout.projects.list"), platform_repository_path(@platform, @repository) + "#projects" %li.first= link_to t("layout.projects.list"), platform_repository_path(@platform, @repository) + "#projects"
%li.active= link_to t("layout.projects.new"), new_platform_repository_project_path(@platform, @repository) %li.active= link_to t("layout.projects.new"), new_platform_repository_project_path(@platform, @repository)
%li= link_to "git-repo", platform_repository_project_repo_path(@platform, @repository, @project)
%li= link_to t("layout.projects.build"), build_platform_repository_project_path(@platform, @repository, @project)
.content .content
%h2.title= t("layout.projects.new_header") %h2.title= t("layout.projects.new_header")
.inner .inner

View File

@ -5,6 +5,7 @@
%li= link_to t("layout.projects.new"), new_platform_repository_project_path(@platform, @repository) %li= link_to t("layout.projects.new"), new_platform_repository_project_path(@platform, @repository)
%li.active= link_to t("layout.projects.show"), platform_repository_project_path(@platform, @repository, @project) %li.active= link_to t("layout.projects.show"), platform_repository_project_path(@platform, @repository, @project)
%li= link_to "git-repo", platform_repository_project_repo_path(@platform, @repository, @project) %li= link_to "git-repo", platform_repository_project_repo_path(@platform, @repository, @project)
%li= link_to t("layout.projects.build"), build_platform_repository_project_path(@platform, @repository, @project)
.content .content
.inner .inner

View File

@ -16,6 +16,8 @@ ru:
or: или or: или
yes_: Да yes_: Да
no_: Нет no_: Нет
true_: Да
false_: Нет
menu: menu:
users: Пользователи users: Пользователи
platforms: Платформы platforms: Платформы
@ -56,15 +58,17 @@ ru:
list: Список list: Список
list_header: Проекты list_header: Проекты
show: Проект show: Проект
build: Собрать
new_build: Новая сборка
confirm_delete: Вы уверены, что хотите удалить этот проект? confirm_delete: Вы уверены, что хотите удалить этот проект?
new: Новый проект new: Новый проект
new_header: Новый проект new_header: Новый проект
new_header: Новый проект new_header: Новый проект
location: Расположение location: Расположение
git_repo_location: Путь к git-репозиторию git_repo_location: Путь к git-репозиторию
back_to_the_list: К списку проектов репозитория
current_project_header: Текущий проект current_project_header: Текущий проект
current_build_lists: Текущие сборки current_build_lists: Текущие сборки
build_button: Начать сборку
users: users:
list: Список list: Список
new: Создать new: Создать
@ -90,6 +94,10 @@ ru:
created_at_end: "Время постановки на сборку по:" created_at_end: "Время постановки на сборку по:"
notified_at_start: "Время последнего обновления от BS с:" notified_at_start: "Время последнего обновления от BS с:"
notified_at_end: "Время последнего обновления от BS по:" notified_at_end: "Время последнего обновления от BS по:"
bs_id_not_set: Id еще не присвоен
items_header: Элементы сборки
no_items_data: Данных нет
show: Просмотр
items: items:
statuses: statuses:
build_error: ошибка сборки build_error: ошибка сборки
@ -102,9 +110,14 @@ ru:
mock_not_found: mock не найден mock_not_found: mock не найден
dependencies_fail: dependencies fail dependencies_fail: dependencies fail
srpm_not_found: srpm не найден srpm_not_found: srpm не найден
waiting_for_response: ожидает ответа
build_pending: ожидает сборку build_pending: ожидает сборку
success: собран success: собран
build_started: собирается build_started: собирается
platform_not_found: платформа не найдена
platform_pending: платформа в процессе создания
project_not_found: проект не найден
branch_not_found: бранч не найден
flash: flash:
project: project:
@ -127,7 +140,13 @@ ru:
unfreezed: Платформа успешно разморожена unfreezed: Платформа успешно разморожена
unfreeze_error: Не удалось разморозить платформу, попробуйте еще раз unfreeze_error: Не удалось разморозить платформу, попробуйте еще раз
destroyed: Платформа успешно удалена destroyed: Платформа успешно удалена
build_list:
saved: Билд лист для бранча '%{branch_name}' и архитектуры '%{arch}' создан успешно
save_error: Не удалось сохранить билд лист для бранча '%{branch_name}' и архитектуры '%{arch}'
no_branch_selected: Выберите какой-нибудь бранч
no_branch_found: Выбранный бранч '%{branch_name}' не найден
no_arch_selected: Выберите хотя бы одну ахритектуру
no_arch_found: Выбранные ахритектуры не найдены
attributes: attributes:
password: Пароль password: Пароль

View File

@ -18,6 +18,12 @@ Rosa::Application.routes.draw do
post :filter post :filter
end end
end end
member do
get :build
post :process_build
end
end end
end end
end end

View File

@ -0,0 +1,21 @@
class CreateDelayedJobs < ActiveRecord::Migration
def self.up
create_table :delayed_jobs, :force => true do |table|
table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
table.text :handler # YAML-encoded string of the object that will do work
table.text :last_error # reason for last failure (See Note below)
table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future.
table.datetime :locked_at # Set when a client is working on this object
table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
table.string :locked_by # Who is working on this object (if locked)
table.timestamps
end
add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
end
def self.down
drop_table :delayed_jobs
end
end

View File

@ -10,7 +10,7 @@
# #
# 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 => 20110411082826) do ActiveRecord::Schema.define(:version => 20110411160955) 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
@ -58,6 +58,21 @@ ActiveRecord::Schema.define(:version => 20110411082826) do
t.datetime "updated_at" t.datetime "updated_at"
end end
create_table "delayed_jobs", :force => true do |t|
t.integer "priority", :default => 0
t.integer "attempts", :default => 0
t.text "handler"
t.text "last_error"
t.datetime "run_at"
t.datetime "locked_at"
t.datetime "failed_at"
t.string "locked_by"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority"
create_table "platforms", :force => true do |t| create_table "platforms", :force => true do |t|
t.string "name" t.string "name"
t.string "unixname" t.string "unixname"

5
script/delayed_job Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env ruby
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
require 'delayed/command'
Delayed::Command.new(ARGV).daemonize