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.
- 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
|