Merge branch 'master' into 242-restart_last_build_list
This commit is contained in:
commit
c2ee66cb67
|
@ -290,6 +290,18 @@ class BuildList < ActiveRecord::Base
|
|||
BuildList.where(:id => extra_build_lists).where('status != ?', BUILD_PUBLISHED).count == 0
|
||||
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)
|
||||
I18n.t("layout.build_lists.statuses.#{HUMAN_STATUSES[status]}")
|
||||
end
|
||||
|
|
|
@ -14,9 +14,14 @@ class BuildListObserver < ActiveRecord::Observer
|
|||
|
||||
if record.status == BuildList::SUCCESS
|
||||
# Update project average build time
|
||||
build_count = record.project.build_count
|
||||
new_av_time = ( record.project.average_build_time * build_count + record.duration ) / ( build_count + 1 )
|
||||
record.project.update_attributes({ :average_build_time => new_av_time, :build_count => build_count + 1 }, :without_protection => true)
|
||||
begin
|
||||
statistic = record.project.project_statistics.find_or_create_by_arch_id(record.arch_id)
|
||||
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
|
||||
|
|
|
@ -15,6 +15,7 @@ class Project < ActiveRecord::Base
|
|||
has_many :project_to_repositories, :dependent => :destroy
|
||||
has_many :repositories, :through => :project_to_repositories
|
||||
has_many :project_tags, :dependent => :destroy
|
||||
has_many :project_statistics, :dependent => :destroy
|
||||
|
||||
has_many :build_lists, :dependent => :destroy
|
||||
has_many :hooks, :dependent => :destroy
|
||||
|
@ -193,14 +194,6 @@ class Project < ActiveRecord::Base
|
|||
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)
|
||||
AbfWorker::BuildListsPublishTaskManager.destroy_project_from_repository self, repository
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -1,6 +1,6 @@
|
|||
json.projects @projects do |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.updated_at project.updated_at.to_i
|
||||
json.partial! 'api/v1/shared/owner', :owner => project.owner
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
json.project do
|
||||
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.updated_at @project.updated_at.to_i
|
||||
json.partial! 'api/v1/shared/owner', :owner => @project.owner
|
||||
json.maintainer do
|
||||
json.partial! 'api/v1/shared/member', :member => @project.maintainer
|
||||
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.(repo, :id, :name)
|
||||
json.url api_v1_repository_path(repo.name, :format => :json)
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
- 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")}
|
||||
= 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
|
||||
= build_list.project.formatted_average_build_time
|
||||
= build_list.formatted_average_build_time
|
||||
- if build_list.project.present?
|
||||
%td= link_to build_list.project.name_with_owner, build_list.project
|
||||
%td= build_list_version_link(build_list)
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
%br
|
||||
.leftlist
|
||||
.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
|
||||
|
||||
- if @build_list.can_cancel? && can?(:cancel, @build_list)
|
||||
|
|
|
@ -9,6 +9,9 @@ common: &common
|
|||
- 127.0.0.100
|
||||
abf_worker:
|
||||
publish_workers_count: 2
|
||||
log_server:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
keys:
|
||||
key_pair_secret_key: 'key_pair_secret_key'
|
||||
airbrake_api_key: 'airbrake_api_key'
|
||||
|
|
|
@ -9,6 +9,9 @@ common: &common
|
|||
- 127.0.0.100
|
||||
abf_worker:
|
||||
publish_workers_count: 2
|
||||
log_server:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
keys:
|
||||
key_pair_secret_key: 'key_pair_secret_key'
|
||||
airbrake_api_key: 'airbrake_api_key'
|
||||
|
|
|
@ -47,7 +47,6 @@ en:
|
|||
sections: Sections
|
||||
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.
|
||||
human_average_build_time: Expected time is %{hours} h. %{minutes} min.
|
||||
git_global_setup: Git global setup
|
||||
create_repository: Create Repository
|
||||
move_files_to_folder: Move files you need to the project or create them.
|
||||
|
|
|
@ -3,7 +3,7 @@ ru:
|
|||
projects:
|
||||
branches: Ветки
|
||||
delete_branch: Удалить ветку
|
||||
restore_branch: Востановить ветку
|
||||
restore_branch: Восстановить ветку
|
||||
no_branches: Нет веток
|
||||
base_branch: Текущая ветка
|
||||
compare: Сравнить
|
||||
|
@ -47,7 +47,6 @@ ru:
|
|||
sections: Разделы
|
||||
has_issue_description: Трэкер предоставляет лекговесный менеджер для задач по разработке Вашего проекта.
|
||||
has_wiki_description: Wiki - это самый простой способ предоставить другим вносить свой вклад в развитие Вашего проекта. Каждый пользователь нашего сервиса может использовать Wiki для документирования, примеров, поддержки или всего другого, в чем у Вас появится необходимость.
|
||||
human_average_build_time: 'Ожидаемое время: %{hours} ч. %{minutes} мин.'
|
||||
git_global_setup: Общие настройки Git
|
||||
create_repository: Создание репозитория
|
||||
move_files_to_folder: Переместите нужные файлы в проект или создайте их.
|
||||
|
|
|
@ -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:
|
|
@ -0,0 +1,16 @@
|
|||
ru:
|
||||
layout:
|
||||
project_statistics:
|
||||
human_average_build_time: 'Ожидаемое время: %{hours} ч. %{minutes} мин.'
|
||||
|
||||
flash:
|
||||
project_statistic:
|
||||
|
||||
|
||||
activerecord:
|
||||
models:
|
||||
project_statistic: Статистика проекта
|
||||
attributes:
|
||||
project_statistic:
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
15
db/schema.rb
15
db/schema.rb
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# 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|
|
||||
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
|
||||
|
||||
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|
|
||||
t.integer "project_id"
|
||||
t.string "commit_id"
|
||||
|
@ -412,8 +423,6 @@ ActiveRecord::Schema.define(:version => 20130724105821) do
|
|||
t.boolean "has_wiki", :default => false
|
||||
t.string "default_branch", :default => "master"
|
||||
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.boolean "publish_i686_into_x86_64", :default => false
|
||||
t.string "owner_uname", :null => false
|
||||
|
|
|
@ -1,59 +1,70 @@
|
|||
module AbfWorker
|
||||
module ModelHelper
|
||||
# In model which contains this helper should be:
|
||||
# - #abf_worker_args
|
||||
# - #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
|
||||
module AbfWorker::ModelHelper
|
||||
# In model which contains this helper should be:
|
||||
# - #abf_worker_args
|
||||
# - #build_canceled
|
||||
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
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
|
|
@ -0,0 +1,7 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
FactoryGirl.define do
|
||||
factory :project_statistic do
|
||||
association :project, :factory => :project
|
||||
association :arch, :factory => :arch
|
||||
end
|
||||
end
|
|
@ -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
|
Loading…
Reference in New Issue