lolcommits 0.9.8 → 0.10.0.pre1

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: 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"