lapidarist 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/lapidarist +6 -0
- data/lapidarist.gemspec +26 -0
- data/lib/lapidarist.rb +29 -0
- data/lib/lapidarist/bundle_command.rb +49 -0
- data/lib/lapidarist/cli.rb +94 -0
- data/lib/lapidarist/configuration.rb +22 -0
- data/lib/lapidarist/gem.rb +137 -0
- data/lib/lapidarist/gems.rb +47 -0
- data/lib/lapidarist/git_command.rb +128 -0
- data/lib/lapidarist/level.rb +32 -0
- data/lib/lapidarist/logger.rb +76 -0
- data/lib/lapidarist/options.rb +79 -0
- data/lib/lapidarist/outdated.rb +37 -0
- data/lib/lapidarist/sha.rb +27 -0
- data/lib/lapidarist/shell.rb +57 -0
- data/lib/lapidarist/status.rb +16 -0
- data/lib/lapidarist/summary.rb +46 -0
- data/lib/lapidarist/test_command.rb +23 -0
- data/lib/lapidarist/update.rb +60 -0
- data/lib/lapidarist/version.rb +3 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 52a3f4f375bdf8923d629d74fbe00ebfb7e7dd84738ff6c8e3977d1be2dbcba0
|
4
|
+
data.tar.gz: f6b6ff542df51de84e710725b8a8d9bc53b9e39d529fb1c4e61cbf6eb4d1c40f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3ba56292233a696e78c23d274d8ab85d8ec04c5345d2991e2cbbae7f6b52b3dd08090c90af08eed8f63916676061f87415271dfeb6b2e6da020985cf07890f49
|
7
|
+
data.tar.gz: e09937e6620630a277868e27941fca69d893b3fb2513fa0ca24cbfdb06975c5ed238f33604297e6628d73edeaf3b185faed32ba83f55fef7043f0d255c2d25d3
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Mark Gangl
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Lapidarist
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/lapidarist`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'lapidarist'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install lapidarist
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/attack/lapidarist.
|
36
|
+
|
37
|
+
## License
|
38
|
+
|
39
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "lapidarist"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/lapidarist
ADDED
data/lapidarist.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "lapidarist/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "lapidarist"
|
7
|
+
spec.version = Lapidarist::VERSION
|
8
|
+
spec.authors = ["Mark Gangl"]
|
9
|
+
spec.email = ["mark@attackcorp.com"]
|
10
|
+
|
11
|
+
spec.summary = %q{Automatically update ruby gem dependencies.}
|
12
|
+
spec.description = %q{Sit back, relax, and allow Lapidarist to do the heavy lifiting and update your ruby gem dependencies for you.}
|
13
|
+
spec.homepage = "https://github.com/attack/lapidarist"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(spec)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
end
|
data/lib/lapidarist.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'lapidarist/version'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
require_relative 'lapidarist/configuration'
|
5
|
+
require_relative 'lapidarist/options'
|
6
|
+
require_relative 'lapidarist/level'
|
7
|
+
require_relative 'lapidarist/gem'
|
8
|
+
require_relative 'lapidarist/gems'
|
9
|
+
|
10
|
+
require_relative 'lapidarist/logger'
|
11
|
+
require_relative 'lapidarist/shell'
|
12
|
+
require_relative 'lapidarist/bundle_command'
|
13
|
+
require_relative 'lapidarist/git_command'
|
14
|
+
require_relative 'lapidarist/test_command'
|
15
|
+
require_relative 'lapidarist/update'
|
16
|
+
require_relative 'lapidarist/outdated'
|
17
|
+
require_relative 'lapidarist/sha'
|
18
|
+
|
19
|
+
require_relative 'lapidarist/summary'
|
20
|
+
require_relative 'lapidarist/status'
|
21
|
+
require_relative 'lapidarist/cli'
|
22
|
+
|
23
|
+
module Lapidarist
|
24
|
+
class << self
|
25
|
+
def config
|
26
|
+
@config ||= Lapidarist::Configuration.new
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class BundleCommand
|
3
|
+
def initialize
|
4
|
+
@shell = Shell.new
|
5
|
+
@logger = Logger.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def outdated
|
9
|
+
shell.run('cat Gemfile') if Lapidarist.config.debug
|
10
|
+
|
11
|
+
Enumerator.new do |y|
|
12
|
+
shell.run('bundle outdated --strict') do |std_out_err|
|
13
|
+
while line = std_out_err.gets
|
14
|
+
logger.std_out_err(line, 'bundle outdated')
|
15
|
+
gem = parse_gem_from(line)
|
16
|
+
y.yield(gem) if gem
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def update(gem, level: MAJOR)
|
23
|
+
shell.run("bundle update #{gem.name} --strict --#{level.to_s}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def version(gem)
|
27
|
+
stdout = shell.run('bundle list', "grep \" #{gem.name} \"")
|
28
|
+
result = stdout.match(/\((?<version>[0-9\.]+)\)/)
|
29
|
+
result[:version] if result
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :shell, :logger
|
35
|
+
|
36
|
+
def parse_gem_from(line)
|
37
|
+
regex = / \* (.*) \(newest (\d[\d\.]*\d)[,\s] installed (\d[\d\.]*\d)[\),\s](.*groups \"(.*)\")?/.match line
|
38
|
+
|
39
|
+
unless regex.nil?
|
40
|
+
Gem.new(
|
41
|
+
name: regex[1],
|
42
|
+
newest_version: regex[2],
|
43
|
+
installed_version: regex[3],
|
44
|
+
groups: Array(regex[5]&.split(',')).map(&:strip)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class CLI
|
3
|
+
def initialize(args)
|
4
|
+
@args = args
|
5
|
+
@git = GitCommand.new
|
6
|
+
@test = TestCommand.new
|
7
|
+
@outdated = Outdated.new
|
8
|
+
@update = Update.new
|
9
|
+
@sha = Sha.new
|
10
|
+
|
11
|
+
@logger = Logger.new
|
12
|
+
@logger.setup
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
Options.new(args).parse
|
17
|
+
logger.header('Starting lapidarist')
|
18
|
+
logger.debug("directory: #{Lapidarist.config.directory}", :options)
|
19
|
+
logger.debug("test_script: #{Lapidarist.config.test_script}", :options)
|
20
|
+
|
21
|
+
unless git.clean?
|
22
|
+
logger.footer('stopping, there are uncommitted changes')
|
23
|
+
return 1
|
24
|
+
end
|
25
|
+
|
26
|
+
sha.record_good
|
27
|
+
gems = outdated.run
|
28
|
+
|
29
|
+
status = nil
|
30
|
+
1.step do |attempt|
|
31
|
+
logger.header("Attempt ##{attempt}")
|
32
|
+
|
33
|
+
if gems.outdated.none?
|
34
|
+
logger.footer('stopping, there are no applicable outdated gems')
|
35
|
+
status = Status.new(gems, attempt)
|
36
|
+
break
|
37
|
+
end
|
38
|
+
|
39
|
+
updated_gems = update.run(gems, attempt)
|
40
|
+
|
41
|
+
if sha.new_commit_count.zero?
|
42
|
+
logger.footer('nothing updated, trying again')
|
43
|
+
gems = gems.merge(updated_gems)
|
44
|
+
next
|
45
|
+
end
|
46
|
+
|
47
|
+
logger.header("Testing gem updates")
|
48
|
+
if test.success?
|
49
|
+
logger.footer('test passed, nothing left to do')
|
50
|
+
gems = gems.merge(updated_gems)
|
51
|
+
status = Status.new(gems, attempt)
|
52
|
+
break
|
53
|
+
else
|
54
|
+
logger.footer('test failed, investigating failure')
|
55
|
+
end
|
56
|
+
|
57
|
+
failed_gem =
|
58
|
+
if updated_gems.one?
|
59
|
+
updated_but_failed_gem = updated_gems.first
|
60
|
+
git.reset_hard('HEAD^')
|
61
|
+
|
62
|
+
Gem.from(
|
63
|
+
updated_but_failed_gem,
|
64
|
+
attempt: attempt,
|
65
|
+
status: :failed,
|
66
|
+
updated_version: updated_but_failed_gem.latest_attempt[:version],
|
67
|
+
level: updated_but_failed_gem.latest_attempt[:level]
|
68
|
+
)
|
69
|
+
else
|
70
|
+
failed_gem_name = git.bisect(sha.last_good, test)
|
71
|
+
updated_but_failed_gem = updated_gems.detect { |g| g.name == failed_gem_name }
|
72
|
+
gems = gems.merge(updated_gems.take(sha.new_commit_count))
|
73
|
+
sha.record_good
|
74
|
+
|
75
|
+
Gem.from(
|
76
|
+
updated_but_failed_gem,
|
77
|
+
attempt: attempt,
|
78
|
+
status: :failed,
|
79
|
+
updated_version: updated_but_failed_gem.latest_attempt[:version],
|
80
|
+
level: updated_but_failed_gem.latest_attempt[:level]
|
81
|
+
)
|
82
|
+
end
|
83
|
+
gems = gems.merge(failed_gem)
|
84
|
+
end
|
85
|
+
|
86
|
+
Summary.new(gems, logger).display
|
87
|
+
return status.to_i
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
attr_reader :args, :git, :test, :outdated, :update, :sha, :logger
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Lapidarist
|
4
|
+
class Configuration < OpenStruct
|
5
|
+
def initialize
|
6
|
+
super(
|
7
|
+
directory: Pathname.new('.'),
|
8
|
+
test_script: 'test.sh',
|
9
|
+
all: false,
|
10
|
+
quiet: false,
|
11
|
+
verbosity: 0,
|
12
|
+
commit_flags: '',
|
13
|
+
debug: false,
|
14
|
+
log_path: Pathname.new('./tmp/lapidarist.log'),
|
15
|
+
update_limit: nil,
|
16
|
+
groups: [],
|
17
|
+
version: MAJOR,
|
18
|
+
recursive: false
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class Gem
|
3
|
+
attr_reader :name, :newest_version, :installed_version, :attempts
|
4
|
+
|
5
|
+
def initialize(name:, newest_version:, installed_version:, groups: [], attempts: {})
|
6
|
+
@name = name
|
7
|
+
@newest_version = newest_version
|
8
|
+
@installed_version = installed_version
|
9
|
+
@groups = groups
|
10
|
+
@attempts = attempts
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.from(gem, attempt: 0, status: nil, reason: nil, updated_version: nil, level: nil)
|
14
|
+
attempts = gem.attempts
|
15
|
+
|
16
|
+
if status
|
17
|
+
attempts = attempts.merge(
|
18
|
+
attempt => {
|
19
|
+
status: status,
|
20
|
+
reason: reason,
|
21
|
+
version: updated_version,
|
22
|
+
level: level
|
23
|
+
}
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
new(
|
28
|
+
name: gem.name,
|
29
|
+
newest_version: gem.newest_version,
|
30
|
+
installed_version: gem.installed_version,
|
31
|
+
groups: gem.groups,
|
32
|
+
attempts: attempts
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(other_gem)
|
37
|
+
current_status == other_gem.current_status &&
|
38
|
+
name == other_gem.name &&
|
39
|
+
installed_version == other_gem.installed_version &&
|
40
|
+
newest_version == other_gem.newest_version &&
|
41
|
+
groups == other_gem.groups
|
42
|
+
end
|
43
|
+
|
44
|
+
def groups
|
45
|
+
@groups.sort
|
46
|
+
end
|
47
|
+
|
48
|
+
def dependency?
|
49
|
+
groups.any?
|
50
|
+
end
|
51
|
+
|
52
|
+
def current_status
|
53
|
+
latest_attempt&.fetch(:status, nil)
|
54
|
+
end
|
55
|
+
|
56
|
+
def current_level
|
57
|
+
latest_attempt&.fetch(:level, nil)
|
58
|
+
end
|
59
|
+
|
60
|
+
def outdated?(recursive: false)
|
61
|
+
current_status.nil? || (recursive && available_update_levels?)
|
62
|
+
end
|
63
|
+
|
64
|
+
def failed?
|
65
|
+
current_status == :failed
|
66
|
+
end
|
67
|
+
|
68
|
+
def skip?
|
69
|
+
current_status == :skipped
|
70
|
+
end
|
71
|
+
|
72
|
+
def updated?
|
73
|
+
current_status == :updated
|
74
|
+
end
|
75
|
+
|
76
|
+
def updated_version
|
77
|
+
updated_attempt&.fetch(:version, nil)
|
78
|
+
end
|
79
|
+
|
80
|
+
def what_changed
|
81
|
+
if version_changed?
|
82
|
+
"#{name} from #{installed_version} to #{updated_version}"
|
83
|
+
else
|
84
|
+
"#{name} dependencies"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def available_update_levels?
|
89
|
+
failed? && current_level > PATCH
|
90
|
+
end
|
91
|
+
|
92
|
+
def next_semver_level
|
93
|
+
if current_level
|
94
|
+
LEVELS.detect { |level| level < current_level }
|
95
|
+
else
|
96
|
+
MAJOR
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def log_s
|
101
|
+
[
|
102
|
+
"outdated gem: #{name}",
|
103
|
+
"installed: #{installed_version}",
|
104
|
+
"newest: #{newest_version}",
|
105
|
+
"updated: #{updated_version}"
|
106
|
+
].join(', ')
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_h
|
110
|
+
{
|
111
|
+
name: name,
|
112
|
+
newest_version: newest_version,
|
113
|
+
installed_version: installed_version,
|
114
|
+
groups: groups,
|
115
|
+
attempts: attempts.to_h
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
def latest_attempt_number
|
120
|
+
@latest_attempt_number ||= attempts.keys.last
|
121
|
+
end
|
122
|
+
|
123
|
+
def latest_attempt
|
124
|
+
@latest_attempt ||= attempts[latest_attempt_number] || {}
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def version_changed?
|
130
|
+
updated_version && installed_version != updated_version
|
131
|
+
end
|
132
|
+
|
133
|
+
def updated_attempt
|
134
|
+
@updated_attempt ||= attempts.values.detect { |a| a[:status] == :updated }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class Gems
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize(gems)
|
6
|
+
@gems = gems
|
7
|
+
end
|
8
|
+
|
9
|
+
def each(&block)
|
10
|
+
gems.sort_by(&:name).each(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def outdated
|
14
|
+
entries.select do |gem|
|
15
|
+
if (Lapidarist.config.all || gem.dependency?) && gem.outdated?(recursive: Lapidarist.config.recursive)
|
16
|
+
gem
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def updated
|
22
|
+
entries.select(&:updated?)
|
23
|
+
end
|
24
|
+
|
25
|
+
def skipped
|
26
|
+
entries.select(&:skip?)
|
27
|
+
end
|
28
|
+
|
29
|
+
def failed
|
30
|
+
entries.select(&:failed?)
|
31
|
+
end
|
32
|
+
|
33
|
+
def merge(other_gems)
|
34
|
+
Gems.new(
|
35
|
+
Array(other_gems) + entries.select { |gem| !Array(other_gems).map(&:name).include?(gem.name) }
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def attempts
|
40
|
+
entries.map(&:latest_attempt_number).compact.max
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
attr_reader :gems
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class GitCommand
|
3
|
+
def initialize
|
4
|
+
@shell = Shell.new
|
5
|
+
@logger = Logger.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def head
|
9
|
+
shell.run('git rev-parse HEAD')[0].strip
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(*files)
|
13
|
+
shell.run("git add #{files.join(' ')}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def commit(message)
|
17
|
+
shell.run("git commit -m '#{message}' #{Lapidarist.config.commit_flags}".strip, label: 'git commit')
|
18
|
+
end
|
19
|
+
|
20
|
+
def bisect(start_sha, test)
|
21
|
+
logger.header('Starting bisect')
|
22
|
+
bisect_start(start_sha)
|
23
|
+
bisect_run(start_sha, test)
|
24
|
+
end
|
25
|
+
|
26
|
+
def log(sha)
|
27
|
+
shell.run("git log HEAD...#{sha}^ --no-color --oneline", label: 'git log')
|
28
|
+
end
|
29
|
+
|
30
|
+
def reset_hard(ref)
|
31
|
+
shell.run("git reset --hard #{ref}")
|
32
|
+
end
|
33
|
+
|
34
|
+
def clean?
|
35
|
+
shell.run('[ -z "$(git status --porcelain)" ]')[1] == 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def count_commits(start_sha, end_sha)
|
39
|
+
shell.run("git rev-list #{end_sha} ^#{start_sha} --count")[0].to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :shell, :logger
|
45
|
+
|
46
|
+
def bisect_start(sha)
|
47
|
+
shell.run('git bisect start')
|
48
|
+
shell.run('git bisect bad')
|
49
|
+
shell.run("git bisect good #{sha}", label: 'git bisect good')
|
50
|
+
end
|
51
|
+
|
52
|
+
def bisect_run(start_sha, test)
|
53
|
+
failing_gem_name = nil
|
54
|
+
|
55
|
+
shell.run("git bisect run #{test}") do |std_out_err|
|
56
|
+
while line = std_out_err.gets
|
57
|
+
bisect_step = BisectStep.new(line, shell)
|
58
|
+
|
59
|
+
if bisect_step.failure?
|
60
|
+
failing_sha = bisect_step.failing_sha
|
61
|
+
failing_gem_name = bisect_step.failing_gem(failing_sha)
|
62
|
+
logger.info("... found failing gem update: #{failing_gem_name}")
|
63
|
+
end
|
64
|
+
|
65
|
+
if bisect_step.success?
|
66
|
+
bisect_reset
|
67
|
+
rewind_to_last_good_commit(failing_sha)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
unless failing_gem_name
|
72
|
+
logger.info("... last commit was failing commit")
|
73
|
+
end
|
74
|
+
|
75
|
+
logger.footer("bisect done")
|
76
|
+
end
|
77
|
+
|
78
|
+
if failing_gem_name && Lapidarist.config.debug
|
79
|
+
log(start_sha)
|
80
|
+
end
|
81
|
+
|
82
|
+
failing_gem_name
|
83
|
+
end
|
84
|
+
|
85
|
+
def bisect_reset
|
86
|
+
shell.run('git bisect reset')
|
87
|
+
end
|
88
|
+
|
89
|
+
def rewind_to_last_good_commit(sha)
|
90
|
+
reset_hard("#{sha}^")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class BisectStep
|
95
|
+
def initialize(line, shell)
|
96
|
+
@line = line
|
97
|
+
@shell = shell
|
98
|
+
end
|
99
|
+
|
100
|
+
def success?
|
101
|
+
line == "bisect run success\n"
|
102
|
+
end
|
103
|
+
|
104
|
+
def failure?
|
105
|
+
!failing_sha.nil?
|
106
|
+
end
|
107
|
+
|
108
|
+
def failing_sha
|
109
|
+
sha_regex = Regexp::new("(.*) is the first bad commit\n").match(line)
|
110
|
+
unless sha_regex.nil?
|
111
|
+
sha_regex[1]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def failing_gem(sha)
|
116
|
+
commit_message = shell.run("git log --format=%s -n 1 #{sha}", label: 'git log')[0]
|
117
|
+
|
118
|
+
sha_regex = Regexp::new('Update (.*) from').match(commit_message)
|
119
|
+
unless sha_regex.nil?
|
120
|
+
sha_regex[1]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
attr_reader :shell, :line
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class Level
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
attr_reader :index
|
6
|
+
|
7
|
+
def initialize(name:, index:)
|
8
|
+
@name = name
|
9
|
+
@index = index
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
name.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def <=>(other)
|
17
|
+
return 1 if index < other.index
|
18
|
+
return 0 if index == other.index
|
19
|
+
return -1 if index > other.index
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :name
|
25
|
+
end
|
26
|
+
|
27
|
+
MAJOR = Level.new(name: :major, index: 1)
|
28
|
+
MINOR = Level.new(name: :minor, index: 2)
|
29
|
+
PATCH = Level.new(name: :patch, index: 3)
|
30
|
+
|
31
|
+
LEVELS = [MAJOR, MINOR, PATCH].freeze
|
32
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class Logger
|
3
|
+
def header(message)
|
4
|
+
write '', 0
|
5
|
+
write "#{message} ...", 0
|
6
|
+
end
|
7
|
+
|
8
|
+
def smart_header(message)
|
9
|
+
if Lapidarist.config.verbosity > 0
|
10
|
+
header(message)
|
11
|
+
else
|
12
|
+
info(message, 0)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def footer(message)
|
17
|
+
write "... #{message}", 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def info(message, level = 0)
|
21
|
+
write message, level
|
22
|
+
end
|
23
|
+
|
24
|
+
def debug(message, label = nil)
|
25
|
+
return unless Lapidarist.config.debug
|
26
|
+
|
27
|
+
if label
|
28
|
+
puts " DEBUG (#{label}) > #{message}"
|
29
|
+
else
|
30
|
+
puts " DEBUG > #{message}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def std_out_err(message, command)
|
35
|
+
write "OUT_ERR (#{command}) > #{message.strip}", 2
|
36
|
+
end
|
37
|
+
|
38
|
+
def setup
|
39
|
+
if Lapidarist.config.log_path && !Lapidarist.config.log_path.empty?
|
40
|
+
Open3.capture2("mkdir -p #{Lapidarist.config.log_path.dirname}", chdir: Lapidarist.config.directory)
|
41
|
+
Open3.capture2("touch #{Lapidarist.config.log_path}", chdir: Lapidarist.config.directory)
|
42
|
+
clear_log_file
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def summary(message)
|
47
|
+
write_std_out(message, 0)
|
48
|
+
write_log_file(message)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def write(message, level)
|
54
|
+
log_line = "#{' ' * level}#{message}"
|
55
|
+
|
56
|
+
write_std_out(log_line, level)
|
57
|
+
write_log_file(log_line)
|
58
|
+
end
|
59
|
+
|
60
|
+
def write_std_out(message, level)
|
61
|
+
if level <= Lapidarist.config.verbosity && !Lapidarist.config.quiet
|
62
|
+
puts message
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def clear_log_file
|
67
|
+
Open3.capture2("cp /dev/null #{Lapidarist.config.log_path}", chdir: Lapidarist.config.directory)
|
68
|
+
end
|
69
|
+
|
70
|
+
def write_log_file(message)
|
71
|
+
if Lapidarist.config.log_path && !Lapidarist.config.log_path.empty?
|
72
|
+
Open3.capture2("echo \"#{message}\" >> #{Lapidarist.config.log_path}", chdir: Lapidarist.config.directory)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Lapidarist
|
4
|
+
class Options
|
5
|
+
def initialize(args)
|
6
|
+
@args = args
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse
|
10
|
+
opt_parser = OptionParser.new do |opts|
|
11
|
+
opts.on("-d", "--directory DIRECTORY", "Directory to run Lapidarist from.") do |d|
|
12
|
+
Lapidarist.config.directory = Pathname.new(d)
|
13
|
+
end
|
14
|
+
|
15
|
+
opts.on("-t", "--test TEST_SCRIPT", "Test script given to git bisect.") do |t|
|
16
|
+
Lapidarist.config.test_script = t
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on("-a", "--all", "Update gems that are sub-dependencies.") do |t|
|
20
|
+
Lapidarist.config.all = true
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("-q", "--quiet", "Do not print anything to stdout.") do |t|
|
24
|
+
Lapidarist.config.quiet = true
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-v", "Increase verbosity, repeat for more verbosity.") do |t|
|
28
|
+
Lapidarist.config.verbosity += 1
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-f", "--commit-flags flags", "Append flags to the commit command.") do |t|
|
32
|
+
Lapidarist.config.commit_flags = t
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("--debug", "Display debug output.") do |t|
|
36
|
+
Lapidarist.config.debug = true
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-l LOG_PATH", "Path to log file") do |t|
|
40
|
+
Lapidarist.config.log_path = t
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-n NUMBER_OF_GEMS", "Limit the number of gems to be updated.") do |t|
|
44
|
+
Lapidarist.config.update_limit = t.to_i
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("--one", "Limit the number of gems to be updated to just one.") do |t|
|
48
|
+
Lapidarist.config.update_limit = 1
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on("-g GROUP_NAME", "--group GROUP_NAME", "Limit gems to be updated to a specified group(s).") do |g|
|
52
|
+
Lapidarist.config.groups << g
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("--major", "Limit updates to major, minor and patch versions (essentially everything).") do |p|
|
56
|
+
Lapidarist.config.version = MAJOR
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on("--minor", "Limit updates to minor and patch versions.") do |p|
|
60
|
+
Lapidarist.config.version = MINOR
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("--patch", "Limit updates to patch versions.") do |p|
|
64
|
+
Lapidarist.config.version = PATCH
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on("-r", "--recursive", "Try updating a the major version, minor version then patch version.") do |t|
|
68
|
+
Lapidarist.config.recursive = true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
opt_parser.parse!(args)
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
attr_reader :args
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class Outdated
|
3
|
+
def initialize
|
4
|
+
@bundle = BundleCommand.new
|
5
|
+
@logger = Logger.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
logger.header('Detecting outdated gems')
|
10
|
+
|
11
|
+
gems = bundle.outdated.each_with_object([]) do |gem, results|
|
12
|
+
reason = reason_to_skip(gem)
|
13
|
+
if reason.nil?
|
14
|
+
logger.info(" + #{gem.log_s}")
|
15
|
+
results.push Gem.from(gem)
|
16
|
+
else
|
17
|
+
logger.info(" - (#{reason}) #{gem.log_s}")
|
18
|
+
results.push Gem.from(gem, status: :skipped, reason: reason)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Gems.new(gems)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :bundle, :logger
|
28
|
+
|
29
|
+
def reason_to_skip(gem)
|
30
|
+
if !Lapidarist.config.all && !gem.dependency?
|
31
|
+
:sub_dependency
|
32
|
+
elsif Lapidarist.config.groups.any? && (Lapidarist.config.groups & gem.groups).none?
|
33
|
+
:unmatched_group
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class Sha
|
3
|
+
def initialize
|
4
|
+
@good_shas = []
|
5
|
+
@git = GitCommand.new
|
6
|
+
@logger = Logger.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def record_good
|
10
|
+
good_sha = git.head
|
11
|
+
logger.debug("good sha: #{good_sha}")
|
12
|
+
@good_shas << good_sha
|
13
|
+
end
|
14
|
+
|
15
|
+
def last_good
|
16
|
+
good_shas.last
|
17
|
+
end
|
18
|
+
|
19
|
+
def new_commit_count
|
20
|
+
git.count_commits(last_good, 'HEAD')
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :good_shas, :git, :logger
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class Shell
|
3
|
+
def initialize
|
4
|
+
@logger = Logger.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def run(*commands, label: nil, &block)
|
8
|
+
if commands.one?
|
9
|
+
run_single_command(commands.first, label, &block)
|
10
|
+
else
|
11
|
+
pipe_multiple_commands(*commands, &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :logger
|
18
|
+
|
19
|
+
def run_single_command(command, label)
|
20
|
+
logger.info "COMMAND > `#{command}`", 1
|
21
|
+
|
22
|
+
if block_given?
|
23
|
+
Open3.popen2e(command, chdir: Lapidarist.config.directory) do |_std_in, std_out_err|
|
24
|
+
yield(std_out_err)
|
25
|
+
end
|
26
|
+
else
|
27
|
+
out_err = []
|
28
|
+
|
29
|
+
status = Open3.popen2e(command, chdir: Lapidarist.config.directory) do |_std_in, std_out_err, wait_thr|
|
30
|
+
while line = std_out_err.gets
|
31
|
+
logger.std_out_err(line, label || command)
|
32
|
+
out_err << line
|
33
|
+
end
|
34
|
+
wait_thr.value
|
35
|
+
end
|
36
|
+
|
37
|
+
logger.info "STATUS > #{status}", 2
|
38
|
+
|
39
|
+
[out_err.join("\n"), status]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def pipe_multiple_commands(*commands)
|
44
|
+
if block_given?
|
45
|
+
Open3.pipeline_r(*commands, chdir: Lapidarist.config.directory) do |std_out, _ts|
|
46
|
+
yield(std_out)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
output = ''
|
50
|
+
Open3.pipeline_r(*commands, chdir: Lapidarist.config.directory) do |std_out, _ts|
|
51
|
+
output = std_out.read
|
52
|
+
end
|
53
|
+
output
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class Summary
|
3
|
+
def initialize(gems, logger)
|
4
|
+
@gems = gems
|
5
|
+
@logger = logger
|
6
|
+
end
|
7
|
+
|
8
|
+
def display
|
9
|
+
logger.summary ''
|
10
|
+
logger.summary 'Summary'
|
11
|
+
logger.summary '-'*50
|
12
|
+
logger.summary "#{object_count(gems.updated, 'gem', 'gems')} updated, #{object_count(gems.failed, 'gem', 'gems')} failed and #{object_count(gems.skipped, 'gem', 'gems')} skipped in #{object_count(gems.attempts, 'attempt', 'attempts')}"
|
13
|
+
gems.each do |gem|
|
14
|
+
gem.attempts.each do |i, data|
|
15
|
+
case data[:status]
|
16
|
+
when :updated
|
17
|
+
logger.summary " + updated #{gem.name} from #{gem.installed_version} to #{data[:version]}"
|
18
|
+
when :failed
|
19
|
+
logger.summary " x failed #{gem.name} from #{gem.installed_version} to #{data[:version]}"
|
20
|
+
when :skipped
|
21
|
+
logger.summary " - skipped #{gem.name} (#{data[:reason]})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :gems, :logger
|
30
|
+
|
31
|
+
def object_count(objects_or_length, singlular, plural)
|
32
|
+
length =
|
33
|
+
if objects_or_length.respond_to?(:length)
|
34
|
+
objects_or_length.length
|
35
|
+
else
|
36
|
+
objects_or_length
|
37
|
+
end
|
38
|
+
|
39
|
+
if length == 1
|
40
|
+
"1 #{singlular}"
|
41
|
+
else
|
42
|
+
"#{length} #{plural}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class TestCommand
|
3
|
+
def initialize
|
4
|
+
@shell = Shell.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def run
|
8
|
+
shell.run(to_s)[1]
|
9
|
+
end
|
10
|
+
|
11
|
+
def success?
|
12
|
+
run == 0
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
Lapidarist.config.test_script
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :shell
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Lapidarist
|
2
|
+
class Update
|
3
|
+
def initialize
|
4
|
+
@bundle = BundleCommand.new
|
5
|
+
@git = GitCommand.new
|
6
|
+
@logger = Logger.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(gems, attempt)
|
10
|
+
before_sha = git.head if Lapidarist.config.debug
|
11
|
+
|
12
|
+
logger.header('Updating outdated gems')
|
13
|
+
|
14
|
+
limit =
|
15
|
+
if Lapidarist.config.update_limit
|
16
|
+
[Lapidarist.config.update_limit - gems.updated.length, 0].max
|
17
|
+
else
|
18
|
+
gems.outdated.length
|
19
|
+
end
|
20
|
+
|
21
|
+
updated_gems = gems.outdated.take(limit).map do |outdated_gem|
|
22
|
+
update_gem(outdated_gem, attempt)
|
23
|
+
end
|
24
|
+
|
25
|
+
git.log(before_sha) if Lapidarist.config.debug
|
26
|
+
|
27
|
+
updated_gems
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :outdated_gems, :bundle, :git, :logger
|
33
|
+
|
34
|
+
def update_gem(outdated_gem, attempt)
|
35
|
+
logger.smart_header "Updating #{outdated_gem.name} from #{outdated_gem.installed_version}"
|
36
|
+
|
37
|
+
available_semver_levels = [Lapidarist.config.version]
|
38
|
+
available_semver_levels << outdated_gem.next_semver_level if Lapidarist.config.recursive
|
39
|
+
semver_level_restriction = available_semver_levels.compact.min
|
40
|
+
|
41
|
+
bundle.update(outdated_gem, level: semver_level_restriction)
|
42
|
+
updated_version = bundle.version(outdated_gem)
|
43
|
+
|
44
|
+
if git.clean?
|
45
|
+
skipped_gem = Gem.from(outdated_gem, attempt: attempt, status: :skipped, reason: :nothing_to_update)
|
46
|
+
logger.footer "nothing to update for #{skipped_gem.name}"
|
47
|
+
|
48
|
+
skipped_gem
|
49
|
+
else
|
50
|
+
updated_gem = Gem.from(outdated_gem, attempt: attempt, status: :updated, updated_version: updated_version, level: semver_level_restriction)
|
51
|
+
logger.footer "updated #{updated_gem.name} to #{updated_gem.updated_version}"
|
52
|
+
|
53
|
+
git.add('Gemfile', 'Gemfile.lock')
|
54
|
+
git.commit("Update #{updated_gem.what_changed}")
|
55
|
+
|
56
|
+
updated_gem
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lapidarist
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mark Gangl
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-08-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: Sit back, relax, and allow Lapidarist to do the heavy lifiting and update
|
56
|
+
your ruby gem dependencies for you.
|
57
|
+
email:
|
58
|
+
- mark@attackcorp.com
|
59
|
+
executables:
|
60
|
+
- lapidarist
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- ".gitignore"
|
65
|
+
- ".rspec"
|
66
|
+
- ".travis.yml"
|
67
|
+
- Gemfile
|
68
|
+
- LICENSE.txt
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- bin/console
|
72
|
+
- bin/setup
|
73
|
+
- exe/lapidarist
|
74
|
+
- lapidarist.gemspec
|
75
|
+
- lib/lapidarist.rb
|
76
|
+
- lib/lapidarist/bundle_command.rb
|
77
|
+
- lib/lapidarist/cli.rb
|
78
|
+
- lib/lapidarist/configuration.rb
|
79
|
+
- lib/lapidarist/gem.rb
|
80
|
+
- lib/lapidarist/gems.rb
|
81
|
+
- lib/lapidarist/git_command.rb
|
82
|
+
- lib/lapidarist/level.rb
|
83
|
+
- lib/lapidarist/logger.rb
|
84
|
+
- lib/lapidarist/options.rb
|
85
|
+
- lib/lapidarist/outdated.rb
|
86
|
+
- lib/lapidarist/sha.rb
|
87
|
+
- lib/lapidarist/shell.rb
|
88
|
+
- lib/lapidarist/status.rb
|
89
|
+
- lib/lapidarist/summary.rb
|
90
|
+
- lib/lapidarist/test_command.rb
|
91
|
+
- lib/lapidarist/update.rb
|
92
|
+
- lib/lapidarist/version.rb
|
93
|
+
homepage: https://github.com/attack/lapidarist
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.7.6
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: Automatically update ruby gem dependencies.
|
117
|
+
test_files: []
|