lolcommits 0.5.7 → 0.5.8.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +8 -8
  2. data/.rubocop.yml +1 -0
  3. data/.rubocop_todo.yml +16 -161
  4. data/.travis.yml +11 -4
  5. data/Gemfile +2 -2
  6. data/Rakefile +24 -32
  7. data/bin/lolcommits +62 -125
  8. data/features/bugs.feature +24 -9
  9. data/features/lolcommits.feature +136 -145
  10. data/features/plugins.feature +16 -33
  11. data/features/step_definitions/lolcommits_steps.rb +91 -71
  12. data/features/support/env.rb +18 -48
  13. data/features/support/path_helpers.rb +9 -8
  14. data/lib/lolcommits.rb +3 -10
  15. data/lib/lolcommits/capturer.rb +10 -2
  16. data/lib/lolcommits/capturer/capture_linux.rb +1 -1
  17. data/lib/lolcommits/capturer/capture_linux_animated.rb +12 -13
  18. data/lib/lolcommits/capturer/capture_mac_animated.rb +12 -13
  19. data/lib/lolcommits/cli/fatals.rb +77 -0
  20. data/lib/lolcommits/cli/launcher.rb +29 -0
  21. data/lib/lolcommits/cli/process_runner.rb +48 -0
  22. data/lib/lolcommits/cli/timelapse_gif.rb +45 -0
  23. data/lib/lolcommits/configuration.rb +30 -133
  24. data/lib/lolcommits/git_info.rb +58 -28
  25. data/lib/lolcommits/installation.rb +11 -21
  26. data/lib/lolcommits/platform.rb +134 -0
  27. data/lib/lolcommits/plugin.rb +2 -2
  28. data/lib/lolcommits/plugins/dot_com.rb +15 -15
  29. data/lib/lolcommits/plugins/lol_protonet.rb +68 -0
  30. data/lib/lolcommits/plugins/lol_twitter.rb +12 -15
  31. data/lib/lolcommits/plugins/lol_yammer.rb +4 -6
  32. data/lib/lolcommits/plugins/lolsrv.rb +8 -11
  33. data/lib/lolcommits/plugins/loltext.rb +7 -7
  34. data/lib/lolcommits/plugins/tranzlate.rb +70 -70
  35. data/lib/lolcommits/plugins/uploldz.rb +8 -8
  36. data/lib/lolcommits/runner.rb +36 -35
  37. data/lib/lolcommits/version.rb +1 -1
  38. data/lolcommits.gemspec +11 -10
  39. data/test/lolcommits_test.rb +35 -0
  40. data/test/plugins_test.rb +52 -0
  41. metadata +41 -20
  42. data/test/test_lolcommits.rb +0 -78
@@ -3,50 +3,80 @@ module Lolcommits
3
3
  class GitInfo
4
4
  include Methadone::CLILogging
5
5
  attr_accessor :sha, :message, :repo_internal_path, :repo, :url,
6
- :author_name, :author_email
6
+ :author_name, :author_email, :branch
7
7
 
8
- GIT_URL_REGEX = /.*[:]([\/\w\-]*).git/
8
+ GIT_URL_REGEX = %r{.*[:]([\/\w\-]*).git}
9
9
 
10
10
  def initialize
11
- debug 'GitInfo: attempting to read local repository'
12
- g = Git.open('.')
13
- debug 'GitInfo: reading commits logs'
14
- commit = g.log.first
15
- debug "GitInfo: most recent commit is '#{commit}'"
16
-
17
- self.message = commit.message.split("\n").first
18
- self.sha = commit.sha[0..10]
19
- self.repo_internal_path = g.repo.path
20
-
21
- if g.remote.url
22
- self.url = remote_https_url(g.remote.url)
23
- match = g.remote.url.match(GIT_URL_REGEX)
24
- end
25
-
26
- if match
27
- self.repo = match[1]
28
- elsif !g.repo.path.empty?
29
- self.repo = g.repo.path.split(File::SEPARATOR)[-2]
30
- end
31
-
32
- if commit.author
33
- self.author_name = commit.author.name
34
- self.author_email = commit.author.email
35
- end
36
-
37
11
  debug 'GitInfo: parsed the following values from commit:'
38
12
  debug "GitInfo: \t#{message}"
39
13
  debug "GitInfo: \t#{sha}"
40
14
  debug "GitInfo: \t#{repo_internal_path}"
41
15
  debug "GitInfo: \t#{repo}"
16
+ debug "GitInfo: \t#{branch}"
42
17
  debug "GitInfo: \t#{author_name}" if author_name
43
18
  debug "GitInfo: \t#{author_email}" if author_email
44
19
  end
45
20
 
21
+ def branch
22
+ @branch ||= repository.current_branch
23
+ end
24
+
25
+ def message
26
+ @message ||= begin
27
+ message = last_commit.message || ''
28
+ message.split("\n").first
29
+ end
30
+ end
31
+
32
+ def sha
33
+ @sha ||= last_commit.sha[0..10]
34
+ end
35
+
36
+ def repo_internal_path
37
+ @repo_internal_path ||= repository.repo.path
38
+ end
39
+
40
+ def url
41
+ @url ||= begin
42
+ remote_https_url(repository.remote.url) if repository.remote
43
+ end
44
+ end
45
+
46
+ def repo
47
+ @repo ||= begin
48
+ if repository.remote && repository.remote.url
49
+ match = repository.remote.url.match(GIT_URL_REGEX)
50
+ end
51
+
52
+ if match
53
+ match[1]
54
+ elsif !repository.repo.path.empty?
55
+ repository.repo.path.split(File::SEPARATOR)[-2]
56
+ end
57
+ end
58
+ end
59
+
60
+ def author_name
61
+ @author_name ||= last_commit.author.name if last_commit.author
62
+ end
63
+
64
+ def author_email
65
+ @author_email ||= last_commit.author.email if last_commit.author
66
+ end
67
+
46
68
  private
47
69
 
48
70
  def remote_https_url(url)
49
71
  url.gsub(':', '/').gsub(/^git@/, 'https://').gsub(/\.git$/, '') + '/commit/'
50
72
  end
73
+
74
+ def repository(path = '.')
75
+ @repository ||= Git.open(path)
76
+ end
77
+
78
+ def last_commit
79
+ @commit ||= repository.log.first
80
+ end
51
81
  end
52
82
  end
@@ -11,15 +11,13 @@ module Lolcommits
11
11
  # IF --ENABLE, DO ENABLE
12
12
  #
13
13
  def self.do_enable
14
- if not File.directory?('.git')
14
+ unless File.directory?('.git')
15
15
  fatal "You don't appear to be in the base directory of a git project."
16
16
  exit 1
17
17
  end
18
18
 
19
19
  # its possible a hooks dir doesnt exist, so create it if so
20
- if not File.directory?(HOOK_DIR)
21
- Dir.mkdir(HOOK_DIR)
22
- end
20
+ Dir.mkdir(HOOK_DIR) unless File.directory?(HOOK_DIR)
23
21
 
24
22
  # should add a shebang (or not) adding will rewrite hook file
25
23
  add_shebang = false
@@ -40,9 +38,7 @@ module Lolcommits
40
38
  end
41
39
 
42
40
  File.open(HOOK_PATH, add_shebang ? 'w' : 'a') do |f|
43
- if add_shebang
44
- f.write("#!/bin/sh\n")
45
- end
41
+ f.write("#!/bin/sh\n") if add_shebang
46
42
  f.write(hook_script)
47
43
  end
48
44
 
@@ -62,7 +58,7 @@ module Lolcommits
62
58
  if lolcommits_hook_exists?
63
59
  remove_existing_hook!
64
60
  info "uninstalled lolcommits hook (from #{HOOK_PATH})"
65
- elsif File.exists?(HOOK_PATH)
61
+ elsif File.exist?(HOOK_PATH)
66
62
  info "couldn't find an lolcommits hook (at #{HOOK_PATH})"
67
63
  if File.read(HOOK_PATH) =~ /lolcommit/
68
64
  info "warning: an older-style lolcommit hook may still exist, edit #{HOOK_PATH} to remove it manually"
@@ -72,11 +68,9 @@ module Lolcommits
72
68
  end
73
69
  end
74
70
 
75
- protected
76
-
77
- def self.hook_script(add_shebang = true)
78
- ruby_path = Lolcommits::Configuration.command_which('ruby', true)
79
- imagick_path = Lolcommits::Configuration.command_which('identify', true)
71
+ def self.hook_script(_add_shebang = true)
72
+ ruby_path = Lolcommits::Platform.command_which('ruby', true)
73
+ imagick_path = Lolcommits::Platform.command_which('identify', true)
80
74
  locale_export = "export LANG=\"#{ENV['LANG']}\"\n"
81
75
  hook_export = "export PATH=\"#{ruby_path}:#{imagick_path}:$PATH\"\n"
82
76
  capture_cmd = 'lolcommits --capture'
@@ -91,7 +85,7 @@ EOS
91
85
 
92
86
  # does a git hook exist at all?
93
87
  def self.hook_file_exists?
94
- File.exists?(HOOK_PATH)
88
+ File.exist?(HOOK_PATH)
95
89
  end
96
90
 
97
91
  # does a git hook exist with lolcommits commands?
@@ -102,7 +96,7 @@ EOS
102
96
 
103
97
  # does the git hook file have a good shebang?
104
98
  def self.good_shebang?
105
- File.read(HOOK_PATH).lines.first =~ /^\#\!\/bin\/.*sh/
99
+ File.read(HOOK_PATH).lines.first =~ %r{^\#\!\/bin\/.*sh}
106
100
  end
107
101
 
108
102
  def self.remove_existing_hook!
@@ -111,15 +105,11 @@ EOS
111
105
  skip = false
112
106
 
113
107
  hook.lines.each do |line|
114
- if !skip && (line =~ /lolcommits.*\(begin\)/)
115
- skip = true
116
- end
108
+ skip = true if !skip && (line =~ /lolcommits.*\(begin\)/)
117
109
 
118
110
  out << line unless skip
119
111
 
120
- if skip && (line =~ /lolcommits.*\(end\)/)
121
- skip = false
122
- end
112
+ skip = false if skip && (line =~ /lolcommits.*\(end\)/)
123
113
  end
124
114
 
125
115
  out.close
@@ -0,0 +1,134 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'mini_magick'
3
+
4
+ module Lolcommits
5
+ class Platform
6
+ # A convenience name for the platform. Mainly used for metaprogramming.
7
+ # @return String
8
+ def self.platform
9
+ if platform_fakeplatform? then ENV['LOLCOMMITS_FAKEPLATFORM']
10
+ elsif platform_fakecapture? then 'Fake'
11
+ elsif platform_mac? then 'Mac'
12
+ elsif platform_linux? then 'Linux'
13
+ elsif platform_windows? then 'Windows'
14
+ elsif platform_cygwin? then 'Cygwin'
15
+ else
16
+ fail 'Unknown / Unsupported Platform.'
17
+ end
18
+ end
19
+
20
+ # Are we on a Mac platform?
21
+ # @return Boolean
22
+ def self.platform_mac?
23
+ RUBY_PLATFORM.to_s.downcase.include?('darwin')
24
+ end
25
+
26
+ # Are we on a Linux platform?
27
+ # @return Boolean
28
+ def self.platform_linux?
29
+ RUBY_PLATFORM.to_s.downcase.include?('linux')
30
+ end
31
+
32
+ # Are we on a Windows platform?
33
+ # @return Boolean
34
+ def self.platform_windows?
35
+ !RUBY_PLATFORM.match(/(win|w)32/)
36
+ end
37
+
38
+ # Are we on a Cygwin platform?
39
+ # @return Boolean
40
+ def self.platform_cygwin?
41
+ RUBY_PLATFORM.to_s.downcase.include?('cygwin')
42
+ end
43
+
44
+ # Are we currently faking webcam capture for test purposes?
45
+ # @return Boolean
46
+ def self.platform_fakecapture?
47
+ (ENV['LOLCOMMITS_FAKECAPTURE'] == '1' || false)
48
+ end
49
+
50
+ # Are we currently overriding and faking the platform entirely?
51
+ # @todo possibly make this a private method?
52
+ # @return Boolean
53
+ def self.platform_fakeplatform?
54
+ ENV['LOLCOMMITS_FAKEPLATFORM']
55
+ end
56
+
57
+ # Is the platform capable of capturing animated GIFs from webcam?
58
+ # @return Boolean
59
+ def self.can_animate?
60
+ # FIXME: this is currently matching against string instead of
61
+ # simply returning platform_mac? || platform_linux?
62
+ # This is not ideal... but otherwise overriding platform via
63
+ # LOLCOMMITS_FAKEPLATFORM when running cucumber tests won't work.
64
+ # We should come up with a better solution.
65
+ %w(Mac Linux).include? platform
66
+ end
67
+
68
+ # Is a valid install of imagemagick present on the system?
69
+ # @return Boolean
70
+ def self.valid_imagemagick_installed?
71
+ return false unless command_which('identify')
72
+ return false unless command_which('mogrify')
73
+ # you'd expect the below to work on its own, but it only handles old versions
74
+ # and will throw an exception if IM is not installed in PATH
75
+ MiniMagick.valid_version_installed?
76
+ rescue
77
+ return false
78
+ end
79
+
80
+ # Is a valid install of ffmpeg present on the system?
81
+ #
82
+ # @note For now, this just checks for presence, any version should work.
83
+ # @return Boolean
84
+ def self.valid_ffmpeg_installed?
85
+ command_which('ffmpeg')
86
+ end
87
+
88
+ # Cross-platform way of finding an executable in the $PATH.
89
+ #
90
+ # Idea taken from http://bit.ly/qDaTbY, if only_path is true, only the path
91
+ # is returned (not the path and command)
92
+ #
93
+ # @example
94
+ # command_which('ruby') #=> /usr/bin/ruby
95
+ #
96
+ # @return Boolean
97
+ def self.command_which(cmd, only_path = false)
98
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
99
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
100
+ exts.each do |ext|
101
+ exe = "#{path}/#{cmd}#{ext}"
102
+ return only_path ? path : exe if File.executable? exe
103
+ end
104
+ end
105
+ nil
106
+ end
107
+
108
+ # Is `git config color.ui` set to 'always'?
109
+ #
110
+ # Due to a bug in the ruby-git library, git config for color.ui cannot be
111
+ # set to 'always' or it won't read properly.
112
+ #
113
+ # This helper method let's us check for that error condition so we can
114
+ # alert the user in the CLI tool.
115
+ #
116
+ # @return Boolean
117
+ def self.git_config_color_always?
118
+ `git config color.ui`.chomp =~ /always/
119
+ end
120
+
121
+ # Returns a list of system camera devices in a format suitable to display
122
+ # to the user.
123
+ #
124
+ # @note Currently only functions on Mac.
125
+ # @return String
126
+ def self.device_list
127
+ # TODO: handle other platforms here (linux/windows)
128
+ if Platform.platform_mac?
129
+ capturer = Lolcommits::CaptureMacAnimated.new
130
+ `#{capturer.executable_path} -l`
131
+ end
132
+ end
133
+ end
134
+ end
@@ -46,7 +46,7 @@ module Lolcommits
46
46
  # ask for plugin options
47
47
  def configure_options!
48
48
  puts "Configuring plugin: #{self.class.name}\n"
49
- options.reduce(Hash.new) do |acc, option|
49
+ options.reduce({}) do |acc, option|
50
50
  print "#{option}: "
51
51
  val = parse_user_input(STDIN.gets.strip)
52
52
  # check enabled option isn't a String
@@ -103,7 +103,7 @@ module Lolcommits
103
103
 
104
104
  # uniform debug logging for plugins
105
105
  def debug(msg)
106
- super("Plugin: #{self.class.to_s}: " + msg)
106
+ super("Plugin: #{self.class}: " + msg)
107
107
  end
108
108
 
109
109
  # identifying plugin name (for config, listing)
@@ -7,27 +7,27 @@ module Lolcommits
7
7
 
8
8
  def initialize(runner)
9
9
  super
10
- self.options.concat(['api_key', 'api_secret', 'repo_id'])
10
+ options.concat(%w(api_key api_secret repo_id))
11
11
  end
12
12
 
13
13
  def run_postcapture
14
14
  return unless valid_configuration?
15
15
 
16
16
  t = Time.now.to_i.to_s
17
- resp = HTTMultiParty.post("#{BASE_URL}/git_commits.json",
18
- :body => {
19
- :git_commit => {
20
- :sha => self.runner.sha,
21
- :repo_external_id => configuration['repo_id'],
22
- :image => File.open(self.runner.main_image),
23
- :raw => File.open(self.runner.snapshot_loc)
24
- },
25
-
26
- :key => configuration['api_key'],
27
- :t => t,
28
- :token => Digest::SHA1.hexdigest(configuration['api_secret'] + t)
29
- }
30
- )
17
+ HTTMultiParty.post(
18
+ "#{BASE_URL}/git_commits.json",
19
+ :body => {
20
+ :git_commit => {
21
+ :sha => runner.sha,
22
+ :repo_external_id => configuration['repo_id'],
23
+ :image => File.open(runner.main_image),
24
+ :raw => File.open(runner.snapshot_loc)
25
+ },
26
+
27
+ :key => configuration['api_key'],
28
+ :t => t,
29
+ :token => Digest::SHA1.hexdigest(configuration['api_secret'] + t)
30
+ })
31
31
  rescue => e
32
32
  log_error(e, "ERROR: HTTMultiParty POST FAILED #{e.class} - #{e.message}")
33
33
  end
@@ -0,0 +1,68 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'rest_client'
3
+
4
+ module Lolcommits
5
+ class LolProtonet < Plugin
6
+ def initialize(runner)
7
+ super
8
+ options.concat(%w(api_token api_endpoint))
9
+ end
10
+
11
+ def run_postcapture
12
+ return unless valid_configuration?
13
+
14
+ debug "Posting capture to #{configuration['endpoint']}"
15
+ RestClient.post(
16
+ api_url,
17
+ {
18
+ :files => [File.new(runner.main_image)],
19
+ :message => message
20
+ },
21
+ 'X-Protonet-Token' => configuration['api_token']
22
+ )
23
+ end
24
+
25
+ def api_url
26
+ configuration['api_endpoint']
27
+ end
28
+
29
+ def message
30
+ "commited some #{random_adjective} #{random_object} to #{runner.git_info.repo}@#{runner.sha} (#{runner.git_info.branch}) "
31
+ end
32
+
33
+ def random_object
34
+ objects = %w(screws bolts exceptions errors cookies)
35
+
36
+ objects.sample
37
+ end
38
+
39
+ def random_adjective
40
+ adjectives = ['awesome', 'great', 'interesting', 'cool', 'EPIC', 'gut', 'good', 'pansy',
41
+ 'powerful', 'boring', 'quirky', 'untested', 'german', 'iranian', 'neutral', 'crazy', 'well tested',
42
+ 'jimmy style', 'nasty', 'bibliographical (we received complaints about the original wording)',
43
+ 'bombdiggidy', 'narly', 'spiffy', 'smashing', 'xing style',
44
+ 'leo apotheker style', 'black', 'white', 'yellow', 'shaggy', 'tasty', 'mind bending', 'JAY-Z',
45
+ 'Kanye (the best ever)', '* Toby Keith was here *', 'splendid', 'stupendulous',
46
+ '(freedom fries!)', '[vote RON PAUL]', '- these are not my glasses -', 'typical pansy',
47
+ '- ze goggles zey do nothing! -', 'almost working', 'legen- wait for it -', '-dairy!',
48
+ ' - Tavonius would be proud of this - ', 'Meg FAILMAN!', '- very brofessional of you -',
49
+ 'heartbleeding', 'juciy', 'supercalifragilisticexpialidocious', 'failing', 'loving'
50
+ ]
51
+ adjectives.sample
52
+ end
53
+
54
+ def configured?
55
+ !configuration['enabled'].nil? &&
56
+ configuration['api_token'] &&
57
+ configuration['api_endpoint']
58
+ end
59
+
60
+ def self.name
61
+ 'lolprotonet'
62
+ end
63
+
64
+ def self.runner_order
65
+ :postcapture
66
+ end
67
+ end
68
+ end