travis-lock 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +61 -0
- data/README.md +32 -0
- data/lib/travis/lock/none.rb +9 -0
- data/lib/travis/lock/postgresql.rb +76 -0
- data/lib/travis/lock/redis.rb +60 -0
- data/lib/travis/lock/support/retry.rb +33 -0
- data/lib/travis/lock/version.rb +5 -0
- data/lib/travis/lock.rb +28 -0
- data/spec/integration.rb +55 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/database.rb +7 -0
- data/spec/travis/lock/none_spec.rb +8 -0
- data/spec/travis/lock/postgresql_spec.rb +138 -0
- data/spec/travis/lock/redis_spec.rb +17 -0
- data/travis-lock.gemspec +22 -0
- metadata +74 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4c983c384c38f7bb07cddd92b3ea775570ff2aec
|
4
|
+
data.tar.gz: 21b952b4ce5c7eeed44d21d4db04e6b4e920f428
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 490a9cb44c09b52426876d131d30c118e3e279a82dd75d7c9cc30d0d6553d5278ba4e9b8d686d34683a18e370727e09a6e2e1ea124365f359a4aaf23a2c2f3c0
|
7
|
+
data.tar.gz: afccd06931aaa156e0e6fbafa590d3929e0a0fc903f3386554499d15277e862f6ab6d1ee09822ae9cf0042e91c134e1a07959def5a58f3522b8439aaa48d590d
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
travis-lock (0.1.4)
|
5
|
+
activerecord (~> 4.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activemodel (4.2.4)
|
11
|
+
activesupport (= 4.2.4)
|
12
|
+
builder (~> 3.1)
|
13
|
+
activerecord (4.2.4)
|
14
|
+
activemodel (= 4.2.4)
|
15
|
+
activesupport (= 4.2.4)
|
16
|
+
arel (~> 6.0)
|
17
|
+
activesupport (4.2.4)
|
18
|
+
i18n (~> 0.7)
|
19
|
+
json (~> 1.7, >= 1.7.7)
|
20
|
+
minitest (~> 5.1)
|
21
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
22
|
+
tzinfo (~> 1.1)
|
23
|
+
arel (6.0.3)
|
24
|
+
builder (3.2.2)
|
25
|
+
diff-lcs (1.2.5)
|
26
|
+
i18n (0.7.0)
|
27
|
+
json (1.8.3)
|
28
|
+
metaclass (0.0.4)
|
29
|
+
minitest (5.8.0)
|
30
|
+
mocha (1.1.0)
|
31
|
+
metaclass (~> 0.0.1)
|
32
|
+
pg (0.18.3)
|
33
|
+
redis (3.2.1)
|
34
|
+
redlock (0.1.1)
|
35
|
+
redis (~> 3, >= 3.0.5)
|
36
|
+
rspec (3.3.0)
|
37
|
+
rspec-core (~> 3.3.0)
|
38
|
+
rspec-expectations (~> 3.3.0)
|
39
|
+
rspec-mocks (~> 3.3.0)
|
40
|
+
rspec-core (3.3.2)
|
41
|
+
rspec-support (~> 3.3.0)
|
42
|
+
rspec-expectations (3.3.1)
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
44
|
+
rspec-support (~> 3.3.0)
|
45
|
+
rspec-mocks (3.3.2)
|
46
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
47
|
+
rspec-support (~> 3.3.0)
|
48
|
+
rspec-support (3.3.0)
|
49
|
+
thread_safe (0.3.5)
|
50
|
+
tzinfo (1.2.2)
|
51
|
+
thread_safe (~> 0.1)
|
52
|
+
|
53
|
+
PLATFORMS
|
54
|
+
ruby
|
55
|
+
|
56
|
+
DEPENDENCIES
|
57
|
+
mocha (~> 1.1)
|
58
|
+
pg
|
59
|
+
redlock
|
60
|
+
rspec (~> 3.0)
|
61
|
+
travis-lock!
|
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Travis Lock
|
2
|
+
|
3
|
+
Application-level locks for use in, e.g. travis-hub.
|
4
|
+
|
5
|
+
At the moment it seems the Redlock strategy works fine as well as the
|
6
|
+
Postgresql advisory locks strategy when used with the options in the
|
7
|
+
example below.
|
8
|
+
|
9
|
+
Usage:
|
10
|
+
|
11
|
+
```
|
12
|
+
options = {
|
13
|
+
strategy: :postgresql,
|
14
|
+
try: true,
|
15
|
+
transactional: false
|
16
|
+
}
|
17
|
+
Travis::Lock.exclusive('build-1', options) do
|
18
|
+
# update build
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
### Doing a Rubygem release
|
23
|
+
|
24
|
+
Any tool works. The current releases were done with
|
25
|
+
[`gem-release`](https://github.com/svenfuchs/gem-release) which allows creating
|
26
|
+
a Git tag, pushing it to GitHub, building the gem and pushing it to Rubygems in
|
27
|
+
one go:
|
28
|
+
|
29
|
+
```bash
|
30
|
+
$ gem install gem-release
|
31
|
+
$ gem bump --push --tag --release
|
32
|
+
```
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# http://hashrocket.com/blog/posts/advisory-locks-in-postgres
|
2
|
+
# https://github.com/mceachen/with_advisory_lock
|
3
|
+
# 13.3.4. Advisory Locks : http://www.postgresql.org/docs/9.3/static/explicit-locking.html
|
4
|
+
# http://www.postgresql.org/docs/9.3/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS
|
5
|
+
|
6
|
+
require 'zlib'
|
7
|
+
require 'active_record'
|
8
|
+
require 'travis/lock/support/retry'
|
9
|
+
|
10
|
+
module Travis
|
11
|
+
module Lock
|
12
|
+
class Postgresql < Struct.new(:name, :options)
|
13
|
+
def initialize(*)
|
14
|
+
super
|
15
|
+
fail 'lock name cannot be blank' if name.nil? || name.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def exclusive(&block)
|
19
|
+
with_timeout { obtain_lock }
|
20
|
+
transactional? ? connection.transaction(&block) : with_release(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def with_timeout(&block)
|
26
|
+
try? ? Retry.new(name, options).run(&block) : with_statement_timeout(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def obtain_lock
|
30
|
+
result = connection.select_value("select #{pg_function}(#{key});")
|
31
|
+
try? ? result == 't' : true
|
32
|
+
end
|
33
|
+
|
34
|
+
def with_release
|
35
|
+
yield
|
36
|
+
ensure
|
37
|
+
connection.execute("select pg_advisory_unlock(#{key});")
|
38
|
+
end
|
39
|
+
|
40
|
+
def try?
|
41
|
+
!!options[:try]
|
42
|
+
end
|
43
|
+
|
44
|
+
def timeout
|
45
|
+
options[:timeout] || 30
|
46
|
+
end
|
47
|
+
|
48
|
+
def transactional?
|
49
|
+
!!options[:transactional]
|
50
|
+
end
|
51
|
+
|
52
|
+
def with_statement_timeout
|
53
|
+
connection.execute("set statement_timeout to #{Integer(timeout * 1000)};")
|
54
|
+
yield
|
55
|
+
rescue ActiveRecord::StatementInvalid => e
|
56
|
+
retry if defined?(PG) && e.original_exception.is_a?(PG::QueryCanceled)
|
57
|
+
timeout!
|
58
|
+
end
|
59
|
+
|
60
|
+
def pg_function
|
61
|
+
func = ['pg', 'advisory', 'lock']
|
62
|
+
func.insert(2, 'xact') if transactional?
|
63
|
+
func.insert(1, 'try') if try?
|
64
|
+
func.join('_')
|
65
|
+
end
|
66
|
+
|
67
|
+
def connection
|
68
|
+
ActiveRecord::Base.connection
|
69
|
+
end
|
70
|
+
|
71
|
+
def key
|
72
|
+
Zlib.crc32(name).to_i & 0x7fffffff
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
begin
|
3
|
+
require 'redlock'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
module Travis
|
8
|
+
module Lock
|
9
|
+
class Redis
|
10
|
+
class LockError < StandardError
|
11
|
+
def initialize(key)
|
12
|
+
super("Could not obtain lock for #{key.inspect} on Redis.")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
extend MonitorMixin
|
17
|
+
|
18
|
+
DEFAULTS = {
|
19
|
+
ttl: 5 * 60,
|
20
|
+
retries: 5,
|
21
|
+
interval: 0.1
|
22
|
+
}
|
23
|
+
|
24
|
+
attr_reader :name, :config, :retried
|
25
|
+
|
26
|
+
def initialize(name, config)
|
27
|
+
@name = name
|
28
|
+
@config = DEFAULTS.merge(config)
|
29
|
+
@retried = 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def exclusive
|
33
|
+
retrying do
|
34
|
+
client.lock(name, config[:ttl]) do |lock|
|
35
|
+
lock ? yield : raise(LockError.new(name))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def client
|
43
|
+
Redlock::Client.new([url])
|
44
|
+
end
|
45
|
+
|
46
|
+
def url
|
47
|
+
config[:url] || fail("No Redis URL specified")
|
48
|
+
end
|
49
|
+
|
50
|
+
def retrying
|
51
|
+
yield
|
52
|
+
rescue LockError
|
53
|
+
raise if retried.to_i >= config[:retries]
|
54
|
+
sleep config[:interval]
|
55
|
+
@retries = retried + 1
|
56
|
+
retry
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Travis
|
2
|
+
module Lock
|
3
|
+
class Retry < Struct.new(:name, :options)
|
4
|
+
WAIT = 0.0001..0.0009
|
5
|
+
|
6
|
+
def run
|
7
|
+
wait until result = yield
|
8
|
+
result
|
9
|
+
end
|
10
|
+
|
11
|
+
def wait
|
12
|
+
sleep(rand(options[:wait] || WAIT))
|
13
|
+
timeout! if timeout?
|
14
|
+
end
|
15
|
+
|
16
|
+
def started
|
17
|
+
@started ||= Time.now
|
18
|
+
end
|
19
|
+
|
20
|
+
def timeout?
|
21
|
+
started + timeout < Time.now
|
22
|
+
end
|
23
|
+
|
24
|
+
def timeout
|
25
|
+
options[:timeout] || 30
|
26
|
+
end
|
27
|
+
|
28
|
+
def timeout!
|
29
|
+
fail Timeout.new(name, options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/travis/lock.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'travis/lock/none'
|
2
|
+
require 'travis/lock/postgresql'
|
3
|
+
require 'travis/lock/redis'
|
4
|
+
|
5
|
+
module Travis
|
6
|
+
module Lock
|
7
|
+
class Timeout < StandardError
|
8
|
+
def initialize(name, options)
|
9
|
+
super("Could not obtain lock for #{name}: #{options.map { |*pair| pair.join('=') }.join(' ')}")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
extend self
|
14
|
+
|
15
|
+
attr_reader :default_strategy
|
16
|
+
|
17
|
+
def exclusive(name, options = {}, &block)
|
18
|
+
options[:strategy] ||= Lock.default_strategy || :none
|
19
|
+
const_get(camelize(options[:strategy])).new(name, options).exclusive(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def camelize(object)
|
25
|
+
object.to_s.split('_').collect(&:capitalize).join
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/spec/integration.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'travis/lock'
|
3
|
+
|
4
|
+
ActiveRecord::Base.establish_connection(
|
5
|
+
adapter: 'postgresql',
|
6
|
+
database: 'travis_development',
|
7
|
+
pool: 30
|
8
|
+
)
|
9
|
+
|
10
|
+
class Lock
|
11
|
+
class Redis
|
12
|
+
def exclusive(&block)
|
13
|
+
options = {
|
14
|
+
strategy: :redis,
|
15
|
+
url: 'redis://localhost:6379'
|
16
|
+
}
|
17
|
+
Travis::Lock.exclusive('test', options, &block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Postgresql
|
22
|
+
def exclusive(&block)
|
23
|
+
options = {
|
24
|
+
strategy: :postgresql,
|
25
|
+
# try: true,
|
26
|
+
try: false,
|
27
|
+
transactional: false
|
28
|
+
}
|
29
|
+
Travis::Lock.exclusive('test', options, &block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
number_of_runs = Integer(ARGV[0] || 1)
|
35
|
+
concurrency = Integer(ARGV[1] || 20)
|
36
|
+
lock_types = ARGV[2] ? [ARGV[2].to_sym] : Lock.constants
|
37
|
+
|
38
|
+
1.upto(number_of_runs) do |ix|
|
39
|
+
lock_types.each do |strategy|
|
40
|
+
puts "#{ix} Using strategy #{strategy}"
|
41
|
+
lock = Lock.const_get(strategy).new
|
42
|
+
count = 0
|
43
|
+
|
44
|
+
threads = (1..concurrency).to_a.map do
|
45
|
+
Thread.new do
|
46
|
+
lock.exclusive do
|
47
|
+
count = count.tap { sleep(rand(0.001..0.009)) } + 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
threads.map(&:join)
|
52
|
+
|
53
|
+
puts " #{count == concurrency ? "\033[32;1m" : "\033[31;1m" }Expected count to be #{concurrency}. Actually is #{count}.\033[0m\n\n"
|
54
|
+
end
|
55
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
describe Travis::Lock::Postgresql do
|
2
|
+
let(:lock) { described_class.new(name, config) }
|
3
|
+
let(:name) { 'name' }
|
4
|
+
let(:key) { 1579384326 }
|
5
|
+
|
6
|
+
def rescueing
|
7
|
+
yield
|
8
|
+
rescue Travis::Lock::Timeout
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_examples_for 'yields' do
|
12
|
+
it 'yields' do
|
13
|
+
lock.exclusive { @called = true }
|
14
|
+
expect(@called).to eq(true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context do
|
19
|
+
let(:conn) { stub('connection', select_value: 't', execute: nil) }
|
20
|
+
before { def conn.transaction; yield end }
|
21
|
+
before { ActiveRecord::Base.stubs(:connection).returns(conn) }
|
22
|
+
|
23
|
+
shared_examples_for 'locks_with' do |method|
|
24
|
+
it "locks_with #{method}" do
|
25
|
+
conn.expects(:select_value).with("select #{method}(#{key});").returns('t')
|
26
|
+
lock.exclusive { }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
shared_examples_for 'retries until timeout' do
|
31
|
+
it 'retries until timeout' do
|
32
|
+
conn.expects(:select_value).returns('f').at_least(50)
|
33
|
+
rescueing { lock.exclusive { } }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
shared_examples_for 'sets a statement level timeout' do
|
38
|
+
it 'sets a statement level timeout' do
|
39
|
+
conn.expects(:execute).with('set statement_timeout to 100;')
|
40
|
+
lock.exclusive { }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
shared_examples_for 'raises Travis::Lock::Timeout when timed out' do
|
45
|
+
it 'raises Travis::Lock::Timeout when timed out' do
|
46
|
+
conn.stubs(:select_value).returns('f')
|
47
|
+
expect { lock.exclusive { } }.to raise_error(Travis::Lock::Timeout)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'using try_*' do
|
52
|
+
describe 'not using transactions' do
|
53
|
+
let(:config) { { try: true, transactional: false, timeout: 0.1 } }
|
54
|
+
|
55
|
+
include_examples 'yields'
|
56
|
+
include_examples 'locks_with', 'pg_try_advisory_lock'
|
57
|
+
include_examples 'retries until timeout'
|
58
|
+
include_examples 'raises Travis::Lock::Timeout when timed out'
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'using transactions' do
|
62
|
+
let(:config) { { try: true, transactional: true, timeout: 0.1 } }
|
63
|
+
|
64
|
+
include_examples 'yields'
|
65
|
+
include_examples 'locks_with', 'pg_try_advisory_xact_lock'
|
66
|
+
include_examples 'retries until timeout'
|
67
|
+
include_examples 'raises Travis::Lock::Timeout when timed out'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'not using try_*' do
|
72
|
+
describe 'not using transactions' do
|
73
|
+
let(:config) { { try: false, transactional: false, timeout: 0.1 } }
|
74
|
+
|
75
|
+
include_examples 'yields'
|
76
|
+
include_examples 'locks_with', 'pg_advisory_lock'
|
77
|
+
include_examples 'sets a statement level timeout'
|
78
|
+
# include_examples 'raises Travis::Lock::Timeout when timed out'
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'using transactions' do
|
82
|
+
let(:config) { { try: false, transactional: true, timeout: 0.1 } }
|
83
|
+
|
84
|
+
include_examples 'yields'
|
85
|
+
include_examples 'locks_with', 'pg_advisory_xact_lock'
|
86
|
+
include_examples 'sets a statement level timeout'
|
87
|
+
# include_examples 'raises Travis::Lock::Timeout when timed out'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# describe 'integration' do
|
93
|
+
# shared_examples_for 'no race condition' do
|
94
|
+
# runs = ENV['RUNS'] || 1
|
95
|
+
# threads = ENV['THREADS'] || 10
|
96
|
+
|
97
|
+
# 1.upto(runs) do |ix|
|
98
|
+
# it "does not see a race condition on #{threads} threads (run #{ix})" do
|
99
|
+
# counter = 0
|
100
|
+
|
101
|
+
# Array(1..threads).map do
|
102
|
+
# Thread.new do
|
103
|
+
# lock.exclusive do
|
104
|
+
# counter = counter.tap { sleep(rand(0.001)) } + 1
|
105
|
+
# end
|
106
|
+
# end
|
107
|
+
# end.map(&:join)
|
108
|
+
|
109
|
+
# expect(counter).to eq(threads)
|
110
|
+
# end
|
111
|
+
# end
|
112
|
+
# end
|
113
|
+
|
114
|
+
# describe 'using try_*' do
|
115
|
+
# describe 'not using transactions' do
|
116
|
+
# let(:config) { { try: true, transactional: false, timeout: 0.1 } }
|
117
|
+
# include_examples 'no race condition'
|
118
|
+
# end
|
119
|
+
|
120
|
+
# describe 'using transactions' do
|
121
|
+
# let(:config) { { try: true, transactional: true, timeout: 0.1 } }
|
122
|
+
# include_examples 'no race condition'
|
123
|
+
# end
|
124
|
+
# end
|
125
|
+
|
126
|
+
# describe 'not using try_*' do
|
127
|
+
# describe 'not using transactions' do
|
128
|
+
# let(:config) { { try: false, transactional: false, timeout: 0.1 } }
|
129
|
+
# include_examples 'no race condition'
|
130
|
+
# end
|
131
|
+
|
132
|
+
# describe 'using transactions' do
|
133
|
+
# let(:config) { { try: false, transactional: true, timeout: 0.1 } }
|
134
|
+
# include_examples 'no race condition'
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
# end
|
138
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe Travis::Lock::Redis do
|
2
|
+
let(:config) { { url: 'redis://localhost' } }
|
3
|
+
let(:client) { stub('redlock', lock: nil) }
|
4
|
+
let(:lock) { described_class.new(name, config) }
|
5
|
+
let(:name) { 'name' }
|
6
|
+
|
7
|
+
it 'yields' do
|
8
|
+
lock.exclusive { @called = true }
|
9
|
+
expect(@called).to eq(true)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'delegates to a Redlock instance' do
|
13
|
+
Redlock::Client.stubs(:new).returns(client)
|
14
|
+
client.expects(:lock).with(name, 300)
|
15
|
+
lock.exclusive {}
|
16
|
+
end
|
17
|
+
end
|
data/travis-lock.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
4
|
+
require 'travis/lock/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "travis-lock"
|
8
|
+
s.version = Travis::Lock::VERSION
|
9
|
+
s.authors = ["Travis CI"]
|
10
|
+
s.email = "contact@travis-ci.org"
|
11
|
+
s.homepage = "https://github.com/travis-ci/travis-lock"
|
12
|
+
s.summary = "Travis CI config"
|
13
|
+
s.description = "#{s.summary}."
|
14
|
+
s.license = "MIT"
|
15
|
+
|
16
|
+
s.files = Dir['{lib/**/*,spec/**/*,[A-Z]*}']
|
17
|
+
s.platform = Gem::Platform::RUBY
|
18
|
+
s.require_path = 'lib'
|
19
|
+
s.rubyforge_project = '[none]'
|
20
|
+
|
21
|
+
s.add_dependency 'activerecord' , '~> 4.0'
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: travis-lock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Travis CI
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
description: Travis CI config.
|
28
|
+
email: contact@travis-ci.org
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- Gemfile
|
34
|
+
- Gemfile.lock
|
35
|
+
- README.md
|
36
|
+
- lib/travis/lock.rb
|
37
|
+
- lib/travis/lock/none.rb
|
38
|
+
- lib/travis/lock/postgresql.rb
|
39
|
+
- lib/travis/lock/redis.rb
|
40
|
+
- lib/travis/lock/support/retry.rb
|
41
|
+
- lib/travis/lock/version.rb
|
42
|
+
- spec/integration.rb
|
43
|
+
- spec/spec_helper.rb
|
44
|
+
- spec/support/database.rb
|
45
|
+
- spec/travis/lock/none_spec.rb
|
46
|
+
- spec/travis/lock/postgresql_spec.rb
|
47
|
+
- spec/travis/lock/redis_spec.rb
|
48
|
+
- travis-lock.gemspec
|
49
|
+
homepage: https://github.com/travis-ci/travis-lock
|
50
|
+
licenses:
|
51
|
+
- MIT
|
52
|
+
metadata: {}
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project: "[none]"
|
69
|
+
rubygems_version: 2.4.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 4
|
72
|
+
summary: Travis CI config
|
73
|
+
test_files: []
|
74
|
+
has_rdoc:
|