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,68 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'rest_client'
3
+
4
+ module Lolcommits
5
+ class LolSlack < Plugin
6
+ ENDPOINT_URL = 'https://slack.com/api/files.upload'.freeze
7
+ RETRY_COUNT = 2
8
+
9
+ def self.name
10
+ 'slack'
11
+ end
12
+
13
+ def self.runner_order
14
+ :postcapture
15
+ end
16
+
17
+ def configured?
18
+ !configuration['access_token'].nil?
19
+ end
20
+
21
+ def configure
22
+ print "Open the URL below and issue a token for your user:\n"
23
+ print "https://api.slack.com/web\n"
24
+ print "Enter the generated token below, then press enter: (e.g. xxxx-xxxxxxxxx-xxxx) \n"
25
+ code = STDIN.gets.to_s.strip
26
+ print "Enter a comma-seperated list of channel IDs to post images in, then press enter: (e.g. C1234567890,C1234567890)\n"
27
+ print "NOTE: you must use channel IDs (not channel names). Grab them from here; https://api.slack.com/methods/channels.list/test\n"
28
+ channels = STDIN.gets.to_s.strip
29
+
30
+ { 'access_token' => code,
31
+ 'channels' => channels }
32
+ end
33
+
34
+ def configure_options!
35
+ options = super
36
+ if options['enabled']
37
+ config = configure
38
+ options.merge!(config)
39
+ end
40
+ options
41
+ end
42
+
43
+ def run_postcapture
44
+ return unless valid_configuration?
45
+
46
+ retries = RETRY_COUNT
47
+ begin
48
+
49
+ response = RestClient.post(
50
+ ENDPOINT_URL,
51
+ :file => File.new(runner.main_image),
52
+ :token => configuration['access_token'],
53
+ :filetype => 'jpg',
54
+ :filename => runner.sha,
55
+ :title => runner.message + "[#{runner.git_info.repo}]",
56
+ :channels => configuration['channels'])
57
+
58
+ debug response
59
+ rescue => e
60
+ retries -= 1
61
+ retry if retries > 0
62
+ puts "Posting to slack failed - #{e.message}"
63
+ puts 'Try running config again:'
64
+ puts "\tlolcommits --config --plugin slack"
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,127 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'yaml'
3
+ require 'oauth'
4
+ require 'webrick'
5
+ require 'cgi'
6
+ require 'tumblr_client'
7
+
8
+ module Lolcommits
9
+ class LolTumblr < Plugin
10
+ TUMBLR_API_ENDPOINT = 'https://www.tumblr.com'.freeze
11
+ TUMBLR_CONSUMER_KEY = '2FtMEDpEPkxjoUdkpHh42h9wqTu9IVS7Ra0QyNZGixdCvhllN2'.freeze
12
+ TUMBLR_CONSUMER_SECRET = 'qWuvxgFUR2YyWKtbWOkDTMAiBEbj7ZGaNLaNQPba0PI1N4JpBs'.freeze
13
+
14
+ def run_postcapture
15
+ return unless valid_configuration?
16
+ puts 'Posting to Tumblr'
17
+ r = client.photo(configuration['tumblr_name'], :data => runner.main_image)
18
+ if r.key?('id')
19
+ puts "\t--> Post successful!"
20
+ else
21
+ puts "Tumblr post FAILED! #{r}"
22
+ end
23
+ rescue Faraday::Error => e
24
+ puts "Tumblr post FAILED! #{e.message}"
25
+ end
26
+
27
+ def configure_options!
28
+ options = super
29
+ # ask user to configure tokens if enabling
30
+ if options['enabled']
31
+ auth_config = configure_auth!
32
+ return unless auth_config
33
+ options = options.merge(auth_config).merge(configure_tumblr_name)
34
+ end
35
+ options
36
+ end
37
+
38
+ def configure_auth!
39
+ puts '---------------------------'
40
+ puts 'Need to grab tumblr tokens'
41
+ puts '---------------------------'
42
+
43
+ request_token = oauth_consumer.get_request_token(:exclude_callback => true)
44
+ print "\n1) Please open this url in your browser to authorize lolcommits:\n\n"
45
+ puts request_token.authorize_url
46
+ print "\n2) Launching a local server to complete the OAuth authentication process:\n\n"
47
+ begin
48
+ server = WEBrick::HTTPServer.new :Port => 3000
49
+ server.mount_proc '/', server_callback(server)
50
+ server.start
51
+ debug "Requesting Tumblr OAuth Token with verifier: #{@verifier}"
52
+ access_token = request_token.get_access_token(:oauth_verifier => @verifier)
53
+ rescue Errno::EADDRINUSE
54
+ puts "\nERROR You have something running on port 3000. Please turn it off to complete the authorization process"
55
+ return
56
+ rescue OAuth::Unauthorized
57
+ puts "\nERROR: Tumblr OAuth verification faile!"
58
+ return
59
+ end
60
+ return unless access_token.token && access_token.secret
61
+ puts ''
62
+ puts '------------------------------'
63
+ puts 'Thanks! Tumblr Auth Succeeded'
64
+ puts '------------------------------'
65
+
66
+ {
67
+ 'access_token' => access_token.token,
68
+ 'secret' => access_token.secret
69
+ }
70
+ end
71
+
72
+ def configure_tumblr_name
73
+ print "\n3) What's your tumblr name? (i.e. 'http://[THIS PART HERE].tumblr.com'): "
74
+ { 'tumblr_name' => STDIN.gets.strip }
75
+ end
76
+
77
+ def configured?
78
+ !configuration['enabled'].nil? &&
79
+ configuration['access_token'] &&
80
+ configuration['secret']
81
+ end
82
+
83
+ def client
84
+ @client ||= Tumblr.new(:consumer_key => TUMBLR_CONSUMER_KEY,
85
+ :consumer_secret => TUMBLR_CONSUMER_SECRET,
86
+ :oauth_token => configuration['access_token'],
87
+ :oauth_token_secret => configuration['secret']
88
+ )
89
+ end
90
+
91
+ def oauth_consumer
92
+ @oauth_consumer ||= OAuth::Consumer.new(TUMBLR_CONSUMER_KEY,
93
+ TUMBLR_CONSUMER_SECRET,
94
+ :site => TUMBLR_API_ENDPOINT,
95
+ :request_endpoint => TUMBLR_API_ENDPOINT,
96
+ :http_methdo => :get
97
+ )
98
+ end
99
+
100
+ def config_with_default(key, default = nil)
101
+ if configuration[key]
102
+ configuration[key].strip.empty? ? default : configuration[key]
103
+ else
104
+ default
105
+ end
106
+ end
107
+
108
+ def self.name
109
+ 'tumblr'
110
+ end
111
+
112
+ def self.runner_order
113
+ :postcapture
114
+ end
115
+
116
+ protected
117
+
118
+ def server_callback(server)
119
+ proc do |req, res|
120
+ q = CGI.parse req.request_uri.query
121
+ @verifier = q['oauth_verifier'][0]
122
+ server.stop
123
+ res.body = 'Lolcommits authorization complete!'
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,155 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'yaml'
3
+ require 'oauth'
4
+ require 'twitter'
5
+
6
+ module Lolcommits
7
+ class LolTwitter < Plugin
8
+ TWITTER_API_ENDPOINT = 'https://api.twitter.com'.freeze
9
+ TWITTER_CONSUMER_KEY = 'qc096dJJCxIiqDNUqEsqQ'.freeze
10
+ TWITTER_CONSUMER_SECRET = 'rvjNdtwSr1H0TvBvjpk6c4bvrNydHmmbvv7gXZQI'.freeze
11
+ TWITTER_RETRIES = 2
12
+ TWITTER_PIN_REGEX = /^\d{4,}$/ # 4 or more digits
13
+ DEFAULT_SUFFIX = '#lolcommits'.freeze
14
+
15
+ def run_postcapture
16
+ return unless valid_configuration?
17
+ tweet = build_tweet(runner.message)
18
+
19
+ attempts = 0
20
+ begin
21
+ attempts += 1
22
+ puts "Tweeting: #{tweet}"
23
+ debug "--> Tweeting! (attempt: #{attempts}, tweet length: #{tweet.length} chars)"
24
+ if client.update_with_media(tweet, File.open(runner.main_image, 'r'))
25
+ puts "\t--> Tweet Sent!"
26
+ end
27
+ rescue Twitter::Error::ServerError,
28
+ Twitter::Error::ClientError => e
29
+ debug "Tweet FAILED! #{e.class} - #{e.message}"
30
+ retry if attempts < TWITTER_RETRIES
31
+ puts "ERROR: Tweet FAILED! (after #{attempts} attempts) - #{e.message}"
32
+ end
33
+ end
34
+
35
+ def build_tweet(commit_message)
36
+ prefix = config_with_default('prefix', '')
37
+ suffix = " #{config_with_default('suffix', DEFAULT_SUFFIX)}"
38
+ prefix = "#{prefix} " unless prefix.empty?
39
+
40
+ available_commit_msg_size = max_tweet_size - (prefix.length + suffix.length)
41
+ if commit_message.length > available_commit_msg_size
42
+ commit_message = "#{commit_message[0..(available_commit_msg_size - 3)]}..."
43
+ end
44
+
45
+ "#{prefix}#{commit_message}#{suffix}"
46
+ end
47
+
48
+ def configure_options!
49
+ options = super
50
+ # ask user to configure tokens if enabling
51
+ if options['enabled']
52
+ auth_config = configure_auth!
53
+ return unless auth_config
54
+ options = options.merge(auth_config).merge(configure_prefix_suffix)
55
+ end
56
+ options
57
+ end
58
+
59
+ def configure_auth!
60
+ puts '---------------------------'
61
+ puts 'Need to grab twitter tokens'
62
+ puts '---------------------------'
63
+
64
+ request_token = oauth_consumer.get_request_token
65
+ rtoken = request_token.token
66
+ rsecret = request_token.secret
67
+
68
+ print "\n1) Please open this url in your browser to get a PIN for lolcommits:\n\n"
69
+ puts request_token.authorize_url
70
+ print "\n2) Enter PIN, then press enter: "
71
+ twitter_pin = STDIN.gets.strip.downcase.to_s
72
+
73
+ unless twitter_pin =~ TWITTER_PIN_REGEX
74
+ puts "\nERROR: '#{twitter_pin}' is not a valid Twitter Auth PIN"
75
+ return
76
+ end
77
+
78
+ begin
79
+ debug "Requesting Twitter OAuth Token with PIN: #{twitter_pin}"
80
+ OAuth::RequestToken.new(oauth_consumer, rtoken, rsecret)
81
+ access_token = request_token.get_access_token(:oauth_verifier => twitter_pin)
82
+ rescue OAuth::Unauthorized
83
+ puts "\nERROR: Twitter PIN Auth FAILED!"
84
+ return
85
+ end
86
+
87
+ return unless access_token.token && access_token.secret
88
+ puts ''
89
+ puts '------------------------------'
90
+ puts 'Thanks! Twitter Auth Succeeded'
91
+ puts '------------------------------'
92
+ {
93
+ 'access_token' => access_token.token,
94
+ 'secret' => access_token.secret
95
+ }
96
+ end
97
+
98
+ def configure_prefix_suffix
99
+ print "\n3) Prefix all tweets with something? e.g. @user (leave blank for no prefix): "
100
+ prefix = STDIN.gets.strip
101
+ print "\n4) End all tweets with something? e.g. #hashtag (leave blank for default suffix #{DEFAULT_SUFFIX}): "
102
+ suffix = STDIN.gets.strip
103
+
104
+ config = {}
105
+ config['prefix'] = prefix unless prefix.empty?
106
+ config['suffix'] = suffix unless suffix.empty?
107
+ config
108
+ end
109
+
110
+ def configured?
111
+ !configuration['enabled'].nil? &&
112
+ configuration['access_token'] &&
113
+ configuration['secret']
114
+ end
115
+
116
+ def client
117
+ @client ||= Twitter::REST::Client.new do |config|
118
+ config.consumer_key = TWITTER_CONSUMER_KEY
119
+ config.consumer_secret = TWITTER_CONSUMER_SECRET
120
+ config.access_token = configuration['access_token']
121
+ config.access_token_secret = configuration['secret']
122
+ end
123
+ end
124
+
125
+ def oauth_consumer
126
+ @oauth_consumer ||= OAuth::Consumer.new(
127
+ TWITTER_CONSUMER_KEY,
128
+ TWITTER_CONSUMER_SECRET,
129
+ :site => TWITTER_API_ENDPOINT,
130
+ :request_endpoint => TWITTER_API_ENDPOINT,
131
+ :sign_in => true
132
+ )
133
+ end
134
+
135
+ def config_with_default(key, default = nil)
136
+ if configuration[key]
137
+ configuration[key].strip.empty? ? default : configuration[key]
138
+ else
139
+ default
140
+ end
141
+ end
142
+
143
+ def max_tweet_size
144
+ 139 - client.configuration.characters_reserved_per_media
145
+ end
146
+
147
+ def self.name
148
+ 'twitter'
149
+ end
150
+
151
+ def self.runner_order
152
+ :postcapture
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,85 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'yammer'
3
+ require 'rest_client'
4
+
5
+ # https://developer.yammer.com/oauth2-quickstart/
6
+ YAMMER_CLIENT_ID = 'bgORyeKtnjZJSMwp8oln9g'.freeze
7
+ YAMMER_CLIENT_SECRET = 'oer2WdGzh74a5QBbW3INUxblHK3yg9KvCZmiBa2r0'.freeze
8
+ YAMMER_ACCESS_TOKEN_URL = 'https://www.yammer.com/oauth2/access_token.json'.freeze
9
+ YAMMER_RETRY_COUNT = 2
10
+
11
+ module Lolcommits
12
+ class LolYammer < Plugin
13
+ def self.name
14
+ 'yammer'
15
+ end
16
+
17
+ def self.runner_order
18
+ :postcapture
19
+ end
20
+
21
+ def configured?
22
+ !configuration['access_token'].nil?
23
+ end
24
+
25
+ def configure_access_token
26
+ print "Open the URL below and copy the `code` param from query after redirected, enter it as `access_token`:\n"
27
+ print "https://www.yammer.com/dialog/oauth?client_id=#{YAMMER_CLIENT_ID}&response_type=code\n"
28
+ print 'Enter code param from the redirected URL, then press enter: '
29
+ code = STDIN.gets.to_s.strip
30
+
31
+ url = YAMMER_ACCESS_TOKEN_URL
32
+ debug "access_token url: #{url}"
33
+ params = {
34
+ 'client_id' => YAMMER_CLIENT_ID,
35
+ 'client_secret' => YAMMER_CLIENT_SECRET,
36
+ 'code' => code
37
+ }
38
+ debug "params : #{params.inspect}"
39
+ result = JSON.parse(RestClient.post(url, params))
40
+ debug "response : #{result.inspect}"
41
+ # no need for 'return', last line is always the return value
42
+ { 'access_token' => result['access_token']['token'] }
43
+ end
44
+
45
+ def configure_options!
46
+ options = super
47
+ # ask user to configure tokens if enabling
48
+ if options['enabled']
49
+ auth_config = configure_access_token
50
+ return unless auth_config
51
+ options.merge!(auth_config)
52
+ end
53
+ options
54
+ end
55
+
56
+ def run_postcapture
57
+ return unless valid_configuration?
58
+
59
+ commit_msg = runner.message
60
+ post = "#{commit_msg} #lolcommits"
61
+ puts "Yammer post: #{post}" unless runner.capture_stealth
62
+
63
+ Yammer.configure do |c|
64
+ c.client_id = YAMMER_CLIENT_ID
65
+ c.client_secret = YAMMER_CLIENT_SECRET
66
+ end
67
+
68
+ client = Yammer::Client.new(:access_token => configuration['access_token'])
69
+
70
+ retries = YAMMER_RETRY_COUNT
71
+ begin
72
+ lolimage = File.new(runner.main_image)
73
+ response = client.create_message(post, :attachment1 => lolimage)
74
+ debug response.body.inspect
75
+ puts "\t--> Status posted!" if response
76
+ rescue => e
77
+ retries -= 1
78
+ retry if retries > 0
79
+ puts "Status not posted - #{e.message}"
80
+ puts 'Try running config again:'
81
+ puts "\tlolcommits --config --plugin yammer"
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,59 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'rest_client'
3
+ require 'pp'
4
+ require 'json'
5
+
6
+ module Lolcommits
7
+ class Lolsrv < Plugin
8
+ def initialize(runner)
9
+ super
10
+ options << 'server'
11
+ end
12
+
13
+ def run_postcapture
14
+ return unless valid_configuration?
15
+ fork { sync }
16
+ end
17
+
18
+ def configured?
19
+ !configuration['enabled'].nil? && configuration['server']
20
+ end
21
+
22
+ def sync
23
+ existing = existing_lols
24
+ return unless existing.nil?
25
+ Dir[runner.config.loldir + '/*.{jpg,gif}'].each do |item|
26
+ sha = File.basename(item, '.*')
27
+ upload(item, sha) unless existing.include?(sha) || sha == 'tmp_snapshot'
28
+ end
29
+ end
30
+
31
+ def existing_lols
32
+ lols = JSON.parse(
33
+ RestClient.get(configuration['server'] + '/lols'))
34
+ lols.map { |lol| lol['sha'] }
35
+ rescue => e
36
+ log_error(e, "ERROR: existing lols could not be retrieved #{e.class} - #{e.message}")
37
+ return nil
38
+ end
39
+
40
+ def upload(file, sha)
41
+ RestClient.post(configuration['server'] + '/uplol',
42
+ :lol => File.new(file),
43
+ :url => runner.git_info.url + sha,
44
+ :repo => runner.git_info.repo,
45
+ :date => File.ctime(file),
46
+ :sha => sha)
47
+ rescue => e
48
+ log_error(e, "ERROR: Upload of lol #{sha} FAILED #{e.class} - #{e.message}")
49
+ end
50
+
51
+ def self.name
52
+ 'lolsrv'
53
+ end
54
+
55
+ def self.runner_order
56
+ :postcapture
57
+ end
58
+ end
59
+ end