Merge branch 'master' into 242-restart_last_build_list

This commit is contained in:
Alexander Machehin 2013-08-01 01:32:50 +06:00
commit c2ee66cb67
20 changed files with 212 additions and 78 deletions

View File

@ -290,6 +290,18 @@ class BuildList < ActiveRecord::Base
BuildList.where(:id => extra_build_lists).where('status != ?', BUILD_PUBLISHED).count == 0 BuildList.where(:id => extra_build_lists).where('status != ?', BUILD_PUBLISHED).count == 0
end end
def human_average_build_time
I18n.t('layout.project_statistics.human_average_build_time', {:hours => (average_build_time/3600).to_i, :minutes => (average_build_time%3600/60).to_i})
end
def formatted_average_build_time
"%02d:%02d" % [average_build_time / 3600, average_build_time % 3600 / 60]
end
def average_build_time
project.project_statistics.where(:arch_id => arch_id).first.try(:average_build_time) || 0
end
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]}")
end end

View File

@ -14,9 +14,14 @@ class BuildListObserver < ActiveRecord::Observer
if record.status == BuildList::SUCCESS if record.status == BuildList::SUCCESS
# Update project average build time # Update project average build time
build_count = record.project.build_count begin
new_av_time = ( record.project.average_build_time * build_count + record.duration ) / ( build_count + 1 ) statistic = record.project.project_statistics.find_or_create_by_arch_id(record.arch_id)
record.project.update_attributes({ :average_build_time => new_av_time, :build_count => build_count + 1 }, :without_protection => true) rescue ActiveRecord::RecordNotUnique
retry
end
build_count = statistic.build_count
new_av_time = ( statistic.average_build_time * build_count + record.duration ) / ( build_count + 1 )
statistic.update_attributes(:average_build_time => new_av_time, :build_count => build_count + 1)
end end
end end
end end

View File

@ -15,6 +15,7 @@ class Project < ActiveRecord::Base
has_many :project_to_repositories, :dependent => :destroy has_many :project_to_repositories, :dependent => :destroy
has_many :repositories, :through => :project_to_repositories has_many :repositories, :through => :project_to_repositories
has_many :project_tags, :dependent => :destroy has_many :project_tags, :dependent => :destroy
has_many :project_statistics, :dependent => :destroy
has_many :build_lists, :dependent => :destroy has_many :build_lists, :dependent => :destroy
has_many :hooks, :dependent => :destroy has_many :hooks, :dependent => :destroy
@ -193,14 +194,6 @@ class Project < ActiveRecord::Base
end end
end end
def human_average_build_time
I18n.t("layout.projects.human_average_build_time", {:hours => (average_build_time/3600).to_i, :minutes => (average_build_time%3600/60).to_i})
end
def formatted_average_build_time
"%02d:%02d" % [average_build_time / 3600, average_build_time % 3600 / 60]
end
def destroy_project_from_repository(repository) def destroy_project_from_repository(repository)
AbfWorker::BuildListsPublishTaskManager.destroy_project_from_repository self, repository AbfWorker::BuildListsPublishTaskManager.destroy_project_from_repository self, repository
end end

View File

@ -0,0 +1,10 @@
class ProjectStatistic < ActiveRecord::Base
belongs_to :arch
belongs_to :project
validates :arch_id, :project_id, :average_build_time, :build_count, :presence => true
validates :project_id, :uniqueness => {:scope => :arch_id}
attr_accessible :average_build_time, :build_count
end

View File

@ -1,6 +1,6 @@
json.projects @projects do |project| json.projects @projects do |project|
json.partial! 'project', :project => project json.partial! 'project', :project => project
json.(project, :visibility, :description, :ancestry, :has_issues, :has_wiki, :default_branch, :is_package, :average_build_time, :publish_i686_into_x86_64) json.(project, :visibility, :description, :ancestry, :has_issues, :has_wiki, :default_branch, :is_package, :publish_i686_into_x86_64)
json.created_at project.created_at.to_i json.created_at project.created_at.to_i
json.updated_at project.updated_at.to_i json.updated_at project.updated_at.to_i
json.partial! 'api/v1/shared/owner', :owner => project.owner json.partial! 'api/v1/shared/owner', :owner => project.owner

View File

@ -1,12 +1,17 @@
json.project do json.project do
json.partial! 'project', :project => @project json.partial! 'project', :project => @project
json.(@project, :visibility, :description, :ancestry, :has_issues, :has_wiki, :default_branch, :is_package, :average_build_time, :publish_i686_into_x86_64) json.(@project, :visibility, :description, :ancestry, :has_issues, :has_wiki, :default_branch, :is_package, :publish_i686_into_x86_64)
json.created_at @project.created_at.to_i json.created_at @project.created_at.to_i
json.updated_at @project.updated_at.to_i json.updated_at @project.updated_at.to_i
json.partial! 'api/v1/shared/owner', :owner => @project.owner json.partial! 'api/v1/shared/owner', :owner => @project.owner
json.maintainer do json.maintainer do
json.partial! 'api/v1/shared/member', :member => @project.maintainer json.partial! 'api/v1/shared/member', :member => @project.maintainer
end end
json.project_statistics @project.project_statistics do |statistic|
json.(statistic, :average_build_time, :build_count, :arch_id)
end
json.repositories @project.repositories do |repo| json.repositories @project.repositories do |repo|
json.(repo, :id, :name) json.(repo, :id, :name)
json.url api_v1_repository_path(repo.name, :format => :json) json.url api_v1_repository_path(repo.name, :format => :json)

View File

@ -6,10 +6,10 @@
- if BuildList::HUMAN_STATUSES[build_list.status].in? [:build_pending, :build_started, :build_publish] - if BuildList::HUMAN_STATUSES[build_list.status].in? [:build_pending, :build_started, :build_publish]
%time.js-relative-date{:datetime => build_list.updated_at.strftime("%FT%T%:z"), :title => build_list.updated_at.strftime("%F %T")} %time.js-relative-date{:datetime => build_list.updated_at.strftime("%FT%T%:z"), :title => build_list.updated_at.strftime("%F %T")}
= build_list.updated_at.strftime "%F %T" = build_list.updated_at.strftime "%F %T"
- if build_list.build_started? && ((build_list.project.average_build_time || 0) > 0) - if build_list.build_started? && (build_list.average_build_time > 0)
\/ \/
%time %time
= build_list.project.formatted_average_build_time = build_list.formatted_average_build_time
- if build_list.project.present? - if build_list.project.present?
%td= link_to build_list.project.name_with_owner, build_list.project %td= link_to build_list.project.name_with_owner, build_list.project
%td= build_list_version_link(build_list) %td= build_list_version_link(build_list)

View File

@ -98,7 +98,7 @@
%br %br
.leftlist .leftlist
.rightlist .rightlist
= "#{@build_list.human_current_duration} / #{@build_list.project.human_average_build_time}" = "#{@build_list.human_current_duration} / #{@build_list.human_average_build_time}"
.both .both
- if @build_list.can_cancel? && can?(:cancel, @build_list) - if @build_list.can_cancel? && can?(:cancel, @build_list)

View File

@ -9,6 +9,9 @@ common: &common
- 127.0.0.100 - 127.0.0.100
abf_worker: abf_worker:
publish_workers_count: 2 publish_workers_count: 2
log_server:
host: 127.0.0.1
port: 6379
keys: keys:
key_pair_secret_key: 'key_pair_secret_key' key_pair_secret_key: 'key_pair_secret_key'
airbrake_api_key: 'airbrake_api_key' airbrake_api_key: 'airbrake_api_key'

View File

@ -9,6 +9,9 @@ common: &common
- 127.0.0.100 - 127.0.0.100
abf_worker: abf_worker:
publish_workers_count: 2 publish_workers_count: 2
log_server:
host: 127.0.0.1
port: 6379
keys: keys:
key_pair_secret_key: 'key_pair_secret_key' key_pair_secret_key: 'key_pair_secret_key'
airbrake_api_key: 'airbrake_api_key' airbrake_api_key: 'airbrake_api_key'

View File

@ -47,7 +47,6 @@ en:
sections: Sections sections: Sections
has_issue_description: Tracker adds a lightweight issue management system tightly integrated with your repository. has_issue_description: Tracker adds a lightweight issue management system tightly integrated with your repository.
has_wiki_description: Wikis are the simplest way to allow other users to contribute content. Any user can create and edit pages for documentation, examples, support or anything you wish. has_wiki_description: Wikis are the simplest way to allow other users to contribute content. Any user can create and edit pages for documentation, examples, support or anything you wish.
human_average_build_time: Expected time is %{hours} h. %{minutes} min.
git_global_setup: Git global setup git_global_setup: Git global setup
create_repository: Create Repository create_repository: Create Repository
move_files_to_folder: Move files you need to the project or create them. move_files_to_folder: Move files you need to the project or create them.

View File

@ -3,7 +3,7 @@ ru:
projects: projects:
branches: Ветки branches: Ветки
delete_branch: Удалить ветку delete_branch: Удалить ветку
restore_branch: Востановить ветку restore_branch: Восстановить ветку
no_branches: Нет веток no_branches: Нет веток
base_branch: Текущая ветка base_branch: Текущая ветка
compare: Сравнить compare: Сравнить
@ -47,7 +47,6 @@ ru:
sections: Разделы sections: Разделы
has_issue_description: Трэкер предоставляет лекговесный менеджер для задач по разработке Вашего проекта. has_issue_description: Трэкер предоставляет лекговесный менеджер для задач по разработке Вашего проекта.
has_wiki_description: Wiki - это самый простой способ предоставить другим вносить свой вклад в развитие Вашего проекта. Каждый пользователь нашего сервиса может использовать Wiki для документирования, примеров, поддержки или всего другого, в чем у Вас появится необходимость. has_wiki_description: Wiki - это самый простой способ предоставить другим вносить свой вклад в развитие Вашего проекта. Каждый пользователь нашего сервиса может использовать Wiki для документирования, примеров, поддержки или всего другого, в чем у Вас появится необходимость.
human_average_build_time: 'Ожидаемое время: %{hours} ч. %{minutes} мин.'
git_global_setup: Общие настройки Git git_global_setup: Общие настройки Git
create_repository: Создание репозитория create_repository: Создание репозитория
move_files_to_folder: Переместите нужные файлы в проект или создайте их. move_files_to_folder: Переместите нужные файлы в проект или создайте их.

View File

@ -0,0 +1,14 @@
en:
layout:
project_statistics:
human_average_build_time: Expected time is %{hours} h. %{minutes} min.
flash:
project_statistic:
activerecord:
models:
project_statistic: Project statistic
attributes:
project_statistic:

View File

@ -0,0 +1,16 @@
ru:
layout:
project_statistics:
human_average_build_time: 'Ожидаемое время: %{hours} ч. %{minutes} мин.'
flash:
project_statistic:
activerecord:
models:
project_statistic: Статистика проекта
attributes:
project_statistic:

View File

@ -0,0 +1,13 @@
class CreateProjectStatistics < ActiveRecord::Migration
def change
create_table :project_statistics do |t|
t.integer :average_build_time, :null => false, :default => 0
t.integer :build_count, :null => false, :default => 0
t.integer :arch_id, :null => false
t.integer :project_id, :null => false
t.timestamps
end
add_index :project_statistics, [:project_id, :arch_id], :unique => true
end
end

View File

@ -0,0 +1,11 @@
class DropAverageBuildTimeAndBuildCountFromProject < ActiveRecord::Migration
def up
remove_column :projects, :average_build_time
remove_column :projects, :build_count
end
def down
add_column :projects, :average_build_time, :integer, :null => false, :default => 0
add_column :projects, :build_count, :integer, :null => false, :default => 0
end
end

View File

@ -11,7 +11,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 => 20130724105821) do ActiveRecord::Schema.define(:version => 20130731130518) 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
@ -376,6 +376,17 @@ ActiveRecord::Schema.define(:version => 20130724105821) do
add_index "project_imports", ["platform_id", "name"], :name => "index_project_imports_on_name_and_platform_id", :unique => true, :case_sensitive => false add_index "project_imports", ["platform_id", "name"], :name => "index_project_imports_on_name_and_platform_id", :unique => true, :case_sensitive => false
create_table "project_statistics", :force => true do |t|
t.integer "average_build_time", :default => 0, :null => false
t.integer "build_count", :default => 0, :null => false
t.integer "arch_id", :null => false
t.integer "project_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "project_statistics", ["project_id", "arch_id"], :name => "index_project_statistics_on_project_id_and_arch_id", :unique => true
create_table "project_tags", :force => true do |t| create_table "project_tags", :force => true do |t|
t.integer "project_id" t.integer "project_id"
t.string "commit_id" t.string "commit_id"
@ -412,8 +423,6 @@ ActiveRecord::Schema.define(:version => 20130724105821) do
t.boolean "has_wiki", :default => false 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 "build_count", :default => 0, :null => false
t.integer "maintainer_id" t.integer "maintainer_id"
t.boolean "publish_i686_into_x86_64", :default => false t.boolean "publish_i686_into_x86_64", :default => false
t.string "owner_uname", :null => false t.string "owner_uname", :null => false

View File

@ -1,59 +1,70 @@
module AbfWorker module AbfWorker::ModelHelper
module ModelHelper # In model which contains this helper should be:
# In model which contains this helper should be: # - #abf_worker_args
# - #abf_worker_args # - #build_canceled
# - #build_canceled
def abf_worker_log
Resque.redis.get(service_queue) || I18n.t('layout.build_lists.log.not_available')
end
def add_job_to_abf_worker_queue
Resque.push(
worker_queue_with_priority,
'class' => worker_queue_class,
'args' => [abf_worker_args]
)
end
def cancel_job
deleted = Resque::Job.destroy(
worker_queue_with_priority,
worker_queue_class,
abf_worker_args
)
if deleted == 1
build_canceled
else
send_stop_signal
end
true
end
def worker_queue_with_priority(queue = nil)
queue ||= abf_worker_base_queue
queue << '_' << abf_worker_priority if abf_worker_priority.present?
queue
end
def worker_queue_class(queue_class = nil)
queue_class ||= "AbfWorker::#{abf_worker_base_queue.classify}"
queue_class << abf_worker_priority.capitalize
end
private
def send_stop_signal
Resque.redis.setex(
"#{service_queue}::live-inspector",
240, # Data will be removed from Redis after 240 sec.
'USR1' # Immediately kill child but don't exit
)
end
def service_queue
"abfworker::#{abf_worker_base_queue.gsub(/\_/, '-')}-#{id}"
end
def self.included(base)
base.extend(ClassMethods)
end end
module ClassMethods
def log_server
@log_server ||= Redis.new(
:host => APP_CONFIG['abf_worker']['log_server']['host'],
:port => APP_CONFIG['abf_worker']['log_server']['port']
)
end
end
def abf_worker_log
self.class.log_server.get(service_queue) || I18n.t('layout.build_lists.log.not_available')
end
def add_job_to_abf_worker_queue
Resque.push(
worker_queue_with_priority,
'class' => worker_queue_class,
'args' => [abf_worker_args]
)
end
def cancel_job
deleted = Resque::Job.destroy(
worker_queue_with_priority,
worker_queue_class,
abf_worker_args
)
if deleted == 1
build_canceled
else
send_stop_signal
end
true
end
def worker_queue_with_priority(queue = nil)
queue ||= abf_worker_base_queue
queue << '_' << abf_worker_priority if abf_worker_priority.present?
queue
end
def worker_queue_class(queue_class = nil)
queue_class ||= "AbfWorker::#{abf_worker_base_queue.classify}"
queue_class << abf_worker_priority.capitalize
end
private
def send_stop_signal
Resque.redis.setex(
"#{service_queue}::live-inspector",
240, # Data will be removed from Redis after 240 sec.
'USR1' # Immediately kill child but don't exit
)
end
def service_queue
"abfworker::#{abf_worker_base_queue.gsub(/\_/, '-')}-#{id}"
end
end end

View File

@ -0,0 +1,7 @@
# -*- encoding : utf-8 -*-
FactoryGirl.define do
factory :project_statistic do
association :project, :factory => :project
association :arch, :factory => :arch
end
end

View File

@ -0,0 +1,24 @@
require 'spec_helper'
describe ProjectStatistic do
context 'ensures that validations and associations exist' do
it { should belong_to(:project) }
it { should belong_to(:arch) }
it { should validate_presence_of(:project_id) }
it { should validate_presence_of(:arch_id) }
it { should validate_presence_of(:average_build_time) }
it { should validate_presence_of(:build_count) }
it { should_not allow_mass_assignment_of(:project_id) }
it { should_not allow_mass_assignment_of(:arch_id) }
it 'uniqueness of project_id and arch_id' do
FactoryGirl.create(:project_statistic)
should validate_uniqueness_of(:project_id).scoped_to(:arch_id)
end
end
end