snapgit 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
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