lapidarist 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1105156709cc99e5c061836d1815d84721de11b80ae92f90e9404fa9461f7f49
4
- data.tar.gz: b2cbcbe7c210fefcbd870baa5c9de71d5ce4065f9e208a8f36359e6a7daeea05
3
+ metadata.gz: 99fe161d7e3d3242d0d10b602695450f45ce091fff7a7145ed5a4276fe492752
4
+ data.tar.gz: c17bebcb2a4950bff0a72ced8081ff3f66c4b8f1159b69c3f6e2ada8e68a7eba
5
5
  SHA512:
6
- metadata.gz: c4bc4c2ca10de53d0d6af8ff6154290171870029fa72366347577aad742f36e0e6ef7acf43ede35df0c03f789bf016b321748d897d16995c038b068833bf8cd8
7
- data.tar.gz: 62dc6f447328f0ce79287c826a716126a6cffe689216724b58416d2c2a3f330580a9de558cf89829456359b2ddfc80287688585de4e2291ce9fb6116b60fd1c7
6
+ metadata.gz: f3f8ae3c3281d86276683334fd3c26bcb87d00d0473ae880a4d9476e696c3f5562259d125284e4c084a897e526a7b8ebef51c729c84255ce66fad6d30b7a9155
7
+ data.tar.gz: be46e3ffcddcba98f2278e9ef879b2ea1bd63877041ad5b86601d5390bb97da1c5f96c8f028cead290362f689165736030b300b20d39d11021e4627206d5789f
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## master (unreleased)
4
4
 
5
+ * errors return status of 2 instead of 1
6
+ * capture invalid option error, and display message
7
+ * capture interrupt and clean up git commits
8
+
9
+ ### Bug fixes
10
+
11
+ * when the version doesn't change (but dependencies do), do not attempt any more recursive updates
12
+
5
13
  ### New features
6
14
 
7
15
  ## 0.1.1 (2018-08-11)
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![CircleCI](https://circleci.com/gh/attack/lapidarist.svg?style=svg)](https://circleci.com/gh/attack/lapidarist)
4
4
 
5
- Take the manual work out of updaeting your ruby gems, and let Lapidarist do the work.
5
+ Take the manual work out of updating your ruby gems, and let Lapidarist do the work.
6
6
 
7
7
  You can run it from the command line yourself to update the gems of your project, or
8
8
  automate it to run and update for you.
@@ -31,11 +31,132 @@ Lapidarist depends on `bundler` and `git`.
31
31
  lapidarist -d . -t 'rspec spec' --all
32
32
  ```
33
33
 
34
+ ### Options
35
+
34
36
  To see all the options available
35
37
  ```sh
36
38
  lapidarist -h
37
39
  ```
38
40
 
41
+ #### `-t`, `--test TEST_SCRIPT`
42
+
43
+ Test script to assert that the gems updates are safe to commit.
44
+ This is run after any batch of updates, or during git bisect to investigate a
45
+ failing update.
46
+
47
+ #### `-a`, `--all`
48
+
49
+ By default, Lapidarist will only update gems that are listed in the Gemfile.
50
+ Use this option to also selectively update gems (or sub-dependencies) that are
51
+ not listed in the Gemfile.
52
+
53
+ #### `-q`, `--quiet`
54
+
55
+ Do not print anything to stdout. This will take precedence over logging
56
+ verbosity levels and debugging output.
57
+
58
+ #### `-v`
59
+
60
+ Increase verbosity of stdout output. Repeat this option up to three times
61
+ for to control the level of detail.
62
+
63
+ #### `-f`, `--commit-flags`
64
+
65
+ When Lapidarist commits gem updates extra flags can be requested to append
66
+ to this command. A common use case is to bypass local git hooks with `--no-verify`.
67
+
68
+ #### `-l`
69
+
70
+ Path to log file. This is location where Lapidarist will write a log with full
71
+ verbosity. This file will be reset for each run.
72
+
73
+ #### `-n`
74
+
75
+ By default, Lapidarist will attempt to update all outdated gems. Use this option
76
+ to limit the number of gems that are updated to a maximum number.
77
+
78
+ #### `--one`, `-n 1`
79
+
80
+ This is the same as `-n 1`, and limits Lapidarist to only update one gem.
81
+
82
+ #### `-g`, `--group`
83
+
84
+ Limit gems to be updated to a specified group(s). Multiple groups can be can
85
+ be permitted by using this option multiple times.
86
+
87
+ #### `--major`, `--minor`, `--patch`
88
+
89
+ Limit gem updates to a specific maximum level. This option is passed directly to
90
+ `bundle update` and follows the logic controlled by bundler.
91
+
92
+ #### `-r`, `--recursive`
93
+
94
+ By default, Lapidarist will only try to update a gem once. With this option,
95
+ if an update fails then Lapidarist will try again using a lower maximum level.
96
+ For example, if a gem had updates available at a patch level, a minor level and
97
+ a major level, and an update failed when updating to the major level, then with
98
+ this option Lapidarist will try again at the minor then patch levels until all
99
+ levels are exhausted or an update is accepted.
100
+
101
+ This option will respect the maximum update level option, and will only try
102
+ lower available levels, if any.
103
+
104
+ #### `-o`, `--ordered`
105
+
106
+ By default, Lapidarist will randomize the order of gems it attempts to update.
107
+ This option can be used to prevent randomization and force Lapidarist to respect
108
+ the order from `bundle outdated`, which is essentially in alphabetical order.
109
+
110
+ #### `--seed`
111
+
112
+ By default, Lapidarist will randomize the order of gems it attempts to update
113
+ with a randomly generated seed. This option can be used to control the seed and
114
+ thus the resulting random order.
115
+
116
+ #### `--promote`
117
+
118
+ By default, Lapidarist will randomize the order of all gems it attempts to update.
119
+ With this option gems can be promoted to the top of the order so that the specified
120
+ gem(s) will be updated first before any non-promoted gems.
121
+
122
+ This option can be a comma delimited list or the result of using this option
123
+ multiple times.
124
+
125
+ #### `--demote`
126
+
127
+ By default, Lapidarist will randomize the order of all gems it attempts to update.
128
+ With this option gems can be demoted to the bottom of the order so that the specified
129
+ gem(s) will be updated last after any non-demoted gems.
130
+
131
+ This option can be a comma delimited list or the result of using this option
132
+ multiple times.
133
+
134
+ If a gem is both promoted and demoted, then demoted will be preferred and the
135
+ promotion will be ignored.
136
+
137
+ #### `--only`
138
+
139
+ By default, Lapidarist will attempt to update all outdated gems. With this
140
+ option Lapidarist will only attempt to update the outdated gems that match
141
+ those specified, and ignore updating any other gems.
142
+
143
+ This option can be a comma delimited list or the result of using this option
144
+ multiple times.
145
+
146
+ #### `--except`
147
+
148
+ By default, Lapidarist will attempt to update all outdated gems. With this
149
+ option Lapidarist will attempt to update the all outdated gems except those that
150
+ match the ones specified.
151
+
152
+ This option can be a comma delimited list or the result of using this option
153
+ multiple times.
154
+
155
+ If both `--only` and `--except` are given, then a hybrid of the two options will
156
+ be used, essentially behaving like `--only` but excluding any gems provided
157
+ using `--except` (ie `lapidarist --only foo,bar --except foo` is equivalent to
158
+ `lapidarist --only bar`)
159
+
39
160
  ## Development
40
161
 
41
162
  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.
@@ -19,12 +19,20 @@ require_relative 'lapidarist/test_command'
19
19
  require_relative 'lapidarist/update'
20
20
  require_relative 'lapidarist/outdated'
21
21
  require_relative 'lapidarist/sha'
22
+ require_relative 'lapidarist/find_failure'
22
23
 
24
+ require_relative 'lapidarist/threads'
23
25
  require_relative 'lapidarist/summary'
24
26
  require_relative 'lapidarist/status'
25
27
  require_relative 'lapidarist/cli'
26
28
 
27
29
  module Lapidarist
30
+ STATUS_SUCCESS = 0
31
+ STATUS_FAILED = 1
32
+ STATUS_ERROR = 2
33
+
34
+ class Abort < StandardError; end
35
+
28
36
  class << self
29
37
  def config
30
38
  @config ||= Lapidarist::Configuration.new
@@ -33,5 +41,9 @@ module Lapidarist
33
41
  def logger
34
42
  @logger ||= Lapidarist::Logger.new.tap { |l| l.setup }
35
43
  end
44
+
45
+ def threads
46
+ @threads ||= Lapidarist::Threads.new
47
+ end
36
48
  end
37
49
  end
@@ -4,7 +4,6 @@ module Lapidarist
4
4
  @args = args
5
5
  @git = GitCommand.new
6
6
  @test = TestCommand.new
7
- @outdated = Outdated.new
8
7
  @update = Update.new
9
8
  @sha = Sha.new
10
9
  end
@@ -12,16 +11,15 @@ module Lapidarist
12
11
  def run
13
12
  Options.new(args).parse
14
13
  Lapidarist.logger.header('Starting lapidarist')
15
- Lapidarist.logger.debug("directory: #{Lapidarist.config.directory}", :options)
16
- Lapidarist.logger.debug("test_script: #{Lapidarist.config.test_script}", :options)
14
+ trap_interrupt
17
15
 
18
16
  unless git.clean?
19
17
  Lapidarist.logger.footer('stopping, there are uncommitted changes')
20
- return 1
18
+ return STATUS_ERROR
21
19
  end
22
20
 
23
21
  sha.record_good
24
- gems = outdated.run
22
+ gems = Lapidarist::Outdated.new.run
25
23
 
26
24
  status = nil
27
25
  attempt = 0
@@ -50,42 +48,48 @@ module Lapidarist
50
48
  status = Status.new(gems, attempt)
51
49
  break
52
50
  else
53
- Lapidarist.logger.footer('test failed, investigating failure')
51
+ Lapidarist.logger.footer('test failed')
54
52
  end
55
53
 
56
- failed_gem =
57
- if updated_gems.one?
58
- updated_but_failed_gem = updated_gems.first
59
- git.reset_hard('HEAD^')
60
-
61
- Gem.from(
62
- updated_but_failed_gem,
63
- attempt: attempt,
64
- status: :failed,
65
- updated_version: updated_but_failed_gem.latest_attempt.version
66
- )
67
- else
68
- failed_gem_name = git.bisect(sha.last_good, test)
69
- updated_but_failed_gem = updated_gems.detect { |g| g.name == failed_gem_name }
70
- gems = gems.merge(updated_gems.take(sha.new_commit_count))
71
- sha.record_good
72
-
73
- Gem.from(
74
- updated_but_failed_gem,
75
- attempt: attempt,
76
- status: :failed,
77
- updated_version: updated_but_failed_gem.latest_attempt.version
78
- )
79
- end
80
- gems = gems.merge(failed_gem)
54
+ failed_gem = Lapidarist::FindFailure.new(
55
+ gems: updated_gems,
56
+ attempt: attempt,
57
+ last_good_sha: sha.last_good
58
+ ).run
59
+ gems = gems.merge(updated_gems.take(sha.new_commit_count)).merge(failed_gem)
60
+ sha.record_good
61
+
62
+ if Lapidarist.config.debug
63
+ Summary.new(gems).display_debug
64
+ end
81
65
  end
82
66
 
83
67
  Summary.new(gems).display
84
68
  return status.to_i
69
+
70
+ rescue OptionParser::InvalidOption => e
71
+ warn e.message
72
+ warn 'For usage information, use --help'
73
+ return STATUS_ERROR
74
+ rescue Lapidarist::Abort => e
75
+ git.reset_hard(sha.last_good)
76
+ Summary.new(gems).display
77
+ return STATUS_ERROR
78
+ end
79
+
80
+ def trap_interrupt
81
+ Signal.trap('INT') do
82
+ warn
83
+ warn 'Cleaning up and exiting... Interrupt again to exit immediately.'
84
+
85
+ Lapidarist.threads.stop
86
+
87
+ raise Lapidarist::Abort
88
+ end
85
89
  end
86
90
 
87
91
  private
88
92
 
89
- attr_reader :args, :git, :test, :outdated, :update, :sha
93
+ attr_reader :args, :git, :test, :update, :sha
90
94
  end
91
95
  end
@@ -1,4 +1,5 @@
1
1
  require 'ostruct'
2
+ require 'pathname'
2
3
 
3
4
  module Lapidarist
4
5
  class Configuration < OpenStruct
@@ -0,0 +1,35 @@
1
+ module Lapidarist
2
+ class FindFailure
3
+ def initialize(gems:, attempt:, last_good_sha:)
4
+ @gems = gems
5
+ @attempt = attempt
6
+ @last_good_sha = last_good_sha
7
+ @git = GitCommand.new
8
+ @test = TestCommand.new
9
+ end
10
+
11
+ def run
12
+ Lapidarist.logger.header('Investigating failure')
13
+
14
+ updated_but_failed_gem =
15
+ if gems.one?
16
+ git.reset_hard('HEAD^')
17
+ gems.first
18
+ else
19
+ failed_gem_name = git.bisect(last_good_sha, test)
20
+ gems.detect { |gem| gem.name == failed_gem_name }
21
+ end
22
+
23
+ Gem.from(
24
+ updated_but_failed_gem,
25
+ attempt: attempt,
26
+ status: :failed,
27
+ updated_version: updated_but_failed_gem.latest_attempt.version
28
+ )
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :gems, :attempt, :last_good_sha, :git, :test
34
+ end
35
+ end
@@ -131,7 +131,6 @@ module Lapidarist
131
131
  private
132
132
 
133
133
  def version_changed?
134
- # use VersionChange
135
134
  updated_version && installed_version != updated_version
136
135
  end
137
136
 
@@ -28,6 +28,7 @@ module Lapidarist
28
28
  MAJOR = Level.new(name: :major, index: 1)
29
29
  MINOR = Level.new(name: :minor, index: 2)
30
30
  PATCH = Level.new(name: :patch, index: 3)
31
+ NONE = Level.new(name: "", index: 4)
31
32
 
32
33
  LEVELS = [MAJOR, MINOR, PATCH].freeze
33
34
  end
@@ -12,7 +12,7 @@ module Lapidarist
12
12
  Lapidarist.config.directory = Pathname.new(d)
13
13
  end
14
14
 
15
- opts.on("-t", "--test TEST_SCRIPT", "Test script given to git bisect.") do |t|
15
+ opts.on("-t", "--test TEST_SCRIPT", "Test script to assert that the gems updates are safe to commit.") do |t|
16
16
  Lapidarist.config.test_script = t
17
17
  end
18
18
 
@@ -28,7 +28,7 @@ module Lapidarist
28
28
  Lapidarist.config.verbosity += 1
29
29
  end
30
30
 
31
- opts.on("-f", "--commit-flags flags", "Append flags to the commit command.") do |t|
31
+ opts.on("-f", "--commit-flags FLAGS", "Append flags to the commit command.") do |t|
32
32
  Lapidarist.config.commit_flags = t
33
33
  end
34
34
 
@@ -8,7 +8,10 @@ module Lapidarist
8
8
  def record_good
9
9
  good_sha = git.head
10
10
  Lapidarist.logger.debug("good sha: #{good_sha}")
11
- @good_shas << good_sha
11
+
12
+ unless last_good == good_sha
13
+ @good_shas << good_sha
14
+ end
12
15
  end
13
16
 
14
17
  def last_good
@@ -14,13 +14,15 @@ module Lapidarist
14
14
  Lapidarist.logger.info "COMMAND > `#{command}`", 1
15
15
 
16
16
  if block_given?
17
- Open3.popen2e(command, chdir: Lapidarist.config.directory) do |_std_in, std_out_err|
17
+ Open3.popen2e(command, chdir: Lapidarist.config.directory) do |_std_in, std_out_err, wait_thr|
18
+ Lapidarist.threads << wait_thr
18
19
  yield(std_out_err)
19
20
  end
20
21
  else
21
22
  out_err = []
22
23
 
23
24
  status = Open3.popen2e(command, chdir: Lapidarist.config.directory) do |_std_in, std_out_err, wait_thr|
25
+ Lapidarist.threads << wait_thr
24
26
  while line = std_out_err.gets
25
27
  Lapidarist.logger.std_out_err(line, label || command)
26
28
  out_err << line
@@ -36,12 +38,14 @@ module Lapidarist
36
38
 
37
39
  def pipe_multiple_commands(*commands)
38
40
  if block_given?
39
- Open3.pipeline_r(*commands, chdir: Lapidarist.config.directory) do |std_out, _ts|
41
+ Open3.pipeline_r(*commands, chdir: Lapidarist.config.directory) do |std_out, ts|
42
+ Lapidarist.threads << ts
40
43
  yield(std_out)
41
44
  end
42
45
  else
43
46
  output = ''
44
- Open3.pipeline_r(*commands, chdir: Lapidarist.config.directory) do |std_out, _ts|
47
+ Open3.pipeline_r(*commands, chdir: Lapidarist.config.directory) do |std_out, ts|
48
+ Lapidarist.threads << ts
45
49
  output = std_out.read
46
50
  end
47
51
  output
@@ -6,7 +6,11 @@ module Lapidarist
6
6
  end
7
7
 
8
8
  def to_i
9
- gems.updated.any? || attempt == 1
9
+ if gems.updated.any? || attempt == 1
10
+ STATUS_SUCCESS
11
+ else
12
+ STATUS_FAILED
13
+ end
10
14
  end
11
15
 
12
16
  private
@@ -9,17 +9,15 @@ module Lapidarist
9
9
  Lapidarist.logger.summary 'Summary'
10
10
  Lapidarist.logger.summary '-'*50
11
11
  Lapidarist.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')}"
12
- gems.each do |gem|
13
- gem.attempts.each do |i, data|
14
- case data.status
15
- when :updated
16
- Lapidarist.logger.summary " + updated #{gem.name} from #{gem.installed_version} to #{data.version}"
17
- when :failed
18
- Lapidarist.logger.summary " x failed #{gem.name} from #{gem.installed_version} to #{data.version}"
19
- when :skipped
20
- Lapidarist.logger.summary " - skipped #{gem.name} (#{data.reason})"
21
- end
22
- end
12
+ summarize_attempts do |summary|
13
+ Lapidarist.logger.summary summary
14
+ end
15
+ end
16
+
17
+ def display_debug
18
+ Lapidarist.logger.debug "#{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')}"
19
+ summarize_attempts do |summary|
20
+ Lapidarist.logger.debug summary
23
21
  end
24
22
  end
25
23
 
@@ -41,5 +39,22 @@ module Lapidarist
41
39
  "#{length} #{plural}"
42
40
  end
43
41
  end
42
+
43
+ def summarize_attempts
44
+ gems.each do |gem|
45
+ gem.attempts.each do |i, data|
46
+ summary =
47
+ case data.status
48
+ when :updated
49
+ " + updated #{gem.name} from #{gem.installed_version} to #{data.version}"
50
+ when :failed
51
+ " x failed #{gem.name} from #{gem.installed_version} to #{data.version}"
52
+ when :skipped
53
+ " - skipped #{gem.name} (#{data.reason})"
54
+ end
55
+ yield summary
56
+ end
57
+ end
58
+ end
44
59
  end
45
60
  end
@@ -0,0 +1,42 @@
1
+ module Lapidarist
2
+ class Threads
3
+ def initialize
4
+ @threads = []
5
+ @abort = false
6
+ end
7
+
8
+ def <<(thread)
9
+ @threads += Array(thread)
10
+ end
11
+
12
+ def stop
13
+ if aborting?
14
+ kill
15
+ exit! STATUS_ERROR
16
+ else
17
+ @abort = true
18
+ abort
19
+ end
20
+ end
21
+
22
+ def aborting?
23
+ @abort
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :threads
29
+
30
+ def alive
31
+ threads.select { |thread| thread.alive? }
32
+ end
33
+
34
+ def abort
35
+ alive.each { |thread| Process.kill("INT", thread.pid) }
36
+ end
37
+
38
+ def kill
39
+ alive.each { |thread| Process.kill("KILL", thread.pid) }
40
+ end
41
+ end
42
+ end
@@ -1,3 +1,3 @@
1
1
  module Lapidarist
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -33,6 +33,12 @@ module Lapidarist
33
33
  Lapidarist::MINOR
34
34
  elsif updated_segments && updated_segments[0] == installed_segments[0] && updated_segments[1] == installed_segments[1] && updated_segments[2] > installed_segments[2]
35
35
  Lapidarist::PATCH
36
+ elsif updated_segments && (
37
+ (updated_segments[0] == installed_segments[0] && updated_segments[1] == installed_segments[1] && updated_segments[2] <= installed_segments[2]) ||
38
+ (updated_segments[0] == installed_segments[0] && updated_segments[1] <= installed_segments[1]) ||
39
+ updated_segments[0] <= installed_segments[0]
40
+ )
41
+ Lapidarist::NONE
36
42
  end
37
43
  end
38
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lapidarist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Gangl
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-11 00:00:00.000000000 Z
11
+ date: 2018-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -78,6 +78,7 @@ files:
78
78
  - lib/lapidarist/bundle_command.rb
79
79
  - lib/lapidarist/cli.rb
80
80
  - lib/lapidarist/configuration.rb
81
+ - lib/lapidarist/find_failure.rb
81
82
  - lib/lapidarist/gem.rb
82
83
  - lib/lapidarist/gem_version.rb
83
84
  - lib/lapidarist/gems.rb
@@ -93,6 +94,7 @@ files:
93
94
  - lib/lapidarist/status.rb
94
95
  - lib/lapidarist/summary.rb
95
96
  - lib/lapidarist/test_command.rb
97
+ - lib/lapidarist/threads.rb
96
98
  - lib/lapidarist/update.rb
97
99
  - lib/lapidarist/version.rb
98
100
  - lib/lapidarist/version_change.rb