Improve build_lists time. Apply product build lists basic functionality. Move product build functionality to separate controller. Apply event logging for product build. Fix logging for project build list publishing. Code refactor and cleanup. Refs #2161

This commit is contained in:
Pavel Chipiga 2011-11-11 19:13:09 +02:00
parent 8449b5b826
commit 7996740ae7
24 changed files with 493 additions and 53 deletions

View File

@ -66,7 +66,7 @@ class BuildListsController < ApplicationController
@item.save @item.save
@build_list.container_path = params[:container_path] @build_list.container_path = params[:container_path]
@build_list.notified_at = Time.now @build_list.notified_at = Time.current
@build_list.save @build_list.save
@ -75,7 +75,7 @@ class BuildListsController < ApplicationController
def pre_build def pre_build
@build_list.status = BuildList::BUILD_STARTED @build_list.status = BuildList::BUILD_STARTED
@build_list.notified_at = Time.now @build_list.notified_at = Time.current
@build_list.save @build_list.save
@ -85,7 +85,7 @@ class BuildListsController < ApplicationController
def post_build def post_build
@build_list.status = params[:status] @build_list.status = params[:status]
@build_list.container_path = params[:container_path] @build_list.container_path = params[:container_path]
@build_list.notified_at = Time.now @build_list.notified_at = Time.current
@build_list.save @build_list.save
@ -95,7 +95,7 @@ class BuildListsController < ApplicationController
def circle_build def circle_build
@build_list.is_circle = true @build_list.is_circle = true
@build_list.container_path = params[:container_path] @build_list.container_path = params[:container_path]
@build_list.notified_at = Time.now @build_list.notified_at = Time.current
@build_list.save @build_list.save

View File

@ -0,0 +1,38 @@
class ProductBuildListsController < ApplicationController
before_filter :authenticate_user!, :except => [:status_build]
before_filter :find_product_build_list, :only => [:status_build]
before_filter :find_product, :except => [:status_build]
before_filter :find_platform, :except => [:status_build]
before_filter :check_global_access, :except => [:status_build]
# def index
# end
def create
can_perform? @product # if @product
@product.product_build_lists.create! :base_url => "http://#{request.host_with_port}", :notified_at => Time.current
flash[:notice] = t('flash.product.build_started')
redirect_to [@platform, @product]
end
def status_build
@product_build_list.status = params[:status].to_i # ProductBuildList::BUILD_COMPLETED : ProductBuildList::BUILD_FAILED)
@product_build_list.notified_at = Time.current
@product_build_list.save!
render :nothing => true
end
protected
def find_product_build_list
@product_build_list = ProductBuildList.find params[:id]
end
def find_product
@product = Product.find params[:product_id]
end
def find_platform
@platform = Platform.find params[:platform_id]
end
end

View File

@ -1,15 +1,8 @@
class ProductsController < ApplicationController class ProductsController < ApplicationController
before_filter :authenticate_user!, :except => [:product_status] before_filter :authenticate_user!
before_filter :find_product, :only => [:show, :edit, :update, :build, :product_status, :destroy] before_filter :find_product, :only => [:show, :edit, :update, :destroy]
before_filter :find_platform, :except => [:product_status, :build] before_filter :find_platform
before_filter :check_global_access, :only => [:new, :create]#:except => [:product_status] before_filter :check_global_access, :only => [:new, :create]
def product_status
@product.build_status = params[:status] == "0" ? Product::BUILD_COMPLETED : Product::BUILD_FAILED
@product.save!
render :nothing => true, :status => 200
end
def new def new
@product = @platform.products.new @product = @platform.products.new
@ -19,25 +12,14 @@ class ProductsController < ApplicationController
@product.build = DEFAULT_BUILD @product.build = DEFAULT_BUILD
end end
def clone # def clone
can_perform? @platform if @platform # can_perform? @platform if @platform
@template = @platform.products.find(params[:id]) # @template = @platform.products.find(params[:id])
@product = @platform.products.new # @product = @platform.products.new
@product.clone_from!(@template) # @product.clone_from!(@template)
#
render :template => "products/new" # render :template => "products/new"
end # end
def build
can_perform? @product if @product
result = ProductBuilder.create_product @product.id, @product.platform.unixname, @product.ks, @product.menu, @product.build, @product.counter, [], "http://#{request.host_with_port}#{@product.tar.url}"
if result == 0
flash[:notice] = t('flash.product.build_started')
else
flash[:notice] = "Код возврата #{result}"
end
redirect_to :action => :show
end
def edit def edit
can_perform? @product if @product can_perform? @product if @product
@ -83,10 +65,6 @@ class ProductsController < ApplicationController
protected protected
def find_product_by_name
@product = Product.find_by_name params[:product_name]
end
def find_product def find_product
@product = Product.find params[:id] @product = Product.find params[:id]
end end

View File

@ -0,0 +1,2 @@
module ProductBuildListsHelper
end

View File

@ -1,5 +1,5 @@
class EventLogObserver < ActiveRecord::Observer class EventLogObserver < ActiveRecord::Observer
observe :user, :private_user, :platform, :repository, :project, :product, :build_list, :auto_build_list observe :user, :private_user, :platform, :repository, :project, :product, :build_list, :auto_build_list, :product_build_list
def after_create(record) def after_create(record)
ActiveSupport::Notifications.instrument("event_log.observer", :object => record) ActiveSupport::Notifications.instrument("event_log.observer", :object => record)
@ -8,7 +8,7 @@ class EventLogObserver < ActiveRecord::Observer
def before_update(record) def before_update(record)
case record.class.to_s case record.class.to_s
when 'BuildList' when 'BuildList'
if record.status_changed? and record.status == BuildList::BUILD_CANCELED if record.status_changed? and [BuildList::BUILD_CANCELED, BuildList::BUILD_PUBLISHED].include?(record.status)
ActiveSupport::Notifications.instrument("event_log.observer", :object => record) ActiveSupport::Notifications.instrument("event_log.observer", :object => record)
end end
when 'Platform' when 'Platform'

View File

@ -1,15 +1,16 @@
class Product < ActiveRecord::Base class Product < ActiveRecord::Base
NEVER_BUILT = 2 # NEVER_BUILT = 2
BUILD_COMPLETED = 0 # BUILD_COMPLETED = 0
BUILD_FAILED = 1 # BUILD_FAILED = 1
ATTRS_TO_CLONE = [ 'build_path', 'build', 'build', 'counter', 'ks', 'menu', 'tar', 'use_cron', 'cron_tab' ] ATTRS_TO_CLONE = [ 'build_path', 'build', 'build', 'counter', 'ks', 'menu', 'tar', 'use_cron', 'cron_tab' ]
validates :name, :presence => true, :uniqueness => {:scope => :platform_id} validates :name, :presence => true, :uniqueness => {:scope => :platform_id}
validates :build_status, :inclusion => { :in => [ NEVER_BUILT, BUILD_COMPLETED, BUILD_FAILED ] } # validates :build_status, :inclusion => { :in => [ NEVER_BUILT, BUILD_COMPLETED, BUILD_FAILED ] }
# validates :platform_id, :presence => true # if you uncomment this platform clone will not work # validates :platform_id, :presence => true # if you uncomment this platform clone will not work
belongs_to :platform belongs_to :platform
has_many :product_build_lists, :dependent => :destroy
has_attached_file :tar has_attached_file :tar
validates_attachment_content_type :tar, :content_type => ["application/gnutar", "application/x-compressed", "application/x-gzip", "application/x-bzip2", "application/x-tar"], :message => I18n.t('layout.products.invalid_content_type') validates_attachment_content_type :tar, :content_type => ["application/gnutar", "application/x-compressed", "application/x-gzip", "application/x-bzip2", "application/x-tar"], :message => I18n.t('layout.products.invalid_content_type')

View File

@ -0,0 +1,37 @@
class ProductBuildList < ActiveRecord::Base
BUILD_STARTED = 2
BUILD_COMPLETED = 0
BUILD_FAILED = 1
belongs_to :product
validates :product, :status, :presence => true
validates :status, :inclusion => { :in => [BUILD_STARTED, BUILD_COMPLETED, BUILD_FAILED] }
scope :default_order, order('notified_at DESC')
attr_accessor :base_url
after_create :xml_rpc_create
def human_status
I18n.t("layout.product_build_lists.statuses.#{status}")
end
def event_log_message
{:product => Product.find(product_id).name}.inspect # TODO WTF product.name == nil ???
end
protected
def xml_rpc_create
tar_url = "#{base_url}#{product.tar.url}"
result = ProductBuilder.create_product id, product.platform.unixname, product.ks, product.menu, product.build, product.counter, [], tar_url
if result == ProductBuilder::SUCCESS
return true
else
# return false
raise "Failed to create product_build_list #{id} inside platform #{product.platform.unixname} tar url #{tar_url} with code #{result}."
end
end
end

View File

@ -0,0 +1,5 @@
%tr{:class => cycle("odd", "even")}
%td= product_build_list.id
%td= link_to product_build_list.product.name, [product_build_list.product.platform, product_build_list.product]
%td= product_build_list.human_status
%td= product_build_list.notified_at

View File

@ -0,0 +1,21 @@
%h1 Listing product_build_lists
%table
%tr
%th Product
%th Status
%th
%th
%th
- @product_build_lists.each do |product_build_list|
%tr
%td= product_build_list.product
%td= product_build_list.status
%td= link_to 'Show', product_build_list
%td= link_to 'Edit', edit_product_build_list_path(product_build_list)
%td= link_to 'Destroy', product_build_list, :confirm => 'Are you sure?', :method => :delete
%br
= link_to 'New Product build list', new_product_build_list_path

View File

@ -31,4 +31,16 @@
- if @product.can_clone? - if @product.can_clone?
= link_to t("layout.products.clone"), clone_platform_product_path(@platform, @product), :class => "button" = link_to t("layout.products.clone"), clone_platform_product_path(@platform, @product), :class => "button"
- if @product.can_build? - if @product.can_build?
= link_to t("layout.products.build"), build_platform_product_path(@platform, @product), :class => "button" = link_to t("layout.products.build"), platform_product_product_build_lists_path(@platform, @product), :class => "button", :method => 'post', :confirm => t("layout.confirm")
.block
.content
.inner
%table.table
%tr
%th.first= t("activerecord.attributes.product_build_list.id")
%th= t("activerecord.attributes.product_build_list.product")
%th= t("activerecord.attributes.product_build_list.status")
%th.last= t("activerecord.attributes.product_build_list.notified_at")
= render @product.product_build_lists.default_order
/ = will_paginate build_lists

View File

@ -7,6 +7,7 @@ ru:
projects_controller: 'Управление проектами' projects_controller: 'Управление проектами'
build_lists_controller: 'Управление сборочными листами' build_lists_controller: 'Управление сборочными листами'
auto_build_lists_controller: 'Управление автоматической сборкой' auto_build_lists_controller: 'Управление автоматической сборкой'
product_build_lists_controller: 'Управление сборкой продуктов'
'devise/registrations_controller': 'Регистрация пользователей' 'devise/registrations_controller': 'Регистрация пользователей'
'devise/sessions_controller': 'Аутентификация пользователей' 'devise/sessions_controller': 'Аутентификация пользователей'
'devise/passwords_controller': 'Восстановление пароля' 'devise/passwords_controller': 'Восстановление пароля'
@ -29,6 +30,8 @@ ru:
auto_build_lists_controller: auto_build_lists_controller:
create: 'назначена' create: 'назначена'
destroy: 'отменена' destroy: 'отменена'
product_build_lists_controller:
create: 'отправлен на сборку'
rpc_controller: rpc_controller:
xe_index: запрос xe_index: запрос
private_users_controller: private_users_controller:

View File

@ -258,6 +258,12 @@ ru:
branches: Branches branches: Branches
project_versions: Версии project_versions: Версии
product_build_lists:
statuses:
'0': 'собран'
'1': 'ошибка сборки'
'2': 'собирается'
build_lists: build_lists:
filter_header: Фильтр filter_header: Фильтр
current: Текущие current: Текущие
@ -400,6 +406,7 @@ ru:
user: Пользователь user: Пользователь
private_user: Приватный пользователь private_user: Приватный пользователь
product: Продукт product: Продукт
product_build_list: Сборочный лист продукта
build_list: Сборочный лист build_list: Сборочный лист
build_list_item: Элемент сборочного листа build_list_item: Элемент сборочного листа
download: Статистика download: Статистика
@ -533,6 +540,12 @@ ru:
updated_at: Обновлен updated_at: Обновлен
global_role: Роль в системе global_role: Роль в системе
product_build_list:
id: Id
product: Продукт
status: Статус
notified_at: Информация получена
build_list: build_list:
bs_id: Id bs_id: Id
name: Название name: Название

View File

@ -32,8 +32,7 @@ Rosa::Application.routes.draw do
match 'build_lists/' => 'build_lists#all', :as => :all_build_lists match 'build_lists/' => 'build_lists#all', :as => :all_build_lists
match 'build_lists/:id/cancel/' => 'build_lists#cancel', :as => :build_list_cancel match 'build_lists/:id/cancel/' => 'build_lists#cancel', :as => :build_list_cancel
resources :auto_build_lists, :only => [:index, :create, :destroy] do resources :auto_build_lists, :only => [:index, :create, :destroy]
end
resources :personal_repositories, :only => [:show] do resources :personal_repositories, :only => [:show] do
member do member do
@ -59,10 +58,11 @@ Rosa::Application.routes.draw do
end end
resources :products do resources :products do
member do # member do
get :clone # get :clone
get :build # get :build
end # end
resources :product_build_lists, :only => [:create]
end end
resources :repositories resources :repositories
@ -126,7 +126,7 @@ Rosa::Application.routes.draw do
match 'build_lists/circle_build', :to => "build_lists#circle_build" match 'build_lists/circle_build', :to => "build_lists#circle_build"
match 'build_lists/new_bbdt', :to => "build_lists#new_bbdt" match 'build_lists/new_bbdt', :to => "build_lists#new_bbdt"
match 'product_status', :to => 'products#product_status' match 'product_status', :to => 'product_build_lists#status_build'
# Tree # Tree
match '/projects/:project_id/git/tree/:treeish(/*path)', :controller => "git/trees", :action => :show, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :tree match '/projects/:project_id/git/tree/:treeish(/*path)', :controller => "git/trees", :action => :show, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :tree

View File

@ -0,0 +1,16 @@
class CreateProductBuildLists < ActiveRecord::Migration
def self.up
create_table :product_build_lists do |t|
t.references :product
t.integer :status, :null => false, :default => ProductBuildList::BUILD_STARTED
t.datetime :notified_at
t.timestamps
end
add_index :product_build_lists, :product_id
end
def self.down
drop_table :product_build_lists
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 => 20111029150934) do ActiveRecord::Schema.define(:version => 20111107211538) 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
@ -171,6 +171,16 @@ ActiveRecord::Schema.define(:version => 20111029150934) do
t.integer "user_id" t.integer "user_id"
end end
create_table "product_build_lists", :force => true do |t|
t.integer "product_id"
t.integer "status", :default => 2, :null => false
t.datetime "notified_at"
t.datetime "created_at"
t.datetime "updated_at"
end
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

View File

@ -0,0 +1,157 @@
require 'spec_helper'
# This spec was generated by rspec-rails when you ran the scaffold generator.
# It demonstrates how one might use RSpec to specify the controller code that
# was generated by Rails when you ran the scaffold generator.
#
# It assumes that the implementation code is generated by the rails scaffold
# generator. If you are using any extension libraries to generate different
# controller code, this generated spec may or may not pass.
#
# It only uses APIs available in rails and/or rspec-rails. There are a number
# of tools you can use to make these specs even more expressive, but we're
# sticking to rails and rspec-rails APIs to keep things simple and stable.
#
# Compared to earlier versions of this generator, there is very limited use of
# stubs and message expectations in this spec. Stubs are only used when there
# is no simpler way to get a handle on the object needed for the example.
# Message expectations are only used when there is no simpler way to specify
# that an instance is receiving a specific message.
describe ProductBuildListsController do
# This should return the minimal set of attributes required to create a valid
# ProductBuildList. As you add validations to ProductBuildList, be sure to
# update the return value of this method accordingly.
def valid_attributes
{}
end
describe "GET index" do
it "assigns all product_build_lists as @product_build_lists" do
product_build_list = ProductBuildList.create! valid_attributes
get :index
assigns(:product_build_lists).should eq([product_build_list])
end
end
describe "GET show" do
it "assigns the requested product_build_list as @product_build_list" do
product_build_list = ProductBuildList.create! valid_attributes
get :show, :id => product_build_list.id
assigns(:product_build_list).should eq(product_build_list)
end
end
describe "GET new" do
it "assigns a new product_build_list as @product_build_list" do
get :new
assigns(:product_build_list).should be_a_new(ProductBuildList)
end
end
describe "GET edit" do
it "assigns the requested product_build_list as @product_build_list" do
product_build_list = ProductBuildList.create! valid_attributes
get :edit, :id => product_build_list.id
assigns(:product_build_list).should eq(product_build_list)
end
end
describe "POST create" do
describe "with valid params" do
it "creates a new ProductBuildList" do
expect {
post :create, :product_build_list => valid_attributes
}.to change(ProductBuildList, :count).by(1)
end
it "assigns a newly created product_build_list as @product_build_list" do
post :create, :product_build_list => valid_attributes
assigns(:product_build_list).should be_a(ProductBuildList)
assigns(:product_build_list).should be_persisted
end
it "redirects to the created product_build_list" do
post :create, :product_build_list => valid_attributes
response.should redirect_to(ProductBuildList.last)
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved product_build_list as @product_build_list" do
# Trigger the behavior that occurs when invalid params are submitted
ProductBuildList.any_instance.stub(:save).and_return(false)
post :create, :product_build_list => {}
assigns(:product_build_list).should be_a_new(ProductBuildList)
end
it "re-renders the 'new' template" do
# Trigger the behavior that occurs when invalid params are submitted
ProductBuildList.any_instance.stub(:save).and_return(false)
post :create, :product_build_list => {}
response.should render_template("new")
end
end
end
describe "PUT update" do
describe "with valid params" do
it "updates the requested product_build_list" do
product_build_list = ProductBuildList.create! valid_attributes
# Assuming there are no other product_build_lists in the database, this
# specifies that the ProductBuildList created on the previous line
# receives the :update_attributes message with whatever params are
# submitted in the request.
ProductBuildList.any_instance.should_receive(:update_attributes).with({'these' => 'params'})
put :update, :id => product_build_list.id, :product_build_list => {'these' => 'params'}
end
it "assigns the requested product_build_list as @product_build_list" do
product_build_list = ProductBuildList.create! valid_attributes
put :update, :id => product_build_list.id, :product_build_list => valid_attributes
assigns(:product_build_list).should eq(product_build_list)
end
it "redirects to the product_build_list" do
product_build_list = ProductBuildList.create! valid_attributes
put :update, :id => product_build_list.id, :product_build_list => valid_attributes
response.should redirect_to(product_build_list)
end
end
describe "with invalid params" do
it "assigns the product_build_list as @product_build_list" do
product_build_list = ProductBuildList.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
ProductBuildList.any_instance.stub(:save).and_return(false)
put :update, :id => product_build_list.id, :product_build_list => {}
assigns(:product_build_list).should eq(product_build_list)
end
it "re-renders the 'edit' template" do
product_build_list = ProductBuildList.create! valid_attributes
# Trigger the behavior that occurs when invalid params are submitted
ProductBuildList.any_instance.stub(:save).and_return(false)
put :update, :id => product_build_list.id, :product_build_list => {}
response.should render_template("edit")
end
end
end
describe "DELETE destroy" do
it "destroys the requested product_build_list" do
product_build_list = ProductBuildList.create! valid_attributes
expect {
delete :destroy, :id => product_build_list.id
}.to change(ProductBuildList, :count).by(-1)
end
it "redirects to the product_build_lists list" do
product_build_list = ProductBuildList.create! valid_attributes
delete :destroy, :id => product_build_list.id
response.should redirect_to(product_build_lists_url)
end
end
end

View File

@ -0,0 +1,15 @@
require 'spec_helper'
# Specs in this file have access to a helper object that includes
# the ProductBuildListsHelper. For example:
#
# describe ProductBuildListsHelper do
# describe "string concat" do
# it "concats two strings with spaces" do
# helper.concat_strings("this","that").should == "this that"
# end
# end
# end
describe ProductBuildListsHelper do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -0,0 +1,5 @@
require 'spec_helper'
describe ProductBuildList do
pending "add some examples to (or delete) #{__FILE__}"
end

View File

@ -0,0 +1,35 @@
require "spec_helper"
describe ProductBuildListsController do
describe "routing" do
it "routes to #index" do
get("/product_build_lists").should route_to("product_build_lists#index")
end
it "routes to #new" do
get("/product_build_lists/new").should route_to("product_build_lists#new")
end
it "routes to #show" do
get("/product_build_lists/1").should route_to("product_build_lists#show", :id => "1")
end
it "routes to #edit" do
get("/product_build_lists/1/edit").should route_to("product_build_lists#edit", :id => "1")
end
it "routes to #create" do
post("/product_build_lists").should route_to("product_build_lists#create")
end
it "routes to #update" do
put("/product_build_lists/1").should route_to("product_build_lists#update", :id => "1")
end
it "routes to #destroy" do
delete("/product_build_lists/1").should route_to("product_build_lists#destroy", :id => "1")
end
end
end

View File

@ -0,0 +1,20 @@
require 'spec_helper'
describe "product_build_lists/edit.html.haml" do
before(:each) do
@product_build_list = assign(:product_build_list, stub_model(ProductBuildList,
:product => nil,
:status => "MyString"
))
end
it "renders the edit product_build_list form" do
render
# Run the generator again with the --webrat flag if you want to use webrat matchers
assert_select "form", :action => product_build_lists_path(@product_build_list), :method => "post" do
assert_select "input#product_build_list_product", :name => "product_build_list[product]"
assert_select "input#product_build_list_status", :name => "product_build_list[status]"
end
end
end

View File

@ -0,0 +1,24 @@
require 'spec_helper'
describe "product_build_lists/index.html.haml" do
before(:each) do
assign(:product_build_lists, [
stub_model(ProductBuildList,
:product => nil,
:status => "Status"
),
stub_model(ProductBuildList,
:product => nil,
:status => "Status"
)
])
end
it "renders a list of product_build_lists" do
render
# Run the generator again with the --webrat flag if you want to use webrat matchers
assert_select "tr>td", :text => nil.to_s, :count => 2
# Run the generator again with the --webrat flag if you want to use webrat matchers
assert_select "tr>td", :text => "Status".to_s, :count => 2
end
end

View File

@ -0,0 +1,20 @@
require 'spec_helper'
describe "product_build_lists/new.html.haml" do
before(:each) do
assign(:product_build_list, stub_model(ProductBuildList,
:product => nil,
:status => "MyString"
).as_new_record)
end
it "renders new product_build_list form" do
render
# Run the generator again with the --webrat flag if you want to use webrat matchers
assert_select "form", :action => product_build_lists_path, :method => "post" do
assert_select "input#product_build_list_product", :name => "product_build_list[product]"
assert_select "input#product_build_list_status", :name => "product_build_list[status]"
end
end
end

View File

@ -0,0 +1,18 @@
require 'spec_helper'
describe "product_build_lists/show.html.haml" do
before(:each) do
@product_build_list = assign(:product_build_list, stub_model(ProductBuildList,
:product => nil,
:status => "Status"
))
end
it "renders attributes in <p>" do
render
# Run the generator again with the --webrat flag if you want to use webrat matchers
rendered.should match(//)
# Run the generator again with the --webrat flag if you want to use webrat matchers
rendered.should match(/Status/)
end
end

View File

@ -0,0 +1,10 @@
require 'test_helper'
class ProductBuildListTest < ActionDispatch::IntegrationTest
fixtures :all
# Replace this with your real tests.
test "the truth" do
assert true
end
end