Merge pull request #799 from warpc/794-move-all-keys-into-abf-bd
#794: move all keys into abf bd
This commit is contained in:
commit
eeb58ccd8e
2
Gemfile
2
Gemfile
|
@ -56,6 +56,8 @@ gem 'rails-backbone', '~> 0.7.2'
|
|||
gem 'rack-throttle'
|
||||
gem 'rest-client', '~> 1.6.6'
|
||||
|
||||
gem 'attr_encrypted', '1.2.1'
|
||||
|
||||
group :assets do
|
||||
gem 'sass-rails', '~> 3.2.5'
|
||||
gem 'coffee-rails', '~> 3.2.2'
|
||||
|
|
138
Gemfile.lock
138
Gemfile.lock
|
@ -52,23 +52,27 @@ GEM
|
|||
activesupport (3.2.11)
|
||||
i18n (~> 0.6)
|
||||
multi_json (~> 1.0)
|
||||
airbrake (3.1.2)
|
||||
activesupport
|
||||
airbrake (3.1.6)
|
||||
builder
|
||||
girl_friday
|
||||
ancestry (1.3.0)
|
||||
activerecord (>= 2.3.14)
|
||||
arel (3.0.2)
|
||||
attr_encrypted (1.2.1)
|
||||
encryptor (>= 1.1.1)
|
||||
bcrypt-ruby (3.0.1)
|
||||
blankslate (2.1.2.4)
|
||||
blankslate (3.1.2)
|
||||
bluepill (0.0.60)
|
||||
activesupport (>= 3.0.0)
|
||||
daemons (~> 1.1.4, <= 1.1.6)
|
||||
i18n (>= 0.5.0)
|
||||
state_machine (~> 1.1.0)
|
||||
bourne (1.1.2)
|
||||
mocha (= 0.10.5)
|
||||
builder (3.0.4)
|
||||
cancan (1.6.7)
|
||||
cape (1.4.0)
|
||||
capistrano (2.12.0)
|
||||
cape (1.6.0)
|
||||
capistrano (2.14.1)
|
||||
highline
|
||||
net-scp (>= 1.0.0)
|
||||
net-sftp (>= 2.0.0)
|
||||
|
@ -77,22 +81,26 @@ GEM
|
|||
capistrano_colors (0.5.5)
|
||||
charlock_holmes (0.6.9)
|
||||
chronic (0.6.7)
|
||||
chunky_png (1.2.6)
|
||||
cocaine (0.2.1)
|
||||
chunky_png (1.2.7)
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cocaine (0.5.1)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
coffee-rails (3.2.2)
|
||||
coffee-script (>= 2.2.0)
|
||||
railties (~> 3.2.0)
|
||||
coffee-script (2.2.0)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.3.3)
|
||||
coffee-script-source (1.4.0)
|
||||
compass (0.12.2)
|
||||
chunky_png (~> 1.2)
|
||||
fssm (>= 0.2.7)
|
||||
sass (~> 3.1)
|
||||
compass-rails (1.0.3)
|
||||
compass (>= 0.12.2, < 0.14)
|
||||
creole (0.4.2)
|
||||
connection_pool (1.0.0)
|
||||
creole (0.5.0)
|
||||
daemons (1.1.6)
|
||||
devise (2.1.2)
|
||||
bcrypt-ruby (~> 3.0)
|
||||
|
@ -102,9 +110,10 @@ GEM
|
|||
diff-display (0.0.1)
|
||||
diff-lcs (1.1.3)
|
||||
ejs (1.0.0)
|
||||
encryptor (1.1.3)
|
||||
erubis (2.7.0)
|
||||
escape_utils (0.2.4)
|
||||
eventmachine (0.12.10)
|
||||
eventmachine (1.0.0)
|
||||
execjs (1.4.0)
|
||||
multi_json (~> 1.0)
|
||||
expression_parser (0.9.0)
|
||||
|
@ -115,14 +124,17 @@ GEM
|
|||
railties (>= 3.0.0)
|
||||
ffi (1.0.11)
|
||||
fssm (0.2.9)
|
||||
girl_friday (0.11.2)
|
||||
connection_pool (~> 1.0)
|
||||
rubinius-actor
|
||||
github-linguist (2.2.1)
|
||||
charlock_holmes (~> 0.6.6)
|
||||
escape_utils (~> 0.2.3)
|
||||
mime-types (~> 1.18)
|
||||
pygments.rb (>= 0.2.13)
|
||||
github-markdown (0.5.0)
|
||||
github-markup (0.7.4)
|
||||
gollum (2.1.3)
|
||||
github-markdown (0.5.3)
|
||||
github-markup (0.7.5)
|
||||
gollum (2.1.10)
|
||||
github-markdown
|
||||
github-markup (>= 0.7.0, < 1.0.0)
|
||||
grit (~> 2.5.0)
|
||||
|
@ -135,24 +147,24 @@ GEM
|
|||
stringex (~> 1.4.0)
|
||||
useragent (~> 0.4.9)
|
||||
haml (3.1.7)
|
||||
haml-rails (0.3.4)
|
||||
actionpack (~> 3.0)
|
||||
activesupport (~> 3.0)
|
||||
haml (~> 3.0)
|
||||
railties (~> 3.0)
|
||||
haml-rails (0.3.5)
|
||||
actionpack (>= 3.1, < 4.1)
|
||||
activesupport (>= 3.1, < 4.1)
|
||||
haml (~> 3.1)
|
||||
railties (>= 3.1, < 4.1)
|
||||
hashie (1.2.0)
|
||||
highline (1.6.13)
|
||||
highline (1.6.15)
|
||||
hike (1.2.1)
|
||||
hirb (0.7.0)
|
||||
i18n (0.6.1)
|
||||
jbuilder (0.8.2)
|
||||
jbuilder (0.8.3)
|
||||
activesupport (>= 3.0.0)
|
||||
journey (1.0.4)
|
||||
jquery-rails (2.0.2)
|
||||
railties (>= 3.2.0, < 5.0)
|
||||
jquery-rails (2.0.3)
|
||||
railties (>= 3.1.0, < 5.0)
|
||||
thor (~> 0.14)
|
||||
json (1.7.6)
|
||||
kgio (2.7.4)
|
||||
kgio (2.8.0)
|
||||
libv8 (3.3.10.4)
|
||||
macaddr (1.6.1)
|
||||
systemu (~> 2.5.0)
|
||||
|
@ -160,18 +172,21 @@ GEM
|
|||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mailcatcher (0.5.8)
|
||||
mailcatcher (0.5.10)
|
||||
activesupport (~> 3.0)
|
||||
eventmachine (~> 0.12)
|
||||
eventmachine (~> 1.0.0)
|
||||
haml (~> 3.1)
|
||||
mail (~> 2.3)
|
||||
sinatra (~> 1.2)
|
||||
skinny (~> 0.2, >= 0.2.1)
|
||||
skinny (~> 0.2.3)
|
||||
sqlite3 (~> 1.3)
|
||||
thin (~> 1.2)
|
||||
thin (~> 1.5.0)
|
||||
meta-tags (1.2.6)
|
||||
actionpack
|
||||
metaclass (0.0.1)
|
||||
mime-types (1.19)
|
||||
mocha (0.10.5)
|
||||
metaclass (~> 0.0.1)
|
||||
mock_redis (0.6.2)
|
||||
multi_json (1.5.0)
|
||||
mustache (0.99.4)
|
||||
|
@ -179,12 +194,12 @@ GEM
|
|||
net-ssh (>= 1.99.1)
|
||||
net-sftp (2.0.5)
|
||||
net-ssh (>= 2.0.9)
|
||||
net-ssh (2.5.2)
|
||||
net-ssh (2.6.3)
|
||||
net-ssh-gateway (1.1.0)
|
||||
net-ssh (>= 1.99.1)
|
||||
newrelic_rpm (3.4.1)
|
||||
nokogiri (1.5.5)
|
||||
omniauth (1.1.0)
|
||||
newrelic_rpm (3.4.2.1)
|
||||
nokogiri (1.5.6)
|
||||
omniauth (1.1.1)
|
||||
hashie (~> 1.2)
|
||||
rack
|
||||
omniauth-openid (1.0.1)
|
||||
|
@ -201,18 +216,18 @@ GEM
|
|||
rails (~> 3.0)
|
||||
redis
|
||||
resque
|
||||
pg (0.14.0)
|
||||
pg (0.14.1)
|
||||
polyglot (0.3.3)
|
||||
posix-spawn (0.3.6)
|
||||
pygments.rb (0.2.13)
|
||||
rubypython (~> 0.5.3)
|
||||
rack (1.4.3)
|
||||
rack (1.4.4)
|
||||
rack-cache (1.2)
|
||||
rack (>= 0.4)
|
||||
rack-openid (1.3.1)
|
||||
rack (>= 1.1.0)
|
||||
ruby-openid (>= 2.1.8)
|
||||
rack-protection (1.2.0)
|
||||
rack-protection (1.3.2)
|
||||
rack
|
||||
rack-ssl (1.3.2)
|
||||
rack
|
||||
|
@ -232,9 +247,9 @@ GEM
|
|||
coffee-script (~> 2.2.0)
|
||||
ejs (~> 1.0.0)
|
||||
railties (>= 3.1.0)
|
||||
rails3-generators (0.17.4)
|
||||
rails3-generators (1.0.0)
|
||||
railties (>= 3.0.0)
|
||||
rails3-jquery-autocomplete (1.0.7)
|
||||
rails3-jquery-autocomplete (1.0.10)
|
||||
rails (~> 3.0)
|
||||
railties (3.2.11)
|
||||
actionpack (= 3.2.11)
|
||||
|
@ -249,7 +264,7 @@ GEM
|
|||
rdoc (3.12)
|
||||
json (~> 1.4)
|
||||
redcarpet (2.1.1)
|
||||
redis (3.0.1)
|
||||
redis (3.0.2)
|
||||
redis-namespace (1.2.1)
|
||||
redis (~> 3.0.0)
|
||||
redisk (0.2.2)
|
||||
|
@ -274,63 +289,67 @@ GEM
|
|||
rspec-expectations (~> 2.11.0)
|
||||
rspec-mocks (~> 2.11.0)
|
||||
rspec-core (2.11.1)
|
||||
rspec-expectations (2.11.2)
|
||||
rspec-expectations (2.11.3)
|
||||
diff-lcs (~> 1.1.3)
|
||||
rspec-mocks (2.11.2)
|
||||
rspec-rails (2.11.0)
|
||||
rspec-mocks (2.11.3)
|
||||
rspec-rails (2.11.4)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec (~> 2.11.0)
|
||||
rubinius-actor (0.0.2)
|
||||
rubinius-core-api
|
||||
rubinius-core-api (0.0.1)
|
||||
ruby-haml-js (0.0.3)
|
||||
execjs
|
||||
sprockets (>= 2.0.0)
|
||||
ruby-openid (2.2.0)
|
||||
ruby-openid (2.2.2)
|
||||
rubypython (0.5.3)
|
||||
blankslate (>= 2.1.2.3)
|
||||
ffi (~> 1.0.7)
|
||||
russian (0.6.0)
|
||||
i18n (>= 0.5.0)
|
||||
rvm-capistrano (1.2.5)
|
||||
rvm-capistrano (1.2.7)
|
||||
capistrano (>= 2.0.0)
|
||||
sanitize (2.0.3)
|
||||
nokogiri (>= 1.4.4, < 1.6)
|
||||
sass (3.2.0)
|
||||
sass-rails (3.2.5)
|
||||
sass (3.2.5)
|
||||
sass-rails (3.2.6)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
shotgun (0.9)
|
||||
rack (>= 1.0)
|
||||
shoulda (3.1.1)
|
||||
shoulda-context (~> 1.0)
|
||||
shoulda-matchers (~> 1.2)
|
||||
shoulda-context (1.0.0)
|
||||
shoulda-matchers (1.2.0)
|
||||
shoulda (3.3.2)
|
||||
shoulda-context (~> 1.0.1)
|
||||
shoulda-matchers (~> 1.4.1)
|
||||
shoulda-context (1.0.2)
|
||||
shoulda-matchers (1.4.2)
|
||||
activesupport (>= 3.0.0)
|
||||
sinatra (1.3.2)
|
||||
bourne (~> 1.1.2)
|
||||
sinatra (1.3.3)
|
||||
rack (~> 1.3, >= 1.3.6)
|
||||
rack-protection (~> 1.2)
|
||||
tilt (~> 1.3, >= 1.3.3)
|
||||
skinny (0.2.1)
|
||||
eventmachine (~> 0.12)
|
||||
thin (~> 1.2)
|
||||
skinny (0.2.3)
|
||||
eventmachine (~> 1.0.0)
|
||||
thin (~> 1.5.0)
|
||||
sprockets (2.2.2)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sqlite3 (1.3.6)
|
||||
sqlite3 (1.3.7)
|
||||
state_machine (1.1.2)
|
||||
stringex (1.4.0)
|
||||
systemu (2.5.2)
|
||||
therubyracer (0.10.2)
|
||||
libv8 (~> 3.3.10)
|
||||
thin (1.4.1)
|
||||
thin (1.5.0)
|
||||
daemons (>= 1.0.9)
|
||||
eventmachine (>= 0.12.6)
|
||||
rack (>= 1.0.0)
|
||||
thor (0.16.0)
|
||||
thor (0.15.4)
|
||||
tilt (1.3.3)
|
||||
treetop (1.4.12)
|
||||
polyglot
|
||||
|
@ -343,8 +362,8 @@ GEM
|
|||
kgio (~> 2.6)
|
||||
rack
|
||||
raindrops (~> 0.7)
|
||||
useragent (0.4.10)
|
||||
uuid (2.3.5)
|
||||
useragent (0.4.16)
|
||||
uuid (2.3.6)
|
||||
macaddr (~> 1.0)
|
||||
vegas (0.1.11)
|
||||
rack (>= 1.0.0)
|
||||
|
@ -356,7 +375,7 @@ GEM
|
|||
wikicloth (0.8.0)
|
||||
builder
|
||||
expression_parser
|
||||
will_paginate (3.0.3)
|
||||
will_paginate (3.0.4)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
@ -365,6 +384,7 @@ DEPENDENCIES
|
|||
RedCloth
|
||||
airbrake (~> 3.1.2)
|
||||
ancestry (~> 1.3.0)
|
||||
attr_encrypted (= 1.2.1)
|
||||
bluepill (~> 0.0.60)
|
||||
cancan (= 1.6.7)
|
||||
cape
|
||||
|
|
|
@ -30,6 +30,9 @@ class Api::V1::RepositoriesController < Api::V1::BaseController
|
|||
destroy_subject @repository
|
||||
end
|
||||
|
||||
def key_pair
|
||||
end
|
||||
|
||||
def add_project
|
||||
project = Project.where(:id => params[:project_id]).first
|
||||
if project
|
||||
|
|
|
@ -154,6 +154,12 @@ class Ability
|
|||
cannot([:get_list, :create], MassBuild) {|mass_build| mass_build.platform.personal?}
|
||||
cannot(:cancel, MassBuild) {|mass_build| mass_build.platform.personal? || mass_build.stop_build}
|
||||
|
||||
if @user.system?
|
||||
can :key_pair, Repository
|
||||
else
|
||||
cannot :key_pair, Repository
|
||||
end
|
||||
|
||||
can :create, Subscribe do |subscribe|
|
||||
!subscribe.subscribeable.subscribes.exists?(:user_id => user.id)
|
||||
end
|
||||
|
|
|
@ -1,35 +1,84 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
class KeyPair < ActiveRecord::Base
|
||||
belongs_to :repository
|
||||
belongs_to :user
|
||||
|
||||
attr_accessor :secret
|
||||
attr_accessor :fingerprint
|
||||
attr_accessible :public, :secret, :repository_id
|
||||
attr_encrypted :secret, :key => APP_CONFIG['secret_key']
|
||||
|
||||
validates :repository_id, :public, :user_id, :presence => true
|
||||
validates :secret, :presence => true, :on => :create
|
||||
validates :repository_id, :user_id, :presence => true
|
||||
validates :secret, :public, :presence => true, :length => { :maximum => 10000 }, :on => :create
|
||||
|
||||
validates :repository_id, :uniqueness => {:message => I18n.t("activerecord.errors.key_pair.repo_key_exists")}
|
||||
validate :check_keys
|
||||
|
||||
before_create :key_create_call
|
||||
before_destroy :rm_key_call
|
||||
before_create { |record| record.key_id = @fingerprint }
|
||||
after_create { |record|
|
||||
AbfWorker::BuildListsPublishTaskManager.resign_repository(record) unless record.repository.platform.personal?
|
||||
}
|
||||
|
||||
protected
|
||||
|
||||
def key_create_call
|
||||
result, self.key_id = BuildServer.import_gpg_key_pair(public, secret)
|
||||
raise "Failed to create key_pairs for repository #{repository_id} with code #{result}." if result == 4
|
||||
if result != 0 || self.key_id.nil?
|
||||
errors.add(:public, I18n.t("activerecord.errors.key_pair.rpc_error_#{result}"))
|
||||
return false
|
||||
def check_keys
|
||||
dir = Dir.mktmpdir('keys-', "#{APP_CONFIG['root_path']}/tmp")
|
||||
begin
|
||||
%w(pubring secring).each do |kind|
|
||||
filename = "#{dir}/#{kind}"
|
||||
open("#{filename}.txt", "w") { |f| f.write self.send(kind == 'pubring' ? :public : :secret) }
|
||||
system "gpg --homedir #{dir} --dearmor < #{filename}.txt > #{filename}.gpg"
|
||||
end
|
||||
|
||||
public_key = get_info_of_key "#{dir}/pubring.gpg"
|
||||
secret_key = get_info_of_key "#{dir}/secring.gpg"
|
||||
|
||||
if correct_key?(public_key, :public) & correct_key?(secret_key, :secret)
|
||||
if public_key[:fingerprint] != secret_key[:fingerprint]
|
||||
errors.add :secret, I18n.t('activerecord.errors.key_pair.wrong_keys')
|
||||
else
|
||||
stdin, stdout, stderr = Open3.popen3("echo '\n\n\n\n\nsave' | LC_ALL=en gpg --command-fd 0 --homedir #{dir} --edit-key #{secret_key[:keyid]} passwd")
|
||||
output = stderr.read
|
||||
if output =~ /Invalid\spassphrase/
|
||||
errors.add :secret, I18n.t('activerecord.errors.key_pair.key_has_passphrase')
|
||||
else
|
||||
@fingerprint = secret_key[:fingerprint]
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
# remove the directory.
|
||||
FileUtils.remove_entry_secure dir
|
||||
end
|
||||
result = BuildServer.set_repository_key(repository.platform.name, repository.name, self.key_id)
|
||||
raise "Failed to sign repository #{repository.name} in platform #{repository.platform.name}
|
||||
using key_id #{self.key_id} with code #{result}." unless result.zero?
|
||||
end
|
||||
|
||||
def rm_key_call
|
||||
result = BuildServer.rm_repository_key(repository.platform.name, repository.name)
|
||||
raise "Failed to desroy repository key #{repository.name} in platform
|
||||
#{repository.platform.name} with code #{result}." unless result.zero?
|
||||
def correct_key?(info, field)
|
||||
if info.empty? || info[:type].blank? || info[:fingerprint].blank? || info[:keyid].blank?
|
||||
errors.add field, I18n.t('activerecord.errors.key_pair.wrong_key')
|
||||
return false
|
||||
else
|
||||
if info[:type] != field
|
||||
errors.add field, I18n.t("activerecord.errors.key_pair.wrong_#{field}_key")
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def get_info_of_key(file_path)
|
||||
results = {}
|
||||
str = %x[ gpg --with-fingerprint #{file_path} | sed -n 1,2p]
|
||||
info = str.strip.split("\n")
|
||||
if info.size == 2
|
||||
results[:fingerprint] = info[1].gsub(/.*\=/, '').strip.gsub(/\s/, ':')
|
||||
|
||||
results[:type] = info[0] =~ /^pub\s/ ? :public : nil
|
||||
results[:type] ||= info[0] =~ /^sec\s/ ? :secret : nil
|
||||
|
||||
if keyid = info[0].match(/\/[\w]+\s/)
|
||||
results[:keyid] = keyid[0].strip[1..-1]
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -30,9 +30,8 @@ class Platform < ActiveRecord::Base
|
|||
end
|
||||
}
|
||||
|
||||
before_create :create_directory, :if => lambda {Thread.current[:skip]} # TODO remove this when core will be ready
|
||||
before_create :xml_rpc_create, :unless => lambda {Thread.current[:skip]}
|
||||
before_destroy :xml_rpc_destroy
|
||||
before_create :create_directory
|
||||
before_destroy :detele_directory
|
||||
|
||||
after_update :freeze_platform_and_update_repos
|
||||
after_update :update_owner_relation
|
||||
|
@ -145,7 +144,7 @@ class Platform < ActiveRecord::Base
|
|||
|
||||
def full_clone(attrs = {})
|
||||
base_clone(attrs).tap do |c|
|
||||
with_skip {c.save} and c.clone_relations(self) and c.xml_rpc_clone # later with resque
|
||||
with_skip {c.save} and c.clone_relations(self) and c.fs_clone # later with resque
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -159,10 +158,6 @@ class Platform < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def create_directory
|
||||
system("sudo mkdir -p -m 0777 #{path}")
|
||||
end
|
||||
|
||||
def symlink_directory
|
||||
# umount_directory_for_rsync # TODO ignore errors
|
||||
system("ln -s #{path} #{symlink_path}")
|
||||
|
@ -188,8 +183,13 @@ class Platform < ActiveRecord::Base
|
|||
end
|
||||
later :destroy, :queue => :clone_build
|
||||
|
||||
|
||||
protected
|
||||
|
||||
def create_directory
|
||||
system("mkdir -p -m 0777 #{build_path([name, 'repository'])}")
|
||||
end
|
||||
|
||||
def default_host
|
||||
EventLog.current_controller.request.host_with_port rescue ::Rosa::Application.config.action_mailer.default_url_options[:host]
|
||||
end
|
||||
|
@ -198,38 +198,17 @@ class Platform < ActiveRecord::Base
|
|||
File.join(APP_CONFIG['root_path'], 'platforms', dir)
|
||||
end
|
||||
|
||||
def xml_rpc_create
|
||||
result = BuildServer.add_platform name, APP_CONFIG['root_path'] + '/platforms' , distrib_type
|
||||
if result == BuildServer::SUCCESS
|
||||
return true
|
||||
else
|
||||
raise "Failed to create platform #{name} with code #{result}. Path: #{build_path(name)}"
|
||||
end
|
||||
def detele_directory
|
||||
FileUtils.rm_rf path
|
||||
end
|
||||
|
||||
def xml_rpc_destroy
|
||||
result = BuildServer.delete_platform name
|
||||
if result == BuildServer::SUCCESS
|
||||
return true
|
||||
else
|
||||
raise "Failed to delete platform #{name} with code #{result}."
|
||||
end
|
||||
def fs_clone(old_name = parent.name, new_name = name)
|
||||
FileUtils.cp_r "#{parent.path}/repository", path
|
||||
end
|
||||
|
||||
def xml_rpc_clone(old_name = parent.name, new_name = name)
|
||||
result = BuildServer.clone_platform new_name, old_name, APP_CONFIG['root_path'] + '/platforms'
|
||||
if result == BuildServer::SUCCESS
|
||||
return true
|
||||
else
|
||||
raise "Failed to clone platform #{old_name} with code #{result}. Path: #{build_path(old_name)} to platform #{new_name}"
|
||||
end
|
||||
end
|
||||
later :xml_rpc_clone, :loner => true, :queue => :clone_build
|
||||
later :fs_clone, :loner => true, :queue => :clone_build
|
||||
|
||||
def freeze_platform_and_update_repos
|
||||
if released_changed? && released == true
|
||||
result = BuildServer.freeze(name)
|
||||
raise "Failed freeze platform #{name} with code #{result}" if result != BuildServer::SUCCESS
|
||||
repositories.update_all(:publish_without_qa => false)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -193,6 +193,10 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def destroy_project_from_repository(repository)
|
||||
AbfWorker::BuildListsPublishTaskManager.destroy_project_from_repository self, repository
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def truncate_name
|
||||
|
|
|
@ -5,9 +5,7 @@ class ProjectToRepository < ActiveRecord::Base
|
|||
|
||||
delegate :path, :to => :project
|
||||
|
||||
after_create lambda { project.xml_rpc_create(repository) }, :unless => lambda {Thread.current[:skip]}
|
||||
after_destroy lambda { project.xml_rpc_destroy(repository) }, :unless => lambda {Thread.current[:skip]}
|
||||
# after_rollback lambda { project.xml_rpc_destroy(repository) rescue true if new_record? }
|
||||
after_destroy lambda { project.destroy_project_from_repository(repository) }, :unless => lambda {Thread.current[:skip]}
|
||||
|
||||
validate :one_project_in_platform_repositories
|
||||
|
||||
|
|
|
@ -16,8 +16,7 @@ class Repository < ActiveRecord::Base
|
|||
|
||||
scope :recent, order("name ASC")
|
||||
|
||||
before_create :xml_rpc_create, :unless => lambda {Thread.current[:skip]}
|
||||
before_destroy :xml_rpc_destroy, :unless => lambda {Thread.current[:skip]}
|
||||
before_destroy :detele_directory, :unless => lambda {Thread.current[:skip]}
|
||||
|
||||
attr_accessible :name, :description, :publish_without_qa
|
||||
attr_readonly :name, :platform_id
|
||||
|
@ -59,23 +58,27 @@ class Repository < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
with_skip {super} # avoid cascade XML RPC requests
|
||||
end
|
||||
later :destroy, :queue => :clone_build
|
||||
|
||||
protected
|
||||
|
||||
def xml_rpc_create
|
||||
result = BuildServer.create_repo name, platform.name
|
||||
if result == BuildServer::SUCCESS
|
||||
return true
|
||||
def detele_directory
|
||||
repository_path = platform.path << '/repository'
|
||||
if platform.personal?
|
||||
Platform.main.pluck(:name).each do |main_platform_name|
|
||||
detele_repositories_directory "#{repository_path}/#{main_platform_name}"
|
||||
end
|
||||
else
|
||||
raise "Failed to create repository #{name} inside platform #{platform.name} with code #{result}."
|
||||
detele_repositories_directory repository_path
|
||||
end
|
||||
end
|
||||
|
||||
def xml_rpc_destroy
|
||||
result = BuildServer.delete_repo name, platform.name
|
||||
if result == BuildServer::SUCCESS
|
||||
return true
|
||||
else
|
||||
raise "Failed to delete repository #{name} inside platform #{platform.name} with code #{result}."
|
||||
end
|
||||
def detele_repositories_directory(repository_path)
|
||||
srpm_and_arches = (['SRPM'] << Arch.pluck(:name)).join(',')
|
||||
`bash -c 'rm -rf #{repository_path}/{#{srpm_and_arches}}/#{name}'`
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
json.repository do |json|
|
||||
json.partial! 'repository', :repository => @repository, :json => json
|
||||
json.key_pair do |json_key_pair|
|
||||
if @repository.key_pair
|
||||
json_key_pair.(@repository.key_pair, :public, :secret)
|
||||
else
|
||||
json_key_pair.public ''
|
||||
json_key_pair.secret ''
|
||||
end
|
||||
end
|
||||
end
|
|
@ -42,8 +42,4 @@ Rosa::Application.configure do
|
|||
config.active_record.auto_explain_threshold_in_seconds = 0.5
|
||||
end
|
||||
|
||||
require 'stub_xml_rpc'
|
||||
|
||||
Rails.application.config.to_prepare {
|
||||
Platform.send :include, Modules::Models::SymlinkStub
|
||||
}
|
||||
require 'stub_xml_rpc'
|
|
@ -17,10 +17,11 @@ en:
|
|||
errors:
|
||||
key_pair:
|
||||
repo_key_exists: Repository has been signed already! Please remove old signature and try again
|
||||
rpc_error_0: an unexpected error
|
||||
rpc_error_1: could not import public key
|
||||
rpc_error_2: could not import secret key
|
||||
rpc_error_3: keys are imported, but it is not a key pair (ids differ)
|
||||
wrong_keys: keys are imported, but it is not a key pair (ids differ)
|
||||
wrong_key: wrong
|
||||
wrong_public_key: contains secret key
|
||||
wrong_secret_key: contains public key
|
||||
key_has_passphrase: contains passphrase
|
||||
models:
|
||||
key_pair: Key Pair
|
||||
attributes:
|
||||
|
|
|
@ -17,10 +17,11 @@ ru:
|
|||
errors:
|
||||
key_pair:
|
||||
repo_key_exists: Репозиторий уже подписан! Пожалуйста, удалите старую подпись и попробуйте снова
|
||||
rpc_error_0: Неизвестная ошибка
|
||||
rpc_error_1: Проблемы с импортром публичного ключа
|
||||
rpc_error_2: Проблемы с импортром секретного ключа
|
||||
rpc_error_3: Ключи импортированы, но не являются парой (идентификаторы не совпадают)
|
||||
wrong_keys: Ключи импортированы, но не являются парой (идентификаторы не совпадают)
|
||||
wrong_key: неправильный
|
||||
wrong_public_key: содержит секретный ключ
|
||||
wrong_secret_key: содержит публичный ключ
|
||||
key_has_passphrase: содержит пароль
|
||||
models:
|
||||
key_pair: Подпись
|
||||
attributes:
|
||||
|
|
|
@ -38,6 +38,7 @@ Rosa::Application.routes.draw do
|
|||
resources :repositories, :only => [:show, :update, :destroy] do
|
||||
member {
|
||||
get :projects
|
||||
get :key_pair
|
||||
put :add_member
|
||||
delete :remove_member
|
||||
put :add_project
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
class AddEncryptedSecretToKeyPairs < ActiveRecord::Migration
|
||||
def up
|
||||
rename_table :key_pairs, :key_pairs_backup
|
||||
rename_index :key_pairs_backup, 'index_key_pairs_on_repository_id', 'index_key_pairs_backup_on_repository_id'
|
||||
|
||||
create_table :key_pairs do |t|
|
||||
t.text :public, :null => false
|
||||
t.text :encrypted_secret, :null => false
|
||||
t.string :key_id, :null => false
|
||||
t.references :user, :null => false
|
||||
t.references :repository, :null => false
|
||||
t.timestamps
|
||||
end
|
||||
add_index :key_pairs, :repository_id, :unique => true
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :key_pairs
|
||||
rename_table :key_pairs_backup, :key_pairs
|
||||
rename_index :key_pairs, 'index_key_pairs_backup_on_repository_id', 'index_key_pairs_on_repository_id'
|
||||
end
|
||||
end
|
14
db/schema.rb
14
db/schema.rb
|
@ -207,6 +207,18 @@ ActiveRecord::Schema.define(:version => 20130119125710) do
|
|||
add_index "issues", ["project_id", "serial_id"], :name => "index_issues_on_project_id_and_serial_id", :unique => true
|
||||
|
||||
create_table "key_pairs", :force => true do |t|
|
||||
t.text "public", :null => false
|
||||
t.text "encrypted_secret", :null => false
|
||||
t.string "key_id", :null => false
|
||||
t.integer "user_id", :null => false
|
||||
t.integer "repository_id", :null => false
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "key_pairs", ["repository_id"], :name => "index_key_pairs_on_repository_id", :unique => true
|
||||
|
||||
create_table "key_pairs_backup", :force => true do |t|
|
||||
t.integer "repository_id", :null => false
|
||||
t.integer "user_id", :null => false
|
||||
t.string "key_id", :null => false
|
||||
|
@ -215,7 +227,7 @@ ActiveRecord::Schema.define(:version => 20130119125710) do
|
|||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
add_index "key_pairs", ["repository_id"], :name => "index_key_pairs_on_repository_id", :unique => true
|
||||
add_index "key_pairs_backup", ["repository_id"], :name => "index_key_pairs_backup_on_repository_id", :unique => true
|
||||
|
||||
create_table "labelings", :force => true do |t|
|
||||
t.integer "label_id", :null => false
|
||||
|
|
|
@ -2,8 +2,15 @@
|
|||
module AbfWorker
|
||||
class BuildListsPublishTaskManager
|
||||
REDIS_MAIN_KEY = 'abf-worker::build-lists-publish-task-manager::'
|
||||
LOCKED_REP_AND_PLATFORMS = "#{REDIS_MAIN_KEY}locked-repositories-and-platforms"
|
||||
LOCKED_BUILD_LISTS = "#{REDIS_MAIN_KEY}locked-build-lists"
|
||||
|
||||
%w(RESIGN_REPOSITORIES
|
||||
PROJECTS_FOR_CLEANUP
|
||||
LOCKED_PROJECTS_FOR_CLEANUP
|
||||
LOCKED_REPOSITORIES
|
||||
LOCKED_REP_AND_PLATFORMS
|
||||
LOCKED_BUILD_LISTS).each do |kind|
|
||||
const_set kind, "#{REDIS_MAIN_KEY}#{kind.downcase.gsub('_', '-')}"
|
||||
end
|
||||
|
||||
def initialize
|
||||
@redis = Resque.redis
|
||||
|
@ -11,6 +18,91 @@ module AbfWorker
|
|||
end
|
||||
|
||||
def run
|
||||
create_tasks_for_resign_repositories
|
||||
create_tasks_for_build_rpms
|
||||
end
|
||||
|
||||
class << self
|
||||
def destroy_project_from_repository(project, repository)
|
||||
if repository.platform.personal?
|
||||
Platform.main.each do |main_platform|
|
||||
redis.lpush PROJECTS_FOR_CLEANUP, "#{project.id}-#{repository.id}-#{main_platform.id}"
|
||||
end
|
||||
else
|
||||
redis.lpush PROJECTS_FOR_CLEANUP, "#{project.id}-#{repository.id}-#{repository.platform.id}"
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup_completed(projects_for_cleanup)
|
||||
projects_for_cleanup.each do |key|
|
||||
redis.lrem LOCKED_PROJECTS_FOR_CLEANUP, 0, key
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup_failed(projects_for_cleanup)
|
||||
projects_for_cleanup.each do |key|
|
||||
redis.lrem LOCKED_PROJECTS_FOR_CLEANUP, 0, key
|
||||
redis.lpush PROJECTS_FOR_CLEANUP, key
|
||||
end
|
||||
end
|
||||
|
||||
def resign_repository(key_pair)
|
||||
redis.lpush RESIGN_REPOSITORIES, key_pair.repository_id
|
||||
end
|
||||
|
||||
def unlock_repository(repository_id)
|
||||
redis.lrem LOCKED_REPOSITORIES, 0, repository_id
|
||||
end
|
||||
|
||||
def unlock_build_list(build_list)
|
||||
redis.lrem LOCKED_BUILD_LISTS, 0, build_list.id
|
||||
end
|
||||
|
||||
def unlock_rep_and_platform(build_list)
|
||||
redis.lrem LOCKED_REP_AND_PLATFORMS, 0, "#{build_list.save_to_repository_id}-#{build_list.build_for_platform_id}"
|
||||
end
|
||||
|
||||
def redis
|
||||
Resque.redis
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def locked_repositories
|
||||
@redis.lrange LOCKED_REPOSITORIES, 0, -1
|
||||
end
|
||||
|
||||
def create_tasks_for_resign_repositories
|
||||
resign_repos = @redis.lrange RESIGN_REPOSITORIES, 0, -1
|
||||
|
||||
Repository.where(:id => (resign_repos - locked_repositories)).each do |r|
|
||||
@redis.lrem RESIGN_REPOSITORIES, 0, r.id
|
||||
@redis.lpush LOCKED_REPOSITORIES, r.id
|
||||
Resque.push(
|
||||
'publish_worker_default',
|
||||
'class' => "AbfWorker::PublishWorkerDefault",
|
||||
'args' => [{
|
||||
:id => r.id,
|
||||
:arch => 'x86_64',
|
||||
:distrib_type => r.platform.distrib_type,
|
||||
:platform => {
|
||||
:platform_path => "#{r.platform.path}/repository",
|
||||
:released => r.platform.released
|
||||
},
|
||||
:repository => {
|
||||
:name => r.name,
|
||||
:id => r.id
|
||||
},
|
||||
:type => :resign,
|
||||
:skip_feedback => true,
|
||||
:time_living => 2400 # 40 min
|
||||
}]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def create_tasks_for_build_rpms
|
||||
available_repos = BuildList.
|
||||
select('MIN(updated_at) as min_updated_at, save_to_repository_id, build_for_platform_id').
|
||||
where(:new_core => true, :status => BuildList::BUILD_PUBLISH).
|
||||
|
@ -18,34 +110,33 @@ module AbfWorker
|
|||
order(:min_updated_at).
|
||||
limit(@workers_count * 2) # because some repos may be locked
|
||||
|
||||
locked_rep = locked_repositories
|
||||
available_repos = available_repos.where('save_to_repository_id NOT IN (?)', locked_rep) unless locked_rep.empty?
|
||||
|
||||
counter = 1
|
||||
|
||||
# looks like:
|
||||
# ['save_to_repository_id-build_for_platform_id', ...]
|
||||
locked_rep_and_pl = @redis.lrange(LOCKED_REP_AND_PLATFORMS, 0, -1)
|
||||
available_repos.each do |el|
|
||||
key = "#{el.save_to_repository_id}-#{el.build_for_platform_id}"
|
||||
next if locked_rep_and_pl.include?(key)
|
||||
break if counter > @workers_count
|
||||
if create_task(el.save_to_repository_id, el.build_for_platform_id)
|
||||
@redis.lpush(LOCKED_REP_AND_PLATFORMS, key)
|
||||
counter += 1
|
||||
|
||||
for_cleanup = @redis.lrange(PROJECTS_FOR_CLEANUP, 0, -1).map do |key|
|
||||
pr, rep, pl = *key.split('-')
|
||||
if locked_rep.present? && locked_rep.include?(rep)
|
||||
nil
|
||||
else
|
||||
[rep.to_i, pl.to_i]
|
||||
end
|
||||
end
|
||||
end.compact
|
||||
available_repos = available_repos.map{ |bl| [bl.save_to_repository_id, bl.build_for_platform_id] } | for_cleanup
|
||||
|
||||
available_repos.each do |save_to_repository_id, build_for_platform_id|
|
||||
next if locked_rep_and_pl.include?("#{save_to_repository_id}-#{build_for_platform_id}")
|
||||
break if counter > @workers_count
|
||||
counter += 1 if create_rpm_build_task(save_to_repository_id, build_for_platform_id)
|
||||
end
|
||||
end
|
||||
|
||||
def self.unlock_build_list(build_list)
|
||||
Resque.redis.lrem(LOCKED_BUILD_LISTS, 0, build_list.id)
|
||||
end
|
||||
|
||||
def self.unlock_rep_and_platform(build_list)
|
||||
key = "#{build_list.save_to_repository_id}-#{build_list.build_for_platform_id}"
|
||||
Resque.redis.lrem(LOCKED_REP_AND_PLATFORMS, 0, key)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_task(save_to_repository_id, build_for_platform_id)
|
||||
def create_rpm_build_task(save_to_repository_id, build_for_platform_id)
|
||||
build_lists = BuildList.
|
||||
where(:new_core => true, :status => BuildList::BUILD_PUBLISH).
|
||||
where(:save_to_repository_id => save_to_repository_id).
|
||||
|
@ -54,7 +145,24 @@ module AbfWorker
|
|||
locked_ids = @redis.lrange(LOCKED_BUILD_LISTS, 0, -1)
|
||||
build_lists = build_lists.where('build_lists.id NOT IN (?)', locked_ids) unless locked_ids.empty?
|
||||
|
||||
bl = build_lists.first
|
||||
projects_for_cleanup = @redis.lrange(PROJECTS_FOR_CLEANUP, 0, -1).
|
||||
select{ |k| k =~ /#{save_to_repository_id}\-#{build_for_platform_id}$/ }
|
||||
|
||||
build_lists_for_cleanup = projects_for_cleanup.map do |key|
|
||||
pr, rep, pl = *key.split('-')
|
||||
bl = BuildList.where(:project_id => pr).
|
||||
where(:new_core => true, :status => BuildList::BUILD_PUBLISHED).
|
||||
where(:save_to_repository_id => save_to_repository_id).
|
||||
where(:build_for_platform_id => build_for_platform_id).
|
||||
order(:updated_at).first
|
||||
unless bl
|
||||
# No packages for removing
|
||||
@redis.lrem PROJECTS_FOR_CLEANUP, 0, key
|
||||
end
|
||||
bl
|
||||
end.compact
|
||||
|
||||
bl = build_lists.first || build_lists_for_cleanup.first
|
||||
return false unless bl
|
||||
|
||||
platform_path = "#{bl.save_to_platform.path}/repository"
|
||||
|
@ -96,23 +204,37 @@ module AbfWorker
|
|||
build_list_ids << bl.id
|
||||
@redis.lpush(LOCKED_BUILD_LISTS, bl.id)
|
||||
end
|
||||
packages[:sources] = new_sources.values.compact
|
||||
|
||||
build_lists_for_cleanup.each do |bl|
|
||||
bl.last_published.includes(:packages).limit(5).each{ |old_bl|
|
||||
fill_packages(old_bl, old_packages, :fullname)
|
||||
}
|
||||
end
|
||||
|
||||
packages[:sources] = new_sources.values
|
||||
Resque.push(
|
||||
worker_queue,
|
||||
'class' => worker_class,
|
||||
'args' => [options.merge({
|
||||
:packages => packages,
|
||||
:old_packages => old_packages,
|
||||
:build_list_ids => build_list_ids
|
||||
:build_list_ids => build_list_ids,
|
||||
:projects_for_cleanup => projects_for_cleanup
|
||||
})]
|
||||
)
|
||||
|
||||
projects_for_cleanup.each do |key|
|
||||
@redis.lrem PROJECTS_FOR_CLEANUP, 0, key
|
||||
@redis.lpush LOCKED_PROJECTS_FOR_CLEANUP, key
|
||||
end
|
||||
|
||||
@redis.lpush(LOCKED_REP_AND_PLATFORMS, "#{save_to_repository_id}-#{build_for_platform_id}")
|
||||
return true
|
||||
end
|
||||
|
||||
def fill_packages(bl, results_map, field = :sha1)
|
||||
results_map[:sources] |= bl.packages.by_package_type('source').pluck(field) if field != :sha1
|
||||
results_map[:binaries][bl.arch.name.to_sym] |= bl.packages.by_package_type('binary').pluck(field)
|
||||
results_map[:sources] |= bl.packages.by_package_type('source').pluck(field).compact if field != :sha1
|
||||
results_map[:binaries][bl.arch.name.to_sym] |= bl.packages.by_package_type('binary').pluck(field).compact
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -2,28 +2,45 @@ module AbfWorker
|
|||
class PublishObserver < AbfWorker::BaseObserver
|
||||
@queue = :publish_observer
|
||||
|
||||
def self.perform(options)
|
||||
status = options['status'].to_i
|
||||
return if status == STARTED # do nothing when publication started
|
||||
build_lists = BuildList.where(:id => options['build_list_ids'])
|
||||
build_lists.each do |bl|
|
||||
update_results(bl, options)
|
||||
case status
|
||||
when COMPLETED
|
||||
bl.published
|
||||
when FAILED, CANCELED
|
||||
bl.fail_publish
|
||||
end
|
||||
AbfWorker::BuildListsPublishTaskManager.unlock_build_list bl
|
||||
end
|
||||
AbfWorker::BuildListsPublishTaskManager.unlock_rep_and_platform build_lists.first
|
||||
end
|
||||
|
||||
def self.update_results(subject, options)
|
||||
results = (subject.results || []).
|
||||
select{ |r| r['file_name'] !~ /^abfworker\:\:publish\-worker.*\.log$/ }
|
||||
results |= options['results']
|
||||
sort_results_and_save(subject, results)
|
||||
class << self
|
||||
def perform(options)
|
||||
status = options['status'].to_i
|
||||
return if status == STARTED # do nothing when publication started
|
||||
if options['type'] == 'resign'
|
||||
AbfWorker::BuildListsPublishTaskManager.unlock_repository options['id']
|
||||
else
|
||||
update_rpm_builds options
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def update_rpm_builds(options)
|
||||
build_lists = BuildList.where(:id => options['build_list_ids'])
|
||||
build_lists.each do |bl|
|
||||
update_results(bl, options)
|
||||
case status
|
||||
when COMPLETED
|
||||
bl.published
|
||||
AbfWorker::BuildListsPublishTaskManager.cleanup_completed options['projects_for_cleanup']
|
||||
when FAILED, CANCELED
|
||||
bl.fail_publish
|
||||
AbfWorker::BuildListsPublishTaskManager.cleanup_failed options['projects_for_cleanup']
|
||||
end
|
||||
AbfWorker::BuildListsPublishTaskManager.unlock_build_list bl
|
||||
end
|
||||
bl = build_lists.first || BuildList.find(options['id'])
|
||||
AbfWorker::BuildListsPublishTaskManager.unlock_rep_and_platform bl
|
||||
end
|
||||
|
||||
def update_results(subject, options)
|
||||
results = (subject.results || []).
|
||||
select{ |r| r['file_name'] !~ /^abfworker\:\:publish\-worker.*\.log$/ }
|
||||
results |= options['results']
|
||||
sort_results_and_save(subject, results)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
# -*- encoding : utf-8 -*-
|
||||
module Modules
|
||||
module Models
|
||||
module SymlinkStub
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
def create_directory
|
||||
true
|
||||
end
|
||||
|
||||
def symlink_directory
|
||||
true
|
||||
end
|
||||
|
||||
def remove_symlink_directory
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,7 +26,16 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|||
end
|
||||
|
||||
def start_workers
|
||||
run "cd #{fetch :current_path} && COUNT=#{workers_count} QUEUE=fork_import,hook,clone_build,notification,iso_worker_observer,rpm_worker_observer,publish_observer #{rails_env} BACKGROUND=yes bundle exec rake resque:workers"
|
||||
queue = [
|
||||
:fork_import,
|
||||
:hook,
|
||||
:clone_build,
|
||||
:notification,
|
||||
:iso_worker_observer,
|
||||
:rpm_worker_observer,
|
||||
:publish_observer
|
||||
].join(',')
|
||||
run "cd #{fetch :current_path} && COUNT=#{workers_count} QUEUE=#{queue} #{rails_env} BACKGROUND=yes bundle exec rake resque:workers"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -39,6 +39,13 @@ shared_examples_for "api repository user without show rights" do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples_for "api repository user without key_pair rights" do
|
||||
it 'should not be able to perform key_pair action' do
|
||||
get :key_pair, :id => @repository.id, :format => :json
|
||||
response.should_not be_success
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'api repository user with writer rights' do
|
||||
|
||||
context 'api repository user with update rights' do
|
||||
|
@ -127,8 +134,8 @@ shared_examples_for 'api repository user with writer rights' do
|
|||
|
||||
context 'api repository user with update signatures rights' do
|
||||
before do
|
||||
stub_key_pairs_calls
|
||||
put :signatures, :id => @repository.id, :repository => {:public => 'iampublic', :secret => 'iamsecret'}, :format => :json
|
||||
kp = FactoryGirl.build(:key_pair)
|
||||
put :signatures, :id => @repository.id, :repository => {:public => kp.public, :secret => kp.secret}, :format => :json
|
||||
end
|
||||
it 'should be able to perform signatures action' do
|
||||
response.should be_success
|
||||
|
@ -228,8 +235,8 @@ shared_examples_for 'api repository user without writer rights' do
|
|||
|
||||
context 'api repository user without update signatures rights' do
|
||||
before do
|
||||
stub_key_pairs_calls
|
||||
put :signatures, :id => @repository.id, :repository => {:public => 'iampublic', :secret => 'iamsecret'}, :format => :json
|
||||
kp = FactoryGirl.build(:key_pair)
|
||||
put :signatures, :id => @repository.id, :repository => {:public => kp.public, :secret => kp.secret}, :format => :json
|
||||
end
|
||||
it 'should not be able to perform signatures action' do
|
||||
response.should_not be_success
|
||||
|
@ -245,6 +252,7 @@ end
|
|||
describe Api::V1::RepositoriesController do
|
||||
before(:each) do
|
||||
stub_symlink_methods
|
||||
stub_redis
|
||||
|
||||
@platform = FactoryGirl.create(:platform)
|
||||
@repository = FactoryGirl.create(:repository, :platform => @platform)
|
||||
|
@ -264,6 +272,7 @@ describe Api::V1::RepositoriesController do
|
|||
it_should_behave_like 'api repository user with show rights'
|
||||
end
|
||||
it_should_behave_like 'api repository user without writer rights'
|
||||
it_should_behave_like 'api repository user without key_pair rights'
|
||||
|
||||
it 'should not be able to perform projects action', :anonymous_access => false do
|
||||
get :projects, :id => @repository.id, :format => :json
|
||||
|
@ -280,6 +289,7 @@ describe Api::V1::RepositoriesController do
|
|||
it_should_behave_like 'api repository user with reader rights'
|
||||
it_should_behave_like 'api repository user with reader rights for hidden platform'
|
||||
it_should_behave_like 'api repository user with writer rights'
|
||||
it_should_behave_like 'api repository user without key_pair rights'
|
||||
end
|
||||
|
||||
context 'for platform owner user' do
|
||||
|
@ -294,6 +304,7 @@ describe Api::V1::RepositoriesController do
|
|||
it_should_behave_like 'api repository user with reader rights'
|
||||
it_should_behave_like 'api repository user with reader rights for hidden platform'
|
||||
it_should_behave_like 'api repository user with writer rights'
|
||||
it_should_behave_like 'api repository user without key_pair rights'
|
||||
end
|
||||
|
||||
context 'for user' do
|
||||
|
@ -306,5 +317,26 @@ describe Api::V1::RepositoriesController do
|
|||
it_should_behave_like 'api repository user without reader rights for hidden platform'
|
||||
it_should_behave_like 'api repository user with show rights'
|
||||
it_should_behave_like 'api repository user without writer rights'
|
||||
it_should_behave_like 'api repository user without key_pair rights'
|
||||
end
|
||||
|
||||
context 'for system user' do
|
||||
before(:each) do
|
||||
@user = FactoryGirl.create(:user, :role => 'system')
|
||||
http_login(@user)
|
||||
end
|
||||
|
||||
it 'should be able to perform key_pair action when repository has not keys' do
|
||||
get :key_pair, :id => @repository.id, :format => :json
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
it 'should be able to perform key_pair action when repository has keys' do
|
||||
FactoryGirl.create(:key_pair, :repository => @repository)
|
||||
get :key_pair, :id => @repository.id, :format => :json
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -69,17 +69,18 @@ end
|
|||
describe Platforms::KeyPairsController do
|
||||
before(:each) do
|
||||
stub_symlink_methods
|
||||
stub_key_pairs_calls
|
||||
stub_redis
|
||||
|
||||
@platform = FactoryGirl.create(:platform)
|
||||
@repository = FactoryGirl.create(:repository, :platform => @platform)
|
||||
@user = FactoryGirl.create(:user)
|
||||
kp = FactoryGirl.build(:key_pair)
|
||||
@create_params = {
|
||||
:platform_id => @platform,
|
||||
:key_pair => {
|
||||
:repository_id => @repository,
|
||||
:public => "iampublic",
|
||||
:secret => "iamsecret"
|
||||
:public => kp.public,
|
||||
:secret => kp.secret
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -3,8 +3,18 @@ FactoryGirl.define do
|
|||
factory :key_pair do
|
||||
association :repository
|
||||
association :user
|
||||
public FactoryGirl.generate(:string)
|
||||
secret FactoryGirl.generate(:string)
|
||||
public {
|
||||
file = File.open(Rails.root.join('spec', 'support', 'fixtures', 'pubring.gpg'), "rb")
|
||||
contents = file.read
|
||||
file.close
|
||||
contents
|
||||
}
|
||||
secret {
|
||||
file = File.open(Rails.root.join('spec', 'support', 'fixtures', 'secring.gpg'), "rb")
|
||||
contents = file.read
|
||||
file.close
|
||||
contents
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe AbfWorker::BuildListsPublishTaskManager do
|
||||
before(:all) do
|
||||
@publish_workers_count = APP_CONFIG['abf_worker']['publish_workers_count']
|
||||
APP_CONFIG['abf_worker']['publish_workers_count'] = 2
|
||||
end
|
||||
|
||||
before do
|
||||
init_test_root
|
||||
stub_symlink_methods
|
||||
FactoryGirl.create(:build_list_core, :new_core => true)
|
||||
end
|
||||
|
||||
subject { AbfWorker::BuildListsPublishTaskManager }
|
||||
let(:build_list) { FactoryGirl.create(:build_list_core, :new_core => true) }
|
||||
|
||||
describe 'when no items for publishing' do
|
||||
before do
|
||||
stub_redis
|
||||
subject.new.run
|
||||
end
|
||||
|
||||
%w(RESIGN_REPOSITORIES
|
||||
PROJECTS_FOR_CLEANUP
|
||||
LOCKED_PROJECTS_FOR_CLEANUP
|
||||
LOCKED_REPOSITORIES
|
||||
LOCKED_REP_AND_PLATFORMS
|
||||
LOCKED_BUILD_LISTS).each do |kind|
|
||||
|
||||
it "ensure that no '#{kind.downcase.gsub('_', ' ')}'" do
|
||||
@redis_instance.lrange(subject.const_get(kind), 0, -1).should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
%w(publish_worker_default publish_worker).each do |kind|
|
||||
it "ensure that no tasks in '#{kind}' queue" do
|
||||
@redis_instance.lrange(kind, 0, -1).should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'when one build_list for publishing' do
|
||||
before do
|
||||
stub_redis
|
||||
build_list.update_column(:status, BuildList::BUILD_PUBLISH)
|
||||
2.times{ subject.new.run }
|
||||
end
|
||||
%w(RESIGN_REPOSITORIES
|
||||
PROJECTS_FOR_CLEANUP
|
||||
LOCKED_PROJECTS_FOR_CLEANUP
|
||||
LOCKED_REPOSITORIES).each do |kind|
|
||||
|
||||
it "ensure that no '#{kind.downcase.gsub('_', ' ')}'" do
|
||||
@redis_instance.lrange(subject.const_get(kind), 0, -1).should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it "ensure that 'locked rep and platforms' has only one item" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_REP_AND_PLATFORMS, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include("#{build_list.save_to_repository_id}-#{build_list.build_for_platform_id}")
|
||||
end
|
||||
|
||||
it "ensure that 'locked build lists' has only one item" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_BUILD_LISTS, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include(build_list.id.to_s)
|
||||
end
|
||||
|
||||
it "ensure that new task for publishing has been created" do
|
||||
@redis_instance.lrange('queue:publish_worker_default', 0, -1).should have(1).item
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'grouping build lists for publishing into same repository' do
|
||||
let(:build_list2) { FactoryGirl.create(:build_list_core,
|
||||
:new_core => true,
|
||||
:save_to_platform => build_list.save_to_platform,
|
||||
:save_to_repository => build_list.save_to_repository,
|
||||
:build_for_platform => build_list.build_for_platform
|
||||
) }
|
||||
before do
|
||||
stub_redis
|
||||
build_list.update_column(:status, BuildList::BUILD_PUBLISH)
|
||||
build_list2.update_column(:status, BuildList::BUILD_PUBLISH)
|
||||
2.times{ subject.new.run }
|
||||
end
|
||||
|
||||
%w(RESIGN_REPOSITORIES
|
||||
PROJECTS_FOR_CLEANUP
|
||||
LOCKED_PROJECTS_FOR_CLEANUP
|
||||
LOCKED_REPOSITORIES).each do |kind|
|
||||
|
||||
it "ensure that no '#{kind.downcase.gsub('_', ' ')}'" do
|
||||
@redis_instance.lrange(subject.const_get(kind), 0, -1).should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it "ensure that 'locked rep and platforms' has only one item" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_REP_AND_PLATFORMS, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include("#{build_list.save_to_repository_id}-#{build_list.build_for_platform_id}")
|
||||
end
|
||||
|
||||
it "ensure that 'locked build lists' has 2 items" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_BUILD_LISTS, 0, -1)
|
||||
queue.should have(2).item
|
||||
queue.should include(build_list.id.to_s, build_list2.id.to_s)
|
||||
end
|
||||
|
||||
it "ensure that new task for publishing has been created" do
|
||||
@redis_instance.lrange('queue:publish_worker_default', 0, -1).should have(1).item
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'creates not more than 4 tasks for publishing' do
|
||||
before do
|
||||
stub_redis
|
||||
build_list.update_column(:status, BuildList::BUILD_PUBLISH)
|
||||
4.times {
|
||||
bl = FactoryGirl.create(:build_list_core, :new_core => true)
|
||||
bl.update_column(:status, BuildList::BUILD_PUBLISH)
|
||||
}
|
||||
2.times{ subject.new.run }
|
||||
end
|
||||
|
||||
it "ensure that 'locked rep and platforms' has 4 items" do
|
||||
@redis_instance.lrange(subject::LOCKED_REP_AND_PLATFORMS, 0, -1).should have(4).items
|
||||
end
|
||||
|
||||
it "ensure that 'locked build lists' has 4 items" do
|
||||
@redis_instance.lrange(subject::LOCKED_BUILD_LISTS, 0, -1).should have(4).items
|
||||
end
|
||||
|
||||
it "ensure that new tasks for publishing has been created" do
|
||||
@redis_instance.lrange('queue:publish_worker_default', 0, -1).should have(4).items
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'creates task for removing project from repository' do
|
||||
before do
|
||||
stub_redis
|
||||
build_list.update_column(:status, BuildList::BUILD_PUBLISHED)
|
||||
ProjectToRepository.where(:project_id => build_list.project_id, :repository_id => build_list.save_to_repository_id).destroy_all
|
||||
2.times{ subject.new.run }
|
||||
end
|
||||
|
||||
%w(RESIGN_REPOSITORIES
|
||||
PROJECTS_FOR_CLEANUP
|
||||
LOCKED_REPOSITORIES
|
||||
LOCKED_BUILD_LISTS).each do |kind|
|
||||
|
||||
it "ensure that no '#{kind.downcase.gsub('_', ' ')}'" do
|
||||
@redis_instance.lrange(subject.const_get(kind), 0, -1).should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it "ensure that 'locked rep and platforms' has only one item" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_REP_AND_PLATFORMS, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include("#{build_list.save_to_repository_id}-#{build_list.build_for_platform_id}")
|
||||
end
|
||||
|
||||
it "ensure that 'locked projects for cleanup' has only one item" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_PROJECTS_FOR_CLEANUP, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include("#{build_list.project_id}-#{build_list.save_to_repository_id}-#{build_list.build_for_platform_id}")
|
||||
end
|
||||
|
||||
it "ensure that new task for publishing has been created" do
|
||||
@redis_instance.lrange('queue:publish_worker_default', 0, -1).should have(1).item
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'grouping build lists for publishing and tasks for removing project from repository' do
|
||||
let(:build_list2) { FactoryGirl.create(:build_list_core,
|
||||
:new_core => true,
|
||||
:save_to_platform => build_list.save_to_platform,
|
||||
:save_to_repository => build_list.save_to_repository,
|
||||
:build_for_platform => build_list.build_for_platform
|
||||
) }
|
||||
before do
|
||||
stub_redis
|
||||
build_list.update_column(:status, BuildList::BUILD_PUBLISH)
|
||||
build_list2.update_column(:status, BuildList::BUILD_PUBLISHED)
|
||||
ProjectToRepository.where(:project_id => build_list.project_id, :repository_id => build_list.save_to_repository_id).destroy_all
|
||||
2.times{ subject.new.run }
|
||||
end
|
||||
|
||||
%w(RESIGN_REPOSITORIES
|
||||
PROJECTS_FOR_CLEANUP
|
||||
LOCKED_REPOSITORIES).each do |kind|
|
||||
|
||||
it "ensure that no '#{kind.downcase.gsub('_', ' ')}'" do
|
||||
@redis_instance.lrange(subject.const_get(kind), 0, -1).should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it "ensure that 'locked rep and platforms' has only one item" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_REP_AND_PLATFORMS, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include("#{build_list.save_to_repository_id}-#{build_list.build_for_platform_id}")
|
||||
end
|
||||
|
||||
it "ensure that 'locked projects for cleanup' has only one item" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_PROJECTS_FOR_CLEANUP, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include("#{build_list.project_id}-#{build_list.save_to_repository_id}-#{build_list.build_for_platform_id}")
|
||||
end
|
||||
|
||||
it "ensure that new task for publishing has been created" do
|
||||
@redis_instance.lrange('queue:publish_worker_default', 0, -1).should have(1).item
|
||||
end
|
||||
|
||||
it "ensure that 'locked build lists' has only one item" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_BUILD_LISTS, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include(build_list.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'resign packages in repository' do
|
||||
before do
|
||||
stub_redis
|
||||
build_list.update_column(:status, BuildList::BUILD_PUBLISH)
|
||||
FactoryGirl.create(:key_pair, :repository => build_list.save_to_repository)
|
||||
2.times{ subject.new.run }
|
||||
end
|
||||
|
||||
%w(RESIGN_REPOSITORIES
|
||||
PROJECTS_FOR_CLEANUP
|
||||
LOCKED_PROJECTS_FOR_CLEANUP
|
||||
LOCKED_REP_AND_PLATFORMS
|
||||
LOCKED_BUILD_LISTS).each do |kind|
|
||||
|
||||
it "ensure that no '#{kind.downcase.gsub('_', ' ')}'" do
|
||||
@redis_instance.lrange(subject.const_get(kind), 0, -1).should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it "ensure that 'locked repositories' has only one item" do
|
||||
queue = @redis_instance.lrange(subject::LOCKED_REPOSITORIES, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include(build_list.save_to_repository_id.to_s)
|
||||
end
|
||||
|
||||
it "ensure that new task for resign has been created" do
|
||||
@redis_instance.lrange('queue:publish_worker_default', 0, -1).should have(1).item
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
after(:all) do
|
||||
APP_CONFIG['abf_worker']['publish_workers_count'] = @publish_workers_count
|
||||
FileUtils.rm_rf(APP_CONFIG['root_path'])
|
||||
end
|
||||
end
|
|
@ -2,17 +2,71 @@ require 'spec_helper'
|
|||
|
||||
describe KeyPair do
|
||||
before(:all) do
|
||||
stub_symlink_methods
|
||||
stub_key_pairs_calls
|
||||
init_test_root
|
||||
stub_redis
|
||||
FactoryGirl.create(:key_pair)
|
||||
end
|
||||
|
||||
it { should belong_to(:repository) }
|
||||
it { should belong_to(:user)}
|
||||
it { should ensure_length_of(:public).is_at_most(10000) }
|
||||
it { should ensure_length_of(:secret).is_at_most(10000) }
|
||||
|
||||
|
||||
it { should_not allow_mass_assignment_of(:user) }
|
||||
it { should_not allow_mass_assignment_of(:key_id) }
|
||||
|
||||
describe 'check_keys validation' do
|
||||
subject { FactoryGirl.build(:key_pair) }
|
||||
|
||||
it { subject.valid?.should be_true }
|
||||
it 'checks error when wrong public key' do
|
||||
subject.public = 'test'
|
||||
subject.valid?
|
||||
subject.errors[:public].should =~ [I18n.t('activerecord.errors.key_pair.wrong_key')]
|
||||
end
|
||||
|
||||
it 'checks error when wrong secret key' do
|
||||
subject.secret = 'test'
|
||||
subject.valid?
|
||||
subject.errors[:secret].should =~ [I18n.t('activerecord.errors.key_pair.wrong_key')]
|
||||
end
|
||||
|
||||
it 'checks error when public key contains secret key' do
|
||||
subject.public = subject.secret
|
||||
subject.valid?
|
||||
subject.errors[:public].should =~ [I18n.t('activerecord.errors.key_pair.wrong_public_key')]
|
||||
end
|
||||
|
||||
it 'checks error when secret key contains public key' do
|
||||
subject.secret = subject.public
|
||||
subject.valid?
|
||||
subject.errors[:secret].should =~ [I18n.t('activerecord.errors.key_pair.wrong_secret_key')]
|
||||
end
|
||||
|
||||
it 'checks error when different fingerprint of keys' do
|
||||
file = File.open(Rails.root.join('spec', 'support', 'fixtures', 'pubring.pass.gpg'), "rb")
|
||||
subject.public = file.read
|
||||
file.close
|
||||
subject.valid?
|
||||
subject.errors[:secret].should =~ [I18n.t('activerecord.errors.key_pair.wrong_keys')]
|
||||
end
|
||||
|
||||
it 'checks error when secret key contains passphrase' do
|
||||
file = File.open(Rails.root.join('spec', 'support', 'fixtures', 'pubring.pass.gpg'), "rb")
|
||||
subject.public = file.read
|
||||
file.close
|
||||
file = File.open(Rails.root.join('spec', 'support', 'fixtures', 'secring.pass.gpg'), "rb")
|
||||
subject.secret = file.read
|
||||
file.close
|
||||
|
||||
subject.valid?
|
||||
subject.errors[:secret].should =~ [I18n.t('activerecord.errors.key_pair.key_has_passphrase')]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
after(:all) do
|
||||
Platform.delete_all
|
||||
User.delete_all
|
||||
|
|
|
@ -6,7 +6,7 @@ describe Platform do
|
|||
stub_symlink_methods
|
||||
Platform.delete_all
|
||||
User.delete_all
|
||||
FileUtils.rm_rf(APP_CONFIG['root_path'])
|
||||
init_test_root
|
||||
# Need for validate_uniqueness_of check
|
||||
FactoryGirl.create(:platform)
|
||||
end
|
||||
|
@ -44,6 +44,6 @@ describe Platform do
|
|||
after(:all) do
|
||||
Platform.delete_all
|
||||
User.delete_all
|
||||
FileUtils.rm_rf(APP_CONFIG['root_path'])
|
||||
clear_test_root
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ describe Product do
|
|||
Platform.delete_all
|
||||
User.delete_all
|
||||
Product.delete_all
|
||||
FileUtils.rm_rf(APP_CONFIG['root_path'])
|
||||
init_test_root
|
||||
# Need for validate_uniqueness_of check
|
||||
FactoryGirl.create(:product)
|
||||
end
|
||||
|
@ -28,7 +28,7 @@ describe Product do
|
|||
Platform.delete_all
|
||||
User.delete_all
|
||||
Product.delete_all
|
||||
FileUtils.rm_rf(APP_CONFIG['root_path'])
|
||||
clear_test_root
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -16,4 +16,12 @@ describe ProjectToRepository do
|
|||
p2r = @second_repo.project_to_repositories.build :project_id => @project.id
|
||||
p2r.should_not be_valid
|
||||
end
|
||||
|
||||
it 'creates task for removing project from repository on destroy' do
|
||||
stub_redis
|
||||
@first_repo.project_to_repositories.destroy_all
|
||||
queue = @redis_instance.lrange(AbfWorker::BuildListsPublishTaskManager::PROJECTS_FOR_CLEANUP, 0, -1)
|
||||
queue.should have(1).item
|
||||
queue.should include("#{@project.id}-#{@first_repo.id}-#{@platform.id}")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -102,7 +102,7 @@ describe PullRequest do
|
|||
FileUtils.rm_rf(APP_CONFIG['root_path'])
|
||||
end
|
||||
|
||||
it { should belong_to(:issue) }
|
||||
it { should belong_to(:issue).validate(true) }
|
||||
it { should belong_to(:to_project) }
|
||||
it { should belong_to(:from_project) }
|
||||
|
||||
|
|
|
@ -21,16 +21,16 @@ describe Repository do
|
|||
Platform.delete_all
|
||||
User.delete_all
|
||||
Repository.delete_all
|
||||
FileUtils.rm_rf(APP_CONFIG['root_path'])
|
||||
init_test_root
|
||||
# Need for validate_uniqueness_of check
|
||||
FactoryGirl.create(:repository)
|
||||
end
|
||||
|
||||
it { should belong_to(:platform) }
|
||||
it { should have_many(:project_to_repositories)}
|
||||
it { should have_many(:projects).through(:project_to_repositories)}
|
||||
it { should have_many(:project_to_repositories).validate(true) }
|
||||
it { should have_many(:projects).through(:project_to_repositories) }
|
||||
|
||||
it { should validate_presence_of(:name)}
|
||||
it { should validate_presence_of(:name) }
|
||||
it { should validate_uniqueness_of(:name).case_insensitive.scoped_to(:platform_id) }
|
||||
it { should validate_format_of(:name).with('basic_repository-name-1234') }
|
||||
it { should validate_format_of(:name).not_with('.!') }
|
||||
|
@ -48,7 +48,7 @@ describe Repository do
|
|||
Platform.delete_all
|
||||
User.delete_all
|
||||
Repository.delete_all
|
||||
FileUtils.rm_rf(APP_CONFIG['root_path'])
|
||||
clear_test_root
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -46,23 +46,27 @@ def stub_symlink_methods
|
|||
any_instance_of(Platform, :remove_symlink_directory => true)
|
||||
end
|
||||
|
||||
def stub_key_pairs_calls
|
||||
stub(BuildServer).import_gpg_key_pair { [0,"1a2b3c"] }
|
||||
stub(BuildServer).set_repository_key { 0 }
|
||||
stub(BuildServer).rm_repository_key { 0 }
|
||||
Resque.inline = true
|
||||
APP_CONFIG['root_path'] = "#{Rails.root}/tmp/test_root"
|
||||
APP_CONFIG['git_path'] = "#{Rails.root}/tmp/test_root"
|
||||
|
||||
def init_test_root
|
||||
clear_test_root
|
||||
%x(mkdir -p #{APP_CONFIG['root_path']}/{platforms,tmp})
|
||||
end
|
||||
|
||||
Resque.inline = true
|
||||
|
||||
# Add testing root_path
|
||||
%x(rm -Rf #{APP_CONFIG['git_path']})
|
||||
%x(mkdir -p #{APP_CONFIG['git_path']})
|
||||
def clear_test_root
|
||||
%x(rm -Rf #{APP_CONFIG['root_path']})
|
||||
end
|
||||
|
||||
def stub_redis
|
||||
redis_instance = MockRedis.new
|
||||
stub(Redis).new { redis_instance }
|
||||
@redis_instance = MockRedis.new
|
||||
stub(Redis).new { @redis_instance }
|
||||
stub(Resque).redis { @redis_instance }
|
||||
end
|
||||
|
||||
init_test_root
|
||||
|
||||
def fill_project project
|
||||
%x(mkdir -p #{project.path} && cp -Rf #{Rails.root}/spec/tests.git/* #{project.path}) # maybe FIXME ?
|
||||
end
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1.4.12 (Darwin)
|
||||
|
||||
mQENBFDS81MBCADYXCU/PiiKKhufSW5OG2Fq3BYHpTxvzGHJjK1vHxx71iZZmxJb
|
||||
jr1lB2Iac6TXGjZyZCJqXUyi6+d+AFvt1dE4SzCOYDXF30lGJ+sMgR85vA/dOsRm
|
||||
dQuFeqmgtcCQDlD3ptDe4RXvLhbV7jTKSnhzL0OCOx7nw3NdVfUQ9lLWNxVj2/Wi
|
||||
O4/AFwSA97V9zpqZoXY9xm+yN5WN0hHufjoTNLb5wCX4boaChJDrMcx041STtgec
|
||||
HvJKBhLSS3rS4JwUPPPYWYZvlQ/QbCzo0ZVyPJFoP2QQ1hIADgfE2VL9qmbGb3hZ
|
||||
CfQJqdYBqlJgaXXqU5tCVZygSn3JKrmtCbS/ABEBAAG0MFZva2htaW4gQWxleGV5
|
||||
IFYgKGF2b2tobWluKSA8YXZva2htaW5AZ21haWwuY29tPokBOAQTAQIAIgUCUNLz
|
||||
UwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQasbV9duAtkco+gf+ObSa
|
||||
PjGNybCtzo91AGQiyuHvckC4vsuakWV3wuPIvymLVBAwAK3NYpQt9HhV09YlgrTU
|
||||
y2JYALAsAY9dFTVmn0u6AUjxzgcNJG3NJYoUGdxPJJF3Kb7PVMl4qKYvTFooPY/p
|
||||
yo6fkLxqrLdjODNelqqPl3BOkryhEQAKgIiPkBfu3rkCuN0cHhxhbNu4nH7I3iyv
|
||||
atsxi1DDRk2GKZkGiiVQWlAr09ZLP/PpVCzpUxMC3hdjA2yZ118fMfvHzFAM4jdL
|
||||
BGbgFoads+6wbbhrrSXcD2JdW9knwqfX2GMKJQ55N/m0J56/lkD0zjMbEcCk7Tsv
|
||||
yOjrYsNnRyWw7jGE8LkBDQRQ0vNTAQgAvdVpy2VgNNVAZ6BVPFDaAwrReksCnOBR
|
||||
Bx5vtJHx4ZUudTpxYyxkkz8cxVap8pJKlBNrZiim2RS3RP/Ya9nTqNYrY597FHgc
|
||||
KsS9wrdqw8SWse3Pt0QrCpTCcthXvFwho0WW6GP0b5NoEtblHLeCBXG6xBajs80M
|
||||
7uX7RuOO8SPBCacHR70dmxHjlzQlPSUPrcwxDdlM5FeePSN/ANyrcHaHqNnk+3Dh
|
||||
PBbmOxyEVf+CmSRlfuaKgCm2g6V7uhU6DBW/6rczOm8QD6cY3RLVfzFLi+gXK2ym
|
||||
me99WaICe98qQI82HOaCmUk/JGEI8q3m7rMaL2HmYlHOH/6amYoxUQARAQABiQEf
|
||||
BBgBAgAJBQJQ0vNTAhsMAAoJEGrG1fXbgLZHEB0H/0qmUSltASmyQhe7LAXQcqlJ
|
||||
KxxSTCg5IfOAuL++4nn/b5SJFfMo1bkVtgo+r5ix33D8ZDFQsditGVf4red6ddSa
|
||||
SfnNpZkUScOpeOz31N+ev6fspHnMieL9zoHre/FOqWk6h3Wjl4q1NWdRKwpP5zAn
|
||||
ug17kWzTVxB7CeNbW5N403JoH4e2bWyGO7ZlcM9J26o0g05RU7h5i8y//iUkXt/d
|
||||
PjBD6YChYl7jpSezAm3Xqv7z+oNtFNRp5kFDn8z7XeHKn4LbNlJq02dcCQkS3Asu
|
||||
qNgHF0DPEd+lTyvx5ns4Rd5qt4tuwGJGj+VQSMfmLOX88tc/qqwza/0U3Bct+bI=
|
||||
=ZCfP
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,30 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1.4.12 (Darwin)
|
||||
|
||||
mQENBFDS98ABCACaw+nwAvake7DUS8p1vQfLcPMGWPACXxW1x0rvnd6OXakFIb97
|
||||
lcFQFslLr581nYQIIFbNEJRXI3DO5hz21dEJ13uxNYsVjnwX79ToL7JxrEhi/mrH
|
||||
mOyZqDhkVb4nwQQ231aF4gqmpMaxbylYhvUEwEDil2uxvnFCo1oB3lkD4xkhRkjg
|
||||
n7LqNU15pbCKQsY/qYd502UMaYofacXpqaWY9nKMgPwIH1oMYrgbeJO7PrhZPHaX
|
||||
CT0/9K8LELKvK7gVWcScfXShmYaITWS+udFUsEzy4D2zt9jQOie9lRCJHeeDWvoj
|
||||
AvlWE4VVFnbNK3ShblXhhcr3pX6sKMarAPtRABEBAAG0IHF3ZXJ0eSAocXFxcXEp
|
||||
IDxhcXdlckBqZmRzai5jb20+iQE4BBMBAgAiBQJQ0vfAAhsDBgsJCAcDAgYVCAIJ
|
||||
CgsEFgIDAQIeAQIXgAAKCRC1dIaeWBn9lfgQB/9foCBWi/4BqjMfsFVVVEWhTCCo
|
||||
GWMrY5BtQtgAoY7KX5NFNzCqECYua+HZaMAZgxZxElOq2N8Ig84msWnbuKibzZn9
|
||||
+6LJCxYYqyn+5xcqeRpTl5zA3fFV7K6rICZF9AzoBFuJgNZ0Do15XEQCJHIlztm8
|
||||
AtadgUGQDQkU5OuyGlApQ0KfVxlALyNbIb1b9p0wo+D7LEyTAbCXM6RxloDRBaMe
|
||||
A4uoyzIHOzj3UxU+/38nizlcNAAGy5uyf0o29c9GpRN4ga1ZDspxPxTxrAg4y289
|
||||
i6l1GNXqLxko/Cg69269rl6ejZ4c9tDra/3l7LyTWC7fPcorD0PVgj816y+guQEN
|
||||
BFDS98ABCADpObjrAmbkll/9lzJpuKeComRFu3ry6FBtmuhX22zjbwCm8Xb4EmbS
|
||||
e9HioZVelN2k8FNI2bxEfM6eKk0VwY4VTXkEYlEH74gYrK+iiYwUracBVaT3q1au
|
||||
TrFB+xir4I8rZdFI39iwsKsaUt5XoNPVDrVwOWQRUjxTKfA0y1tOOmByyfDRzXNn
|
||||
bo5tHOx/YXz6nJBe4XpQ7uWcVhHe8wgsd/ti9HPgRDM1Q1bxz9xxWLAn6VF3tvey
|
||||
Jz1i3L5SSHoFHd8OInktSgi3VzhoSaZaBcHcbzm3OrqUofuGbLTKJgpXpCvQlqle
|
||||
2ow/wpAL+stluRuPhYWjMSzKarTJwM1DABEBAAGJAR8EGAECAAkFAlDS98ACGwwA
|
||||
CgkQtXSGnlgZ/ZVC0gf6Av6xYN/O3i4zxQ2anql2TqD6WP3zJX46+T7k+9ayIl67
|
||||
5aH7vHFjmXBt4y8V2ESYIT8LYE3qak7XntNwzjqG4jS4kAw5mOTKaDbGjr+oCGFF
|
||||
wfBUlK+JyuxbFL28i5bYa94S/rQJ/suKhjWIQu1O/NKLaNJuN5YlhcA53eA/ppPt
|
||||
TJBNRG2NUD+rAYN5XGb4ctG5h26PpKfr4fxdd90JHf37S/yAcYPnfEfa/WqgnSPL
|
||||
Bd6AHwmjHxeuRhQhOgIXRmTtWYp3LlPb2yNjL+Vk0ePmzaYp4QrIO1wF1XKTUPB2
|
||||
S1x2nlZd4zDbyBYG/2rSWRCB8LwD0H1XVQAMBjBVvQ==
|
||||
=O0re
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,58 @@
|
|||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Version: GnuPG v1.4.12 (Darwin)
|
||||
|
||||
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
|
||||
3Bct+bI=
|
||||
=CNSZ
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
|
@ -0,0 +1,59 @@
|
|||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Version: GnuPG v1.4.12 (Darwin)
|
||||
|
||||
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
|
||||
0lkQgfC8A9B9V1UADAYwVb0=
|
||||
=hZ8N
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
Loading…
Reference in New Issue