lolcommits 0.9.8 → 0.10.0.pre1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12f6e7333b2269c69ec65d675f107c330d05369371672c316e0610b9c263870a
4
- data.tar.gz: d02a439065f69b0687c6f71b1c82d1131e59cf8cb3bc819db918419b8d0278fe
3
+ metadata.gz: 6ac258b4768122ade54206ac494b52d041dbe1ddbee4a8f464d302c4e477805c
4
+ data.tar.gz: 91abb44e9340561efb31942349d2b8edc17ad3b1d86149fe25bdae394beca967
5
5
  SHA512:
6
- metadata.gz: df2fdfc47dc2475c4b5a369876d12e4651a261dff4cc1ee25d57ae1959733e6830a7bc2d3403df21d7e860f087c754d9f799717ef340410934f9cfb187d1d133
7
- data.tar.gz: ab59a454da2e510712390135e46694a087e1510f7b1bdab64d960d1f60f72e05e3b30bd1e150c4b7df5c6fe20c5ab059075e75d68b6824cc27b9a09bf6b709c6
6
+ metadata.gz: 4a6946be8f2501f30dc74da7ffb99f332222f5489be04cb8be41c4c62112a7a82eb30de5f342f57219cf172413ed7df73405eab044be19ee15b8edb71a25b816
7
+ data.tar.gz: db2a6f1e5446ab3ed915d6229e91e97f28a359557d88b7f9a83b27d1516d562d0a40f266a4c40ef938e7f5843646a09391ea3fd2414577a2e0ec8748a18a96d7
data/.rubocop.yml CHANGED
@@ -8,4 +8,12 @@ Metrics/BlockLength:
8
8
  Exclude:
9
9
  - 'lolcommits.gemspec'
10
10
 
11
+ # don't agree with this one, can lead to long lines that are harder to parse
12
+ Style/IfUnlessModifier:
13
+ Enabled: false
14
+
15
+ # our gem supports 2.0+ but Rubocop only supports 2.1+
16
+ Gemspec/RequiredRubyVersion:
17
+ Enabled: false
18
+
11
19
  inherit_from: .rubocop_todo.yml
data/.rubocop_todo.yml CHANGED
@@ -1,44 +1,54 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2017-04-04 11:42:26 +0100 using RuboCop version 0.48.1.
3
+ # on 2017-12-13 17:09:06 +0000 using RuboCop version 0.52.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
+ # Offense count: 7
10
+ # Cop supports --auto-correct.
11
+ # Configuration parameters: Include, TreatCommentsAsGroupSeparators.
12
+ # Include: **/*.gemspec
13
+ Gemspec/OrderedDependencies:
14
+ Exclude:
15
+ - 'lolcommits.gemspec'
16
+
17
+ # Offense count: 1
18
+ # Cop supports --auto-correct.
19
+ # Configuration parameters: EnforcedStyle.
20
+ # SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
21
+ Layout/IndentHeredoc:
22
+ Exclude:
23
+ - 'lib/lolcommits/backends/installation_git.rb'
24
+
9
25
  # Offense count: 1
10
26
  Lint/AmbiguousBlockAssociation:
11
27
  Exclude:
12
28
  - 'lib/lolcommits/cli/process_runner.rb'
13
29
 
14
- # Offense count: 35
30
+ # Offense count: 19
15
31
  Metrics/AbcSize:
16
- Max: 37
32
+ Max: 35
17
33
 
18
- # Offense count: 2
34
+ # Offense count: 1
19
35
  # Configuration parameters: CountComments, ExcludedMethods.
20
36
  Metrics/BlockLength:
21
- Max: 60
37
+ Max: 40
22
38
 
23
- # Offense count: 5
39
+ # Offense count: 2
24
40
  # Configuration parameters: CountComments.
25
41
  Metrics/ClassLength:
26
- Max: 149
42
+ Max: 140
27
43
 
28
- # Offense count: 6
44
+ # Offense count: 5
29
45
  Metrics/CyclomaticComplexity:
30
46
  Max: 9
31
47
 
32
- # Offense count: 152
33
- # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
34
- # URISchemes: http, https
35
- Metrics/LineLength:
36
- Max: 161
37
-
38
- # Offense count: 42
48
+ # Offense count: 23
39
49
  # Configuration parameters: CountComments.
40
50
  Metrics/MethodLength:
41
- Max: 31
51
+ Max: 24
42
52
 
43
53
  # Offense count: 5
44
54
  Metrics/PerceivedComplexity:
@@ -50,37 +60,38 @@ Security/YAMLLoad:
50
60
  Exclude:
51
61
  - 'lib/lolcommits/configuration.rb'
52
62
 
53
- # Offense count: 37
63
+ # Offense count: 25
54
64
  Style/Documentation:
55
65
  Enabled: false
56
66
 
57
- # Offense count: 2
58
- # Cop supports --auto-correct.
59
- Layout/EmptyLinesAroundBeginBody:
60
- Exclude:
61
- - 'lib/lolcommits/plugin/lol_flowdock.rb'
62
- - 'lib/lolcommits/plugin/lol_slack.rb'
63
-
64
- # Offense count: 1
65
- # Cop supports --auto-correct.
66
- # Configuration parameters: EnforcedStyle, SupportedStyles.
67
- # SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
68
- Layout/IndentHeredoc:
67
+ # Offense count: 5
68
+ Style/MixinUsage:
69
69
  Exclude:
70
- - 'lib/lolcommits/backends/installation_git.rb'
70
+ - 'Rakefile'
71
+ - 'bin/lolcommits'
72
+ - 'features/support/env.rb'
73
+ - 'test/lolcommits_test.rb'
71
74
 
72
- # Offense count: 77
75
+ # Offense count: 5
73
76
  # Cop supports --auto-correct.
74
77
  # Configuration parameters: PreferredDelimiters.
75
78
  Style/PercentLiteralDelimiters:
76
- Enabled: false
77
-
78
- Gemspec/OrderedDependencies:
79
- Enabled: false
79
+ Exclude:
80
+ - 'Rakefile'
81
+ - 'features/support/path_helpers.rb'
82
+ - 'lib/lolcommits/backends/installation_mercurial.rb'
83
+ - 'lib/lolcommits/cli/fatals.rb'
84
+ - 'lib/lolcommits/installation.rb'
80
85
 
81
86
  # Offense count: 1
82
87
  # Cop supports --auto-correct.
83
- # Configuration parameters: SupportedStyles.
88
+ # Configuration parameters: MinSize.
84
89
  # SupportedStyles: percent, brackets
85
90
  Style/SymbolArray:
86
91
  EnforcedStyle: brackets
92
+
93
+ # Offense count: 90
94
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
95
+ # URISchemes: http, https
96
+ Metrics/LineLength:
97
+ Max: 161
data/.travis.yml CHANGED
@@ -4,9 +4,9 @@ cache: bundler
4
4
  rvm:
5
5
  - 2.0.0
6
6
  - 2.1.10
7
- - 2.2.8
8
- - 2.3.5
9
- - 2.4.2
7
+ - 2.2.9
8
+ - 2.3.6
9
+ - 2.4.3
10
10
  - ruby-head
11
11
 
12
12
  before_install:
data/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ project adheres to [Semantic Versioning][Semver].
7
7
 
8
8
  * Your contribution here!
9
9
 
10
+ ## [0.10.0][] (10 January 2018)
11
+ * Plugin configuration changes (@matthutchinson [#365][])
12
+ - `--plugins` now shows if plugin is enabled or not
13
+ - `default_options` now available, nested hash with default values
14
+ - if `valid_configuration?` fails, warning message shows
15
+ - `prompt_autocomplete_hash` helper method added
16
+ * Better plugin config flow (@matthutchinson [#363][])
17
+
10
18
  ## [0.9.8][] (3 December 2017)
11
19
  * Extract protonet to gem (@matthutchinson [#361][])
12
20
  * Extract flowdock to gem (@matthutchinson [#360][])
@@ -302,7 +310,8 @@ project adheres to [Semantic Versioning][Semver].
302
310
  instead of compositing multiply image Caption objects (this seems to be more
303
311
  reliable to not glitch.)
304
312
 
305
- [Unreleased]: https://github.com/mroth/lolcommits/compare/v0.9.8...HEAD
313
+ [Unreleased]: https://github.com/mroth/lolcommits/compare/v0.10.0...HEAD
314
+ [0.10.0]: https://github.com/mroth/lolcommits/compare/v0.9.8...v0.10.0
306
315
  [0.9.8]: https://github.com/mroth/lolcommits/compare/v0.9.7...v0.9.8
307
316
  [0.9.7]: https://github.com/mroth/lolcommits/compare/v0.9.6...v0.9.7
308
317
  [0.9.6]: https://github.com/mroth/lolcommits/compare/v0.9.5...v0.9.6
@@ -484,3 +493,5 @@ project adheres to [Semantic Versioning][Semver].
484
493
  [#359]: https://github.com/mroth/lolcommits/pull/359
485
494
  [#360]: https://github.com/mroth/lolcommits/pull/360
486
495
  [#361]: https://github.com/mroth/lolcommits/pull/361
496
+ [#363]: https://github.com/mroth/lolcommits/pull/363
497
+ [#365]: https://github.com/mroth/lolcommits/pull/365
data/README.md CHANGED
@@ -190,13 +190,6 @@ other services), or even translate your commit messages to
190
190
  out on our [plugins
191
191
  page](https://github.com/mroth/lolcommits/wiki/Configuring-Plugins).
192
192
 
193
- Until recently, all plugins lived inside the main lolcommits gem. We are in the
194
- process of extracting them to individual gems. For [gem
195
- plugins](https://github.com/search?q=topic%3Alolcommits-plugin+org%3Alolcommits&type=Repositories),
196
- you'll need to install the gem first:
197
-
198
- [sudo] gem install lolcommits-plugin-sample
199
-
200
193
  To list all installed plugins use:
201
194
 
202
195
  lolcommits --plugins
@@ -209,8 +202,8 @@ Installed plugins can be easily enabled, configured or disabled with the
209
202
  lolcommits --config -p loltext
210
203
 
211
204
  Interested in developing your own plugin? Follow [this simple
212
- guide](https://github.com/lolcommits/lolcommits-plugin-sample#developing-your-own-plugin) at the
213
- Lolcommits Plugin Sample README.
205
+ guide](https://github.com/lolcommits/lolcommits-sample_plugin#developing-your-own-plugin) at the
206
+ Lolcommits Sample Plugin README.
214
207
 
215
208
 
216
209
  ## Timelapse
data/appveyor.yml CHANGED
@@ -15,10 +15,6 @@ clone_folder: c:\projects\lolcommits
15
15
  clone_depth: 10
16
16
  skip_tags: true
17
17
 
18
- branches:
19
- except:
20
- - gh-pages
21
-
22
18
  init:
23
19
  # stub mplayer/ffmpeg so it looks like they are installed
24
20
  - mkdir c:\bin
@@ -26,16 +26,6 @@ Feature: Bug regression testing
26
26
  # Then there should be 4 commit entries in the git log
27
27
  Then there should be exactly 6 jpgs in "../.lolcommits/yuh8history"
28
28
 
29
- #
30
- # issue #81, https://github.com/mroth/lolcommits/issues/81
31
- #
32
- Scenario: don't want initialized constant warning from Faraday (MRI 1.8.7)
33
- When I successfully run `lolcommits`
34
- Then the output should not contain:
35
- """
36
- warning: already initialized constant DEFAULT_BOUNDARY
37
- """
38
-
39
29
  #
40
30
  # issue #87, https://github.com/mroth/lolcommits/issues/87
41
31
  #
@@ -67,15 +67,16 @@ Feature: Basic UI functionality
67
67
  """
68
68
  And the exit status should be 1
69
69
 
70
- Scenario: Capture doesnt break in forked mode
71
- Given I am in a git repo named "forked"
72
- And I do a git commit
73
- When I run `lolcommits --capture --fork`
74
- Then there should be exactly 1 pid in "~/.lolcommits/forked"
75
- When I wait for the child process to exit in "forked"
76
- Then a directory named "~/.lolcommits/forked" should exist
77
- And a file named "~/.lolcommits/forked/tmp_snapshot.jpg" should not exist
78
- And there should be exactly 1 jpg in "~/.lolcommits/forked"
70
+ # flakey test sometimes fails: https://travis-ci.org/mroth/lolcommits/jobs/312629988#L620
71
+ # Scenario: Capture doesnt break in forked mode
72
+ # Given I am in a git repo named "forked"
73
+ # And I do a git commit
74
+ # When I run `lolcommits --capture --fork`
75
+ # Then there should be exactly 1 pid in "~/.lolcommits/forked"
76
+ # When I wait for the child process to exit in "forked"
77
+ # Then a directory named "~/.lolcommits/forked" should exist
78
+ # And a file named "~/.lolcommits/forked/tmp_snapshot.jpg" should not exist
79
+ # And there should be exactly 1 jpg in "~/.lolcommits/forked"
79
80
 
80
81
  Scenario: Commiting in an enabled git repo triggers successful capture
81
82
  Given I am in a git repo named "myrepo" with lolcommits enabled
@@ -119,10 +120,10 @@ Feature: Basic UI functionality
119
120
  When I run `lolcommits --config --test -p loltext` interactively
120
121
  And I wait for output to contain "enabled:"
121
122
  Then I type "false"
122
- Then the output should contain "Successfully configured plugin: loltext"
123
+ Then the output should contain "Disabling plugin: loltext - answer with 'true' to enable & configure"
123
124
  And a file named "~/.lolcommits/test/config.yml" should exist
124
125
  When I successfully run `lolcommits --test --show-config`
125
- Then the output should match /loltext:\s+enabled: false/
126
+ Then the output should match /loltext:\s+:enabled: false/
126
127
 
127
128
  Scenario: test capture should work regardless of whether in a lolrepo
128
129
  Given I am in a directory named "nothingtoseehere"
@@ -160,7 +160,8 @@ Then(/^there should be exactly (.*?) (jpg|gif|pid)s? in "(.*?)"$/) do |n, type,
160
160
  end
161
161
 
162
162
  Then(/^the output should contain a list of plugins$/) do
163
- step %(the output should contain "Available plugins: ")
163
+ step %(the output should contain "Installed plugins: (* enabled)")
164
+ step %(the output should contain "[*] loltext")
164
165
  end
165
166
 
166
167
  When(/^I do a git commit with commit message "(.*?)"$/) do |commit_msg|
@@ -30,9 +30,7 @@ module PathHelpers
30
30
  def preseve_cmds_in_path(cmds, tmpbindir)
31
31
  cmds.each do |cmd|
32
32
  whichcmd = Lolcommits::Platform.command_which(cmd)
33
- unless whichcmd.nil?
34
- FileUtils.ln_s whichcmd, File.join(tmpbindir, File.basename(whichcmd))
35
- end
33
+ FileUtils.ln_s whichcmd, File.join(tmpbindir, File.basename(whichcmd)) unless whichcmd.nil?
36
34
  end
37
35
  end
38
36
  end
@@ -0,0 +1,21 @@
1
+ # Backport Hash#dig to Ruby < 2.3
2
+ # inspired by https://github.com/Invoca/ruby_dig
3
+
4
+ module HashDig
5
+ def dig(key, *rest)
6
+ value = self[key]
7
+ if value.nil? || rest.empty?
8
+ value
9
+ elsif value.respond_to?(:dig)
10
+ value.dig(*rest)
11
+ else
12
+ raise TypeError, "#{value.class} does not have #dig method"
13
+ end
14
+ end
15
+ end
16
+
17
+ if RUBY_VERSION < '2.3'
18
+ class Hash
19
+ include HashDig
20
+ end
21
+ end
data/lib/lolcommits.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  $LOAD_PATH.unshift File.expand_path('.')
2
2
 
3
+ require 'core_ext/hash/hash_dig' # backport Hash#dig for Ruby < 2.3
4
+
3
5
  require 'mini_magick'
4
6
  require 'core_ext/mini_magick/utilities'
5
7
  require 'fileutils'
@@ -42,18 +42,12 @@ module Lolcommits
42
42
  end
43
43
 
44
44
  def url
45
- @url ||= begin
46
- if repository.remote && repository.remote.url
47
- remote_https_url(repository.remote.url)
48
- end
49
- end
45
+ @url ||= remote_repo? ? remote_https_url(repository.remote.url) : nil
50
46
  end
51
47
 
52
48
  def repo
53
49
  @repo ||= begin
54
- if repository.remote && repository.remote.url
55
- match = repository.remote.url.match(GIT_URL_REGEX)
56
- end
50
+ match = repository.remote.url.match(GIT_URL_REGEX) if remote_repo?
57
51
 
58
52
  if match
59
53
  match[1]
@@ -88,5 +82,9 @@ module Lolcommits
88
82
  def last_commit
89
83
  @commit ||= repository.log.first
90
84
  end
85
+
86
+ def remote_repo?
87
+ repository.remote && repository.remote.url
88
+ end
91
89
  end
92
90
  end
@@ -11,11 +11,13 @@ module Lolcommits
11
11
  @loldir = Configuration.loldir_for('test') if test_mode
12
12
  end
13
13
 
14
- def read_configuration
15
- return unless File.exist?(configuration_file)
16
- # TODO: change to safe_load when Ruby 2.0.0 support drops
17
- # YAML.safe_load(File.open(configuration_file), [Symbol])
18
- YAML.load(File.open(configuration_file))
14
+ def yaml
15
+ @_yaml ||= begin
16
+ return Hash.new({}) unless File.exist?(configuration_file)
17
+ # TODO: change to safe_load when Ruby 2.0.0 support drops
18
+ # YAML.safe_load(File.open(configuration_file), [Symbol])
19
+ YAML.load(File.open(configuration_file)) || Hash.new({})
20
+ end
19
21
  end
20
22
 
21
23
  def configuration_file
@@ -65,19 +67,23 @@ module Lolcommits
65
67
  end
66
68
 
67
69
  def list_plugins
68
- puts "Available plugins: \n * #{plugin_manager.plugin_names.join("\n * ")}"
70
+ puts "Installed plugins: (* enabled)\n"
71
+
72
+ plugin_manager.plugins.each do |gem_plugin|
73
+ plugin = gem_plugin.plugin_klass.new(config: yaml[gem_plugin.name])
74
+ puts " [#{plugin.enabled? ? '*' : '-'}] #{gem_plugin.name}"
75
+ end
69
76
  end
70
77
 
71
- def find_plugin(plugin_name_option)
72
- plugin_name = plugin_name_option.empty? ? ask_for_plugin_name : plugin_name_option
73
- return if plugin_name.empty?
78
+ def find_plugin(name)
79
+ plugin_name = name.empty? ? ask_for_plugin_name : name
80
+ plugin = plugin_manager.find_by_name(plugin_name)
74
81
 
75
- plugin_klass = plugin_manager.find_by_name(plugin_name)
76
- return plugin_klass.new(config: self) if plugin_klass
82
+ return plugin if plugin
77
83
 
78
84
  puts "Unable to find plugin: '#{plugin_name}'"
79
- return if plugin_name_option.empty?
80
- list_plugins
85
+ list_plugins unless name.empty?
86
+ nil
81
87
  end
82
88
 
83
89
  def ask_for_plugin_name
@@ -88,33 +94,47 @@ module Lolcommits
88
94
 
89
95
  def do_configure!(plugin_name)
90
96
  $stdout.sync = true
91
-
92
97
  plugin = find_plugin(plugin_name.to_s.strip)
93
98
  return unless plugin
94
- config = read_configuration || {}
95
- plugin_name = plugin.class.name
96
- plugin_config = plugin.configure_options!
97
- # having a plugin_config, means configuring went OK
98
- if plugin_config
99
- # save plugin and print config
100
- config[plugin_name] = plugin_config
101
- save(config)
102
- puts self
103
- puts "\nSuccessfully configured plugin: #{plugin_name} at path '#{configuration_file}'"
104
- else
105
- puts "\nAborted plugin configuration for: #{plugin_name}"
99
+
100
+ puts "Configuring plugin: #{plugin.name}\n"
101
+ plugin_config = plugin.plugin_klass.new(config: yaml[plugin_name]).configure_options! || {}
102
+
103
+ unless plugin_config[:enabled]
104
+ puts "Disabling plugin: #{plugin.name} - answer with 'true' to enable & configure"
105
+ end
106
+ rescue Interrupt
107
+ # e.g. user Ctrl+c or aborted by plugin configure_options!
108
+ puts "\n"
109
+ if plugin
110
+ puts "Configuration aborted: #{plugin.name} has been disabled"
111
+ plugin_config ||= {}
112
+ plugin_config[:enabled] = false
113
+ end
114
+ ensure
115
+ if plugin
116
+ # clean away legacy enabled key, later we can remove this
117
+ plugin_config.delete('enabled')
118
+ # save plugin config (if we have anything in the hash)
119
+ save(plugin.name, plugin_config) unless plugin_config.empty?
120
+
121
+ # print config if plugin was enabled
122
+ if plugin_config[:enabled]
123
+ puts "\nSuccessfully configured plugin: #{plugin.name} - at path '#{configuration_file}'"
124
+ puts plugin_config.to_yaml.to_s
125
+ end
106
126
  end
107
127
  end
108
128
 
109
- def save(config)
110
- config_file_contents = config.to_yaml
129
+ def save(plugin_name, plugin_config)
130
+ config_file_contents = yaml.merge(plugin_name => plugin_config).to_yaml
111
131
  File.open(configuration_file, 'w') do |f|
112
132
  f.write(config_file_contents)
113
133
  end
114
134
  end
115
135
 
116
136
  def to_s
117
- read_configuration.to_yaml.to_s
137
+ yaml.to_yaml.to_s
118
138
  end
119
139
 
120
140
  # class methods
@@ -44,6 +44,10 @@ module Lolcommits
44
44
  warn "failed to load constant from plugin gem '#{plugin_klass_name}: #{e}'"
45
45
  end
46
46
 
47
+ def plugin_instance(runner)
48
+ plugin_klass.new(runner: runner, config: runner.config.yaml[name])
49
+ end
50
+
47
51
  def gem_name
48
52
  gem_spec.name
49
53
  end
@@ -55,7 +59,12 @@ module Lolcommits
55
59
  end
56
60
 
57
61
  def plugin_klass_name
58
- gem_path.split('/').map(&:capitalize).join('::')
62
+ # convert gem paths to plugin classes e.g.
63
+ # lolcommits/loltext --> Lolcommits::Plugin::Loltext
64
+ # lolcommits/term_output --> Lolcommits::Plugin::TermOutput
65
+ gem_path.split('/').insert(1, 'plugin').collect do |c|
66
+ c.split('_').collect(&:capitalize).join
67
+ end.join('::')
59
68
  end
60
69
  end
61
70
  end
@@ -1,30 +1,16 @@
1
+ require 'lolcommits/plugin/configuration_helper'
2
+
1
3
  module Lolcommits
2
4
  module Plugin
3
5
  class Base
4
- attr_accessor :runner, :config, :options
6
+ include Lolcommits::Plugin::ConfigurationHelper
5
7
 
6
- def initialize(runner: nil, config: nil)
7
- self.runner = runner
8
- self.config = config || runner.config
9
- self.options = ['enabled']
10
- end
11
-
12
- def execute_pre_capture
13
- return unless configured_and_enabled?
14
- debug 'I am enabled, about to run pre capture'
15
- run_pre_capture
16
- end
8
+ attr_accessor :runner, :configuration, :options
17
9
 
18
- def execute_post_capture
19
- return unless configured_and_enabled?
20
- debug 'I am enabled, about to run post capture'
21
- run_post_capture
22
- end
23
-
24
- def execute_capture_ready
25
- return unless configured_and_enabled?
26
- debug 'I am enabled, about to run capture ready'
27
- run_capture_ready
10
+ def initialize(runner: nil, config: {})
11
+ self.runner = runner
12
+ self.configuration = config || {}
13
+ self.options = [:enabled]
28
14
  end
29
15
 
30
16
  def run_pre_capture; end
@@ -33,57 +19,60 @@ module Lolcommits
33
19
 
34
20
  def run_capture_ready; end
35
21
 
36
- def configuration
37
- saved_config = config.read_configuration
38
- return {} unless saved_config
39
- saved_config[self.class.name] || {}
40
- end
41
-
42
- # ask for plugin options
22
+ ##
23
+ # Prompts the user to configure all plugin options.
24
+ #
25
+ # Available options can be defined in an Array (@options instance var)
26
+ # and/or a Hash (by overriding the `default_options` method).
27
+ #
28
+ # By default (on initialize), `@options` is set with `[:enabled]`. This is
29
+ # mandatory since `enabled?` checks this option is true before running any
30
+ # capture hooks.
31
+ #
32
+ # Using a Hash to define default options allows you to:
33
+ #
34
+ # - including default values
35
+ # - define nested options, user is prompted for each nested option key
36
+ #
37
+ # `configure_option_hash` will iterate over all options prompting the user
38
+ # for input and building the configuration Hash.
39
+ #
40
+ # Lolcommits will save this Hash to a YAML file. During the capture
41
+ # process the configuration is loaded, parsed and available in the plugin
42
+ # class as `@configuration`. Or if you want to fall back to default
43
+ # values, you should use `config_option` to fetch option values.
44
+ #
45
+ # Alternatively you can override this method entirely to customise the
46
+ # process. A helpful `parse_user_input` method is available to help parse
47
+ # strings from STDIN (into boolean, integer or nil values).
48
+ #
49
+ # @return [Hash] the configured plugin options
43
50
  def configure_options!
44
- puts "Configuring plugin: #{self.class.name}\n"
45
- options.reduce({}) do |acc, option|
46
- print "#{option}: "
47
- val = parse_user_input(gets.strip)
48
- # check enabled option isn't a String
49
- if (option == 'enabled') && ![true, false].include?(val)
50
- puts "Aborting - please respond with 'true' or 'false'"
51
- exit 1
52
- else
53
- acc.merge(option => val)
54
- end
55
- end
51
+ configure_option_hash(
52
+ Hash[options.map { |key, _value| [key, nil] }].merge(default_options)
53
+ )
56
54
  end
57
55
 
58
- def parse_user_input(str)
59
- # cater for bools, strings, ints and blanks
60
- if 'true'.casecmp(str).zero?
61
- true
62
- elsif 'false'.casecmp(str).zero?
63
- false
64
- elsif str =~ /^[0-9]+$/
65
- str.to_i
66
- elsif str.strip.empty?
67
- nil
68
- else
69
- str
70
- end
56
+ def default_options
57
+ {}
71
58
  end
72
59
 
73
- def configured_and_enabled?
74
- valid_configuration? && enabled?
60
+ def config_option(*keys)
61
+ configuration.dig(*keys) || default_options.dig(*keys)
75
62
  end
76
63
 
77
64
  def enabled?
78
- configuration['enabled'] == true
65
+ # legacy configs (< 0.9.9) used a string key
66
+ configuration[:enabled] || configuration['enabled']
79
67
  end
80
68
 
81
69
  # check config is valid
82
70
  def valid_configuration?
83
- configured?
71
+ !configuration.empty?
84
72
  end
85
73
 
86
74
  # empty plugin configuration
75
+ # TODO: remove this method in after 0.9.9 release
87
76
  def configured?
88
77
  !configuration.empty?
89
78
  end
@@ -92,12 +81,12 @@ module Lolcommits
92
81
  # dont puts or print if the runner wants to be silent (stealth mode)
93
82
  def puts(*args)
94
83
  return if runner && runner.capture_stealth
95
- super(args)
84
+ super(*args)
96
85
  end
97
86
 
98
- def print(args)
87
+ def print(*args)
99
88
  return if runner && runner.capture_stealth
100
- super(args)
89
+ super(*args)
101
90
  end
102
91
 
103
92
  # helper to log errors with a message via debug
@@ -111,11 +100,6 @@ module Lolcommits
111
100
  super("#{self.class}: " + msg)
112
101
  end
113
102
 
114
- # identifying plugin name (for config, listing)
115
- def self.name
116
- 'plugin'
117
- end
118
-
119
103
  # Returns position(s) of when a plugin should run during the capture
120
104
  # process.
121
105
  #
@@ -130,6 +114,29 @@ module Lolcommits
130
114
  def self.runner_order
131
115
  []
132
116
  end
117
+
118
+ private
119
+
120
+ def configure_option_hash(option_hash, spacing_count = 0)
121
+ option_hash.keys.reduce({}) do |acc, option|
122
+ option_value = option_hash[option]
123
+ prefix = ' ' * spacing_count
124
+ if option_value.is_a?(Hash)
125
+ puts "#{prefix}#{option}:\n"
126
+ acc.merge(option => configure_option_hash(option_value, (spacing_count + 1)))
127
+ else
128
+ print "#{prefix}#{option.to_s.tr('_', ' ')}#{" (#{option_value})" unless option_value.nil?}: "
129
+ user_value = parse_user_input(gets.chomp.strip)
130
+
131
+ # if not enabled, disable and return without setting more options
132
+ # useful with nested hash configs, place enabled as first sub-option
133
+ # if answer is !true, no further sub-options will be prompted for
134
+ return { option => false } if option == :enabled && user_value != true
135
+
136
+ acc.merge(option => user_value)
137
+ end
138
+ end
139
+ end
133
140
  end
134
141
  end
135
142
  end
@@ -0,0 +1,51 @@
1
+ module Lolcommits
2
+ module Plugin
3
+ module ConfigurationHelper
4
+ # handle for bools, strings, ints and blanks from user input
5
+ def parse_user_input(str)
6
+ if 'true'.casecmp(str).zero?
7
+ true
8
+ elsif 'false'.casecmp(str).zero?
9
+ false
10
+ elsif str =~ /^[0-9]+$/
11
+ str.to_i
12
+ elsif str.strip.empty?
13
+ nil
14
+ else
15
+ str
16
+ end
17
+ end
18
+
19
+ # user input with autocomplete (via tab) through array of named values
20
+ #
21
+ # e.g.
22
+ # prompt_autocomplete_hash("Organization: ", orgs)
23
+ #
24
+ # where orgs are an array of hashes like so (with string keys):
25
+ # [
26
+ # { 'name' => 'some human readable name', 'value' => 1234 },
27
+ # ]
28
+ # User will be asked for Organization, can tab to autocomplete, and chosen
29
+ # value is returned.
30
+ def prompt_autocomplete_hash(prompt, items, name: 'name', value: 'value', suggest_words: 5)
31
+ words = items.map { |item| item[name] }.sort
32
+ puts "e.g. #{words.take(suggest_words).join(', ')}" if suggest_words > 0
33
+ completed_input = gets_autocomplete(prompt, words)
34
+ items.find { |item| item[name] == completed_input }[value]
35
+ end
36
+
37
+ private
38
+
39
+ def gets_autocomplete(prompt, words)
40
+ completion_handler = proc { |s| words.grep(/^#{Regexp.escape(s)}/) }
41
+ Readline.completion_append_character = ''
42
+ Readline.completion_proc = completion_handler
43
+
44
+ while (line = Readline.readline(prompt, true).strip)
45
+ return line if words.include?(line)
46
+ puts "'#{line}' not found"
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -8,6 +8,8 @@ module Lolcommits
8
8
  pm
9
9
  end
10
10
 
11
+ attr_reader :plugins
12
+
11
13
  def initialize
12
14
  @plugins = []
13
15
  end
@@ -19,29 +21,22 @@ module Lolcommits
19
21
  end
20
22
 
21
23
  def plugins_for(position)
22
- plugin_klasses.select { |p| Array(p.runner_order).include?(position) }
24
+ @plugins.select do |plugin|
25
+ Array(plugin.plugin_klass.runner_order).include?(position)
26
+ end
23
27
  end
24
28
 
25
- # @return [Lolcommits::Plugin] find first plugin matching name
29
+ # @return [Lolcommits::Plugin] finds the first plugin matching name
26
30
  def find_by_name(name)
27
- plugin_klasses.find { |plugin| plugin.name =~ /^#{name}/ }
31
+ @plugins.find { |plugin| plugin.name =~ /^#{name}/ } unless name.empty?
28
32
  end
29
33
 
30
34
  def plugin_names
31
- # TODO: when all plugins are gems, get names from GemPlugin with
32
- # @plugins.map(&:name)
33
- plugin_klasses.map(&:name).sort
35
+ @plugins.map(&:name).sort
34
36
  end
35
37
 
36
38
  private
37
39
 
38
- # @return [Array] find all classes inheriting from Lolcommits::Plugin::Base
39
- def plugin_klasses
40
- # TODO: when all plugins are gems, change this to
41
- # @plugins.map(&:plugin_klass)
42
- ObjectSpace.each_object(Class).select { |klass| klass < Lolcommits::Plugin::Base }
43
- end
44
-
45
40
  # @return [Array] find all installed and supported plugins, populate
46
41
  # @plugins array and return it
47
42
  def find_plugins
@@ -24,14 +24,27 @@ module Lolcommits
24
24
  self.message = vcs_info.message if message.nil?
25
25
  end
26
26
 
27
+ def execute_plugins_for(hook)
28
+ plugin_manager.plugins_for(hook).each do |gem_plugin|
29
+ plugin_name = gem_plugin.name
30
+ plugin = gem_plugin.plugin_instance(self)
31
+ next unless plugin.enabled?
32
+
33
+ if plugin.valid_configuration?
34
+ debug "Runner: #{plugin_name} is enabled with valid config, running #{hook}"
35
+ plugin.send("run_#{hook}")
36
+ else
37
+ puts "Warning: skipping plugin #{plugin_name} (invalid configuration, try: lolcommits --config -p #{plugin_name})"
38
+ end
39
+ end
40
+ end
41
+
27
42
  # wrap run to handle things that should happen before and after
28
43
  # this used to be handled with ActiveSupport::Callbacks, but
29
44
  # now we're just using a simple procedural list
30
45
  def run
31
46
  # do plugins that need to happen before capture
32
- plugin_manager.plugins_for(:pre_capture).each do |plugin|
33
- plugin.new(runner: self).execute_pre_capture
34
- end
47
+ execute_plugins_for(:pre_capture)
35
48
 
36
49
  # do main capture to snapshot_loc
37
50
  run_capture
@@ -42,14 +55,10 @@ module Lolcommits
42
55
  resize_snapshot!
43
56
 
44
57
  # execute post_capture plugins, use to alter the capture
45
- plugin_manager.plugins_for(:post_capture).each do |plugin|
46
- plugin.new(runner: self).execute_post_capture
47
- end
58
+ execute_plugins_for(:post_capture)
48
59
 
49
60
  # execute capture_ready plugins, capture is ready for export/sharing
50
- plugin_manager.plugins_for(:capture_ready).each do |plugin|
51
- plugin.new(runner: self).execute_capture_ready
52
- end
61
+ execute_plugins_for(:capture_ready)
53
62
 
54
63
  # clean away any tmp files
55
64
  cleanup!
@@ -1,4 +1,4 @@
1
1
  module Lolcommits
2
- VERSION = '0.9.8'.freeze
2
+ VERSION = '0.10.0.pre1'.freeze
3
3
  GEM_NAME = 'lolcommits'.freeze
4
4
  end
data/lolcommits.gemspec CHANGED
@@ -64,13 +64,12 @@ POSTINSTALL
64
64
  s.add_runtime_dependency('git', '~> 1.3.0')
65
65
 
66
66
  # included plugins
67
- s.add_runtime_dependency('lolcommits-loltext', '~> 0.0.4')
67
+ s.add_runtime_dependency('lolcommits-loltext', '~> 0.0.5')
68
68
 
69
69
  # development & test gems
70
70
  s.add_development_dependency('rdoc')
71
71
  s.add_development_dependency('pry')
72
72
  s.add_development_dependency('rubocop')
73
- s.add_development_dependency('travis')
74
73
  s.add_development_dependency('minitest')
75
74
  s.add_development_dependency('coveralls')
76
75
  s.add_development_dependency('ffaker')
@@ -23,10 +23,10 @@ class LolTest < MiniTest::Test
23
23
  commandcam_perms = File.lstat(File.join(Configuration::LOLCOMMITS_ROOT, 'vendor', 'ext', 'CommandCam', 'CommandCam.exe')).mode & 0o777
24
24
 
25
25
  assert imagesnap_perms == 0o755 || imagesnap_perms == 0o775,
26
- "expected perms of 755/775 but instead got #{format '%o', imagesnap_perms}"
26
+ "expected perms of 755/775 but instead got #{format '%<perms>o', perms: imagesnap_perms}"
27
27
  assert videosnap_perms == 0o755 || videosnap_perms == 0o775,
28
- "expected perms of 755/775 but instead got #{format '%o', videosnap_perms}"
28
+ "expected perms of 755/775 but instead got #{format '%<perms>o', perms: videosnap_perms}"
29
29
  assert commandcam_perms == 0o755 || commandcam_perms == 0o775,
30
- "expected perms of 755/775 but instead got #{format '%o', commandcam_perms}"
30
+ "expected perms of 755/775 but instead got #{format '%<perms>o', perms: commandcam_perms}"
31
31
  end
32
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lolcommits
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.8
4
+ version: 0.10.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Rothenberg
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-12-05 00:00:00.000000000 Z
12
+ date: 2018-01-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aruba
@@ -171,14 +171,14 @@ dependencies:
171
171
  requirements:
172
172
  - - "~>"
173
173
  - !ruby/object:Gem::Version
174
- version: 0.0.4
174
+ version: 0.0.5
175
175
  type: :runtime
176
176
  prerelease: false
177
177
  version_requirements: !ruby/object:Gem::Requirement
178
178
  requirements:
179
179
  - - "~>"
180
180
  - !ruby/object:Gem::Version
181
- version: 0.0.4
181
+ version: 0.0.5
182
182
  - !ruby/object:Gem::Dependency
183
183
  name: rdoc
184
184
  requirement: !ruby/object:Gem::Requirement
@@ -221,20 +221,6 @@ dependencies:
221
221
  - - ">="
222
222
  - !ruby/object:Gem::Version
223
223
  version: '0'
224
- - !ruby/object:Gem::Dependency
225
- name: travis
226
- requirement: !ruby/object:Gem::Requirement
227
- requirements:
228
- - - ">="
229
- - !ruby/object:Gem::Version
230
- version: '0'
231
- type: :development
232
- prerelease: false
233
- version_requirements: !ruby/object:Gem::Requirement
234
- requirements:
235
- - - ">="
236
- - !ruby/object:Gem::Version
237
- version: '0'
238
224
  - !ruby/object:Gem::Dependency
239
225
  name: minitest
240
226
  requirement: !ruby/object:Gem::Requirement
@@ -309,10 +295,10 @@ files:
309
295
  - config/cucumber.yml
310
296
  - features/bugs.feature
311
297
  - features/lolcommits.feature
312
- - features/plugins.feature
313
298
  - features/step_definitions/lolcommits_steps.rb
314
299
  - features/support/env.rb
315
300
  - features/support/path_helpers.rb
301
+ - lib/core_ext/hash/hash_dig.rb
316
302
  - lib/core_ext/mercurial-ruby/command.rb
317
303
  - lib/core_ext/mercurial-ruby/shell.rb
318
304
  - lib/core_ext/mini_magick/utilities.rb
@@ -340,6 +326,7 @@ files:
340
326
  - lib/lolcommits/installation.rb
341
327
  - lib/lolcommits/platform.rb
342
328
  - lib/lolcommits/plugin/base.rb
329
+ - lib/lolcommits/plugin/configuration_helper.rb
343
330
  - lib/lolcommits/plugin/lol_yammer.rb
344
331
  - lib/lolcommits/plugin_manager.rb
345
332
  - lib/lolcommits/runner.rb
@@ -388,9 +375,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
388
375
  version: '2.0'
389
376
  required_rubygems_version: !ruby/object:Gem::Requirement
390
377
  requirements:
391
- - - ">="
378
+ - - ">"
392
379
  - !ruby/object:Gem::Version
393
- version: '0'
380
+ version: 1.3.1
394
381
  requirements:
395
382
  - imagemagick
396
383
  - a webcam
@@ -399,4 +386,11 @@ rubygems_version: 2.7.3
399
386
  signing_key:
400
387
  specification_version: 4
401
388
  summary: Capture webcam image on git commit for lulz.
402
- test_files: []
389
+ test_files:
390
+ - features/bugs.feature
391
+ - features/lolcommits.feature
392
+ - features/step_definitions/lolcommits_steps.rb
393
+ - features/support/env.rb
394
+ - features/support/path_helpers.rb
395
+ - test/images/test_image.jpg
396
+ - test/lolcommits_test.rb
@@ -1,20 +0,0 @@
1
- Feature: Plugins Work
2
-
3
- Background:
4
- Given a mocked home directory
5
-
6
- @slow_process @unstable
7
- Scenario: Lolcommits.com integration works
8
- Given I am in a git repo named "dot_com" with lolcommits enabled
9
- When I run `lolcommits --config` interactively
10
- And I wait for output to contain "Name of plugin to configure:"
11
- Then I type "dot_com"
12
- And I wait for output to contain "enabled:"
13
- Then I type "true"
14
- And I wait for output to contain "api_key:"
15
- Then I type "b2a70ac0b64e012fa61522000a8c42dc"
16
- And I wait for output to contain "api_secret:"
17
- Then I type "b2a70ac0b64e012fa61522000a8c42dc"
18
- And I wait for output to contain "repo_id:"
19
- Then I type "b2a70ac0b64e012fa61522000a8c42dc"
20
- Then the output should contain "Successfully configured plugin: dot_com"