lolcommits 0.5.7 → 0.5.8.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 +8 -8
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +16 -161
- data/.travis.yml +11 -4
- data/Gemfile +2 -2
- data/Rakefile +24 -32
- data/bin/lolcommits +62 -125
- data/features/bugs.feature +24 -9
- data/features/lolcommits.feature +136 -145
- data/features/plugins.feature +16 -33
- data/features/step_definitions/lolcommits_steps.rb +91 -71
- data/features/support/env.rb +18 -48
- data/features/support/path_helpers.rb +9 -8
- data/lib/lolcommits.rb +3 -10
- data/lib/lolcommits/capturer.rb +10 -2
- data/lib/lolcommits/capturer/capture_linux.rb +1 -1
- data/lib/lolcommits/capturer/capture_linux_animated.rb +12 -13
- data/lib/lolcommits/capturer/capture_mac_animated.rb +12 -13
- data/lib/lolcommits/cli/fatals.rb +77 -0
- data/lib/lolcommits/cli/launcher.rb +29 -0
- data/lib/lolcommits/cli/process_runner.rb +48 -0
- data/lib/lolcommits/cli/timelapse_gif.rb +45 -0
- data/lib/lolcommits/configuration.rb +30 -133
- data/lib/lolcommits/git_info.rb +58 -28
- data/lib/lolcommits/installation.rb +11 -21
- data/lib/lolcommits/platform.rb +134 -0
- data/lib/lolcommits/plugin.rb +2 -2
- data/lib/lolcommits/plugins/dot_com.rb +15 -15
- data/lib/lolcommits/plugins/lol_protonet.rb +68 -0
- data/lib/lolcommits/plugins/lol_twitter.rb +12 -15
- data/lib/lolcommits/plugins/lol_yammer.rb +4 -6
- data/lib/lolcommits/plugins/lolsrv.rb +8 -11
- data/lib/lolcommits/plugins/loltext.rb +7 -7
- data/lib/lolcommits/plugins/tranzlate.rb +70 -70
- data/lib/lolcommits/plugins/uploldz.rb +8 -8
- data/lib/lolcommits/runner.rb +36 -35
- data/lib/lolcommits/version.rb +1 -1
- data/lolcommits.gemspec +11 -10
- data/test/lolcommits_test.rb +35 -0
- data/test/plugins_test.rb +52 -0
- metadata +41 -20
- data/test/test_lolcommits.rb +0 -78
data/lib/lolcommits/git_info.rb
CHANGED
@@ -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 =
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
76
|
-
|
77
|
-
|
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.
|
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 =~
|
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
|
data/lib/lolcommits/plugin.rb
CHANGED
@@ -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(
|
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
|
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
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|