snapgit 0.6.4

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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.editorconfig +17 -0
  4. data/.gitattributes +1 -0
  5. data/.gitignore +14 -0
  6. data/.rubocop.yml +10 -0
  7. data/.rubocop_todo.yml +57 -0
  8. data/.travis.yml +42 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE +165 -0
  11. data/README.md +28 -0
  12. data/Rakefile +79 -0
  13. data/bin/lolcommits +335 -0
  14. data/bin/snapgit +14 -0
  15. data/config/cucumber.yml +2 -0
  16. data/features/bugs.feature +63 -0
  17. data/features/lolcommits.feature +286 -0
  18. data/features/plugins.feature +20 -0
  19. data/features/step_definitions/lolcommits_steps.rb +142 -0
  20. data/features/support/env.rb +61 -0
  21. data/features/support/path_helpers.rb +39 -0
  22. data/lib/core_ext/class.rb +8 -0
  23. data/lib/core_ext/mini_magick/utilities.rb +15 -0
  24. data/lib/lolcommits.rb +34 -0
  25. data/lib/lolcommits/capturer.rb +24 -0
  26. data/lib/lolcommits/capturer/capture_cygwin.rb +22 -0
  27. data/lib/lolcommits/capturer/capture_fake.rb +9 -0
  28. data/lib/lolcommits/capturer/capture_linux.rb +45 -0
  29. data/lib/lolcommits/capturer/capture_linux_animated.rb +72 -0
  30. data/lib/lolcommits/capturer/capture_mac.rb +23 -0
  31. data/lib/lolcommits/capturer/capture_mac_animated.rb +73 -0
  32. data/lib/lolcommits/capturer/capture_windows.rb +22 -0
  33. data/lib/lolcommits/cli/fatals.rb +77 -0
  34. data/lib/lolcommits/cli/launcher.rb +29 -0
  35. data/lib/lolcommits/cli/process_runner.rb +48 -0
  36. data/lib/lolcommits/cli/timelapse_gif.rb +45 -0
  37. data/lib/lolcommits/configuration.rb +138 -0
  38. data/lib/lolcommits/git_info.rb +82 -0
  39. data/lib/lolcommits/init.rb +121 -0
  40. data/lib/lolcommits/installation.rb +128 -0
  41. data/lib/lolcommits/platform.rb +127 -0
  42. data/lib/lolcommits/plugin.rb +130 -0
  43. data/lib/lolcommits/plugins/dot_com.rb +50 -0
  44. data/lib/lolcommits/plugins/lol_protonet.rb +68 -0
  45. data/lib/lolcommits/plugins/lol_slack.rb +68 -0
  46. data/lib/lolcommits/plugins/lol_tumblr.rb +127 -0
  47. data/lib/lolcommits/plugins/lol_twitter.rb +155 -0
  48. data/lib/lolcommits/plugins/lol_yammer.rb +85 -0
  49. data/lib/lolcommits/plugins/lolsrv.rb +59 -0
  50. data/lib/lolcommits/plugins/loltext.rb +147 -0
  51. data/lib/lolcommits/plugins/snapgit.rb +167 -0
  52. data/lib/lolcommits/plugins/tranzlate.rb +115 -0
  53. data/lib/lolcommits/plugins/uploldz.rb +65 -0
  54. data/lib/lolcommits/runner.rb +134 -0
  55. data/lib/lolcommits/version.rb +5 -0
  56. data/snapgit.gemspec +63 -0
  57. data/test/images/test_image.jpg +0 -0
  58. data/test/lolcommits_test.rb +35 -0
  59. data/test/plugins_test.rb +52 -0
  60. data/vendor/ext/CommandCam/COPYING +674 -0
  61. data/vendor/ext/CommandCam/CommandCam.exe +0 -0
  62. data/vendor/ext/CommandCam/LICENSE +16 -0
  63. data/vendor/ext/imagesnap/ReadMeOrDont.rtf +117 -0
  64. data/vendor/ext/imagesnap/imagesnap +0 -0
  65. data/vendor/ext/videosnap/videosnap +0 -0
  66. data/vendor/fonts/Lato.ttf +0 -0
  67. data/vendor/logos/Snapgit.png +0 -0
  68. metadata +509 -0
@@ -0,0 +1,128 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ #
4
+ # Methods to handle enabling and disabling of lolcommits
5
+ #
6
+ class Installation
7
+ HOOK_PATH = File.join '.git', 'hooks', 'post-commit'
8
+ HOOK_DIR = File.join '.git', 'hooks'
9
+
10
+ #
11
+ # IF --ENABLE, DO ENABLE
12
+ #
13
+ def self.do_enable
14
+ unless File.directory?('.git')
15
+ fatal "You don't appear to be in the base directory of a git project."
16
+ exit 1
17
+ end
18
+
19
+ # its possible a hooks dir doesnt exist, so create it if so
20
+ Dir.mkdir(HOOK_DIR) unless File.directory?(HOOK_DIR)
21
+
22
+ # should add a shebang (or not) adding will rewrite hook file
23
+ add_shebang = false
24
+ if hook_file_exists?
25
+ # clear away any existing lolcommits hook
26
+ remove_existing_hook! if lolcommits_hook_exists?
27
+
28
+ # if file is empty we should add a shebang (and rewrite hook)
29
+ if File.read(HOOK_PATH).strip.empty?
30
+ add_shebang = true
31
+ elsif !good_shebang?
32
+ # look for good shebang in existing hook, abort if none found
33
+ warn "the existing hook (at #{HOOK_PATH}) doesn't start with a good shebang; like #!/bin/sh"
34
+ exit 1
35
+ end
36
+ else
37
+ add_shebang = true
38
+ end
39
+
40
+ File.open(HOOK_PATH, add_shebang ? 'w' : 'a') do |f|
41
+ f.write("#!/bin/sh\n") if add_shebang
42
+ f.write(hook_script)
43
+ end
44
+
45
+ FileUtils.chmod 0755, HOOK_PATH
46
+
47
+ info 'installed lolcommit hook to:'
48
+ info " -> #{File.expand_path(HOOK_PATH)}"
49
+ info '(to remove later, you can use: lolcommits --disable)'
50
+ # we dont symlink, but rather install a small stub that calls the one from path
51
+ # that way, as gem version changes, script updates even if new file thus breaking symlink
52
+ end
53
+
54
+ #
55
+ # IF --DISABLE, DO DISABLE
56
+ #
57
+ def self.do_disable
58
+ if lolcommits_hook_exists?
59
+ remove_existing_hook!
60
+ info "uninstalled lolcommits hook (from #{HOOK_PATH})"
61
+ elsif File.exist?(HOOK_PATH)
62
+ info "couldn't find an lolcommits hook (at #{HOOK_PATH})"
63
+ if File.read(HOOK_PATH) =~ /lolcommit/
64
+ info "warning: an older-style lolcommit hook may still exist, edit #{HOOK_PATH} to remove it manually"
65
+ end
66
+ else
67
+ info "no post commit hook found (at #{HOOK_PATH}), so there is nothing to uninstall"
68
+ end
69
+ end
70
+
71
+ def self.hook_script
72
+ ruby_path = Lolcommits::Platform.command_which('ruby', true)
73
+ imagick_path = Lolcommits::Platform.command_which('identify', true)
74
+
75
+ if Lolcommits::Platform.platform_windows?
76
+ hook_export = "set path \"#{ruby_path};#{imagick_path};%PATH%\"\n"
77
+ else
78
+ locale_export = "export LANG=\"#{ENV['LANG']}\"\n"
79
+ hook_export = "export PATH=\"#{ruby_path}:#{imagick_path}:$PATH\"\n"
80
+ end
81
+
82
+ capture_cmd = 'lolcommits --capture'
83
+ capture_args = ' '
84
+ capture_args += "#{ARGV[1..-1].join(' ')} " if ARGV.length > 1
85
+ capture_args += ENV['LOLCOMMITS_INIT_PARAMS'].to_s
86
+
87
+ <<-EOS
88
+ ### lolcommits hook (begin) ###
89
+ if [ ! -d "$GIT_DIR/rebase-merge" ]; then
90
+ #{locale_export}#{hook_export}#{capture_cmd}#{capture_args}
91
+ fi
92
+ ### lolcommits hook (end) ###
93
+ EOS
94
+ end
95
+
96
+ # does a git hook exist at all?
97
+ def self.hook_file_exists?
98
+ File.exist?(HOOK_PATH)
99
+ end
100
+
101
+ # does a git hook exist with lolcommits commands?
102
+ def self.lolcommits_hook_exists?
103
+ hook_file_exists? &&
104
+ File.read(HOOK_PATH).to_s =~ /lolcommits.*\(begin\)(.*\n)*.*lolcommits.*\(end\)/
105
+ end
106
+
107
+ # does the git hook file have a good shebang?
108
+ def self.good_shebang?
109
+ File.read(HOOK_PATH).lines.first =~ %r{^\#\!\/bin\/.*sh}
110
+ end
111
+
112
+ def self.remove_existing_hook!
113
+ hook = File.read(HOOK_PATH)
114
+ out = File.open(HOOK_PATH, 'w')
115
+ skip = false
116
+
117
+ hook.lines.each do |line|
118
+ skip = true if !skip && (line =~ /lolcommits.*\(begin\)/)
119
+
120
+ out << line unless skip
121
+
122
+ skip = false if skip && (line =~ /lolcommits.*\(end\)/)
123
+ end
124
+
125
+ out.close
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,127 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'mini_magick'
3
+ require 'rbconfig'
4
+
5
+ module Lolcommits
6
+ class Platform
7
+ # The capturer class constant to use
8
+ # @return Class
9
+ def self.capturer_class(animate = false)
10
+ if ENV['LOLCOMMITS_CAPTURER']
11
+ const_get(ENV['LOLCOMMITS_CAPTURER'])
12
+ elsif platform_mac?
13
+ animate ? CaptureMacAnimated : CaptureMac
14
+ elsif platform_linux?
15
+ animate ? CaptureLinuxAnimated : CaptureLinux
16
+ elsif platform_windows?
17
+ CaptureWindows
18
+ elsif platform_cygwin?
19
+ CaptureCygwin
20
+ else
21
+ raise 'Unknown / Unsupported Platform.'
22
+ end
23
+ end
24
+
25
+ # Are we on a Mac platform?
26
+ # @return Boolean
27
+ def self.platform_mac?
28
+ host_os.include?('darwin')
29
+ end
30
+
31
+ # Are we on a Linux platform?
32
+ # @return Boolean
33
+ def self.platform_linux?
34
+ host_os.include?('linux')
35
+ end
36
+
37
+ # Are we on a Windows platform?
38
+ # @return Boolean
39
+ def self.platform_windows?
40
+ !host_os.match(/(win|w)32/).nil?
41
+ end
42
+
43
+ # Are we on a Cygwin platform?
44
+ # @return Boolean
45
+ def self.platform_cygwin?
46
+ host_os.include?('cygwin')
47
+ end
48
+
49
+ # return host_os identifier from the RbConfig::CONFIG constant
50
+ # @return String
51
+ def self.host_os
52
+ ENV['LOLCOMMITS_FAKE_HOST_OS'] || RbConfig::CONFIG['host_os'].downcase
53
+ end
54
+
55
+ # Is the platform capable of capturing animated GIFs from webcam?
56
+ # @return Boolean
57
+ def self.can_animate?
58
+ platform_linux? || platform_mac?
59
+ end
60
+
61
+ # Is a valid install of imagemagick present on the system?
62
+ # @return Boolean
63
+ def self.valid_imagemagick_installed?
64
+ return false unless command_which('identify')
65
+ return false unless command_which('mogrify')
66
+ # you'd expect the below to work on its own, but it only handles old versions
67
+ # and will throw an exception if IM is not installed in PATH
68
+ MiniMagick.valid_version_installed?
69
+ rescue
70
+ return false
71
+ end
72
+
73
+ # Is a valid install of ffmpeg present on the system?
74
+ #
75
+ # @note For now, this just checks for presence, any version should work.
76
+ # @return Boolean
77
+ def self.valid_ffmpeg_installed?
78
+ command_which('ffmpeg')
79
+ end
80
+
81
+ # Cross-platform way of finding an executable in the $PATH.
82
+ #
83
+ # Idea taken from http://bit.ly/qDaTbY, if only_path is true, only the path
84
+ # is returned (not the path and command)
85
+ #
86
+ # @example
87
+ # command_which('ruby') #=> /usr/bin/ruby
88
+ #
89
+ # @return Boolean
90
+ def self.command_which(cmd, only_path = false)
91
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
92
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
93
+ exts.each do |ext|
94
+ exe = "#{path}/#{cmd}#{ext}"
95
+ return only_path ? path : exe if File.executable? exe
96
+ end
97
+ end
98
+ nil
99
+ end
100
+
101
+ # Is `git config color.ui` set to 'always'?
102
+ #
103
+ # Due to a bug in the ruby-git library, git config for color.ui cannot be
104
+ # set to 'always' or it won't read properly.
105
+ #
106
+ # This helper method let's us check for that error condition so we can
107
+ # alert the user in the CLI tool.
108
+ #
109
+ # @return Boolean
110
+ def self.git_config_color_always?
111
+ `git config color.ui`.chomp =~ /always/
112
+ end
113
+
114
+ # Returns a list of system camera devices in a format suitable to display
115
+ # to the user.
116
+ #
117
+ # @note Currently only functions on Mac.
118
+ # @return String
119
+ def self.device_list
120
+ # TODO: handle other platforms here (linux/windows)
121
+ if Platform.platform_mac?
122
+ capturer = Lolcommits::CaptureMacAnimated.new
123
+ `#{capturer.executable_path} -l`
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,130 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Lolcommits
3
+ class Plugin
4
+ include Methadone::CLILogging
5
+
6
+ attr_accessor :runner, :options
7
+
8
+ def initialize(runner)
9
+ debug 'Initializing'
10
+ self.runner = runner
11
+ self.options = ['enabled']
12
+ end
13
+
14
+ def execute_precapture
15
+ if enabled?
16
+ debug 'I am enabled, about to run precapture'
17
+ run_precapture
18
+ else
19
+ debug 'Disabled, doing nothing for precapture execution'
20
+ end
21
+ end
22
+
23
+ def execute_postcapture
24
+ if enabled?
25
+ debug 'I am enabled, about to run postcapture'
26
+ run_postcapture
27
+ else
28
+ debug 'Disabled, doing nothing for postcapture execution'
29
+ end
30
+ end
31
+
32
+ def run_precapture
33
+ debug 'base plugin, does nothing to anything'
34
+ end
35
+
36
+ def run_postcapture
37
+ debug 'base plugin, does nothing to anything'
38
+ end
39
+
40
+ def configuration
41
+ config = runner.config.read_configuration if runner
42
+ return {} unless config
43
+ config[self.class.name] || {}
44
+ end
45
+
46
+ # ask for plugin options
47
+ def configure_options!
48
+ puts "Configuring plugin: #{self.class.name}\n"
49
+ options.reduce({}) do |acc, option|
50
+ if option != 'enabled'
51
+ print "#{option}: "
52
+ val = parse_user_input(STDIN.gets.strip)
53
+ else
54
+ val = true
55
+ end
56
+
57
+ # check enabled option isn't a String
58
+ if (option == 'enabled') && ![true, false].include?(val)
59
+ puts "Aborting - please respond with 'true' or 'false'"
60
+ exit 1
61
+ else
62
+ acc.merge(option => val)
63
+ end
64
+ end
65
+ end
66
+
67
+ def parse_user_input(str)
68
+ # cater for bools, strings, ints and blanks
69
+ if 'true'.casecmp(str) == 0
70
+ true
71
+ elsif 'false'.casecmp(str) == 0
72
+ false
73
+ elsif str =~ /^[0-9]+$/
74
+ str.to_i
75
+ elsif str.strip.empty?
76
+ nil
77
+ else
78
+ str
79
+ end
80
+ end
81
+
82
+ def enabled?
83
+ configuration['enabled'] == true
84
+ end
85
+
86
+ # check config is valid
87
+ def valid_configuration?
88
+ if configured?
89
+ true
90
+ else
91
+ puts "Missing #{self.class.name} config - configure with: lolcommits --config -p #{self.class.name}"
92
+ false
93
+ end
94
+ end
95
+
96
+ # empty plugin configuration
97
+ def configured?
98
+ !configuration.empty?
99
+ end
100
+
101
+ # uniform puts for plugins
102
+ # dont puts if the runner wants to be silent (stealth mode)
103
+ def puts(*args)
104
+ return if runner && runner.capture_stealth
105
+ super(args)
106
+ end
107
+
108
+ # helper to log errors with a message via debug
109
+ def log_error(e, message)
110
+ debug message
111
+ debug e.backtrace.join("\n")
112
+ end
113
+
114
+ # uniform debug logging for plugins
115
+ def debug(msg)
116
+ super("Plugin: #{self.class}: " + msg)
117
+ end
118
+
119
+ # identifying plugin name (for config, listing)
120
+ def self.name
121
+ 'plugin'
122
+ end
123
+
124
+ # a plugin requests to be run by the runner in one of the possible positions.
125
+ # valid options are [:precapture, :postcapture]
126
+ def self.runner_order
127
+ nil
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,50 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'httmultiparty'
3
+
4
+ module Lolcommits
5
+ class DotCom < Plugin
6
+ BASE_URL = 'http://lolcommits-dot-com.herokuapp.com'.freeze
7
+
8
+ def initialize(runner)
9
+ super
10
+ options.concat(%w(api_key api_secret repo_id))
11
+ end
12
+
13
+ def run_postcapture
14
+ return unless valid_configuration?
15
+
16
+ t = Time.now.to_i.to_s
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
+ rescue => e
32
+ log_error(e, "ERROR: HTTMultiParty POST FAILED #{e.class} - #{e.message}")
33
+ end
34
+
35
+ def configured?
36
+ !configuration['enabled'].nil? &&
37
+ configuration['api_key'] &&
38
+ configuration['api_secret'] &&
39
+ configuration['repo_id']
40
+ end
41
+
42
+ def self.name
43
+ 'dot_com'
44
+ end
45
+
46
+ def self.runner_order
47
+ :postcapture
48
+ end
49
+ end
50
+ 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