travis-akerl 1.8.9

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 (185) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +2512 -0
  4. data/Rakefile +64 -0
  5. data/assets/cacert.pem +69 -0
  6. data/assets/init/c.yml +4 -0
  7. data/assets/init/clojure.yml +1 -0
  8. data/assets/init/cpp.yml +4 -0
  9. data/assets/init/erlang.yml +3 -0
  10. data/assets/init/go.yml +4 -0
  11. data/assets/init/groovy.yml +1 -0
  12. data/assets/init/haskell.yml +1 -0
  13. data/assets/init/java.yml +4 -0
  14. data/assets/init/node_js.yml +5 -0
  15. data/assets/init/objective-c.yml +1 -0
  16. data/assets/init/perl.yml +4 -0
  17. data/assets/init/php.yml +4 -0
  18. data/assets/init/python.yml +5 -0
  19. data/assets/init/ruby.yml +6 -0
  20. data/assets/init/scala.yml +4 -0
  21. data/assets/notifications/Travis CI.app/Contents/Info.plist +52 -0
  22. data/assets/notifications/Travis CI.app/Contents/MacOS/Travis CI +0 -0
  23. data/assets/notifications/Travis CI.app/Contents/PkgInfo +1 -0
  24. data/assets/notifications/Travis CI.app/Contents/Resources/Travis CI.icns +0 -0
  25. data/assets/notifications/Travis CI.app/Contents/Resources/en.lproj/Credits.rtf +29 -0
  26. data/assets/notifications/Travis CI.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  27. data/assets/notifications/Travis CI.app/Contents/Resources/en.lproj/MainMenu.nib +0 -0
  28. data/assets/notifications/Travis CI.app/Contents/_CodeSignature/CodeResources +173 -0
  29. data/assets/notifications/Travis CI.app/Contents/embedded.provisionprofile +0 -0
  30. data/assets/notifications/icon.png +0 -0
  31. data/assets/travis.sh +163 -0
  32. data/assets/travis.sh.erb +64 -0
  33. data/bin/travis +18 -0
  34. data/examples/org_overview.rb +3 -0
  35. data/examples/pro_auth.rb +23 -0
  36. data/examples/stream.rb +6 -0
  37. data/lib/travis/auto_login.rb +3 -0
  38. data/lib/travis/cli/accounts.rb +31 -0
  39. data/lib/travis/cli/api_command.rb +182 -0
  40. data/lib/travis/cli/branches.rb +25 -0
  41. data/lib/travis/cli/cache.rb +76 -0
  42. data/lib/travis/cli/cancel.rb +18 -0
  43. data/lib/travis/cli/command.rb +422 -0
  44. data/lib/travis/cli/console.rb +33 -0
  45. data/lib/travis/cli/disable.rb +15 -0
  46. data/lib/travis/cli/enable.rb +31 -0
  47. data/lib/travis/cli/encrypt.rb +115 -0
  48. data/lib/travis/cli/encrypt_file.rb +140 -0
  49. data/lib/travis/cli/endpoint.rb +35 -0
  50. data/lib/travis/cli/env.rb +66 -0
  51. data/lib/travis/cli/help.rb +23 -0
  52. data/lib/travis/cli/history.rb +49 -0
  53. data/lib/travis/cli/init.rb +82 -0
  54. data/lib/travis/cli/lint.rb +49 -0
  55. data/lib/travis/cli/login.rb +76 -0
  56. data/lib/travis/cli/logout.rb +14 -0
  57. data/lib/travis/cli/logs.rb +65 -0
  58. data/lib/travis/cli/monitor.rb +111 -0
  59. data/lib/travis/cli/open.rb +39 -0
  60. data/lib/travis/cli/parser.rb +43 -0
  61. data/lib/travis/cli/pubkey.rb +30 -0
  62. data/lib/travis/cli/raw.rb +20 -0
  63. data/lib/travis/cli/repo_command.rb +154 -0
  64. data/lib/travis/cli/report.rb +101 -0
  65. data/lib/travis/cli/repos.rb +53 -0
  66. data/lib/travis/cli/requests.rb +47 -0
  67. data/lib/travis/cli/restart.rb +18 -0
  68. data/lib/travis/cli/settings.rb +79 -0
  69. data/lib/travis/cli/setup/anynines.rb +21 -0
  70. data/lib/travis/cli/setup/appfog.rb +19 -0
  71. data/lib/travis/cli/setup/artifacts.rb +23 -0
  72. data/lib/travis/cli/setup/biicode.rb +19 -0
  73. data/lib/travis/cli/setup/cloud_66.rb +20 -0
  74. data/lib/travis/cli/setup/cloud_control.rb +21 -0
  75. data/lib/travis/cli/setup/cloud_files.rb +20 -0
  76. data/lib/travis/cli/setup/cloud_foundry.rb +23 -0
  77. data/lib/travis/cli/setup/code_deploy.rb +55 -0
  78. data/lib/travis/cli/setup/deis.rb +20 -0
  79. data/lib/travis/cli/setup/divshot.rb +18 -0
  80. data/lib/travis/cli/setup/elastic_beanstalk.rb +23 -0
  81. data/lib/travis/cli/setup/engine_yard.rb +24 -0
  82. data/lib/travis/cli/setup/gcs.rb +22 -0
  83. data/lib/travis/cli/setup/hackage.rb +18 -0
  84. data/lib/travis/cli/setup/heroku.rb +20 -0
  85. data/lib/travis/cli/setup/modulus.rb +18 -0
  86. data/lib/travis/cli/setup/ninefold.rb +20 -0
  87. data/lib/travis/cli/setup/nodejitsu.rb +27 -0
  88. data/lib/travis/cli/setup/npm.rb +20 -0
  89. data/lib/travis/cli/setup/open_shift.rb +20 -0
  90. data/lib/travis/cli/setup/opsworks.rb +22 -0
  91. data/lib/travis/cli/setup/pypi.rb +22 -0
  92. data/lib/travis/cli/setup/releases.rb +35 -0
  93. data/lib/travis/cli/setup/ruby_gems.rb +25 -0
  94. data/lib/travis/cli/setup/s3.rb +25 -0
  95. data/lib/travis/cli/setup/sauce_connect.rb +21 -0
  96. data/lib/travis/cli/setup/service.rb +73 -0
  97. data/lib/travis/cli/setup.rb +66 -0
  98. data/lib/travis/cli/show.rb +57 -0
  99. data/lib/travis/cli/sshkey.rb +118 -0
  100. data/lib/travis/cli/status.rb +19 -0
  101. data/lib/travis/cli/sync.rb +30 -0
  102. data/lib/travis/cli/token.rb +14 -0
  103. data/lib/travis/cli/version.rb +17 -0
  104. data/lib/travis/cli/whatsup.rb +30 -0
  105. data/lib/travis/cli/whoami.rb +15 -0
  106. data/lib/travis/cli.rb +126 -0
  107. data/lib/travis/client/account.rb +56 -0
  108. data/lib/travis/client/artifact.rb +88 -0
  109. data/lib/travis/client/auto_login.rb +45 -0
  110. data/lib/travis/client/broadcast.rb +14 -0
  111. data/lib/travis/client/build.rb +47 -0
  112. data/lib/travis/client/cache.rb +25 -0
  113. data/lib/travis/client/commit.rb +28 -0
  114. data/lib/travis/client/entity.rb +238 -0
  115. data/lib/travis/client/env_var.rb +102 -0
  116. data/lib/travis/client/error.rb +38 -0
  117. data/lib/travis/client/has_uuid.rb +13 -0
  118. data/lib/travis/client/job.rb +61 -0
  119. data/lib/travis/client/lint_result.rb +25 -0
  120. data/lib/travis/client/listener.rb +183 -0
  121. data/lib/travis/client/methods.rb +104 -0
  122. data/lib/travis/client/namespace.rb +85 -0
  123. data/lib/travis/client/not_loadable.rb +13 -0
  124. data/lib/travis/client/repository.rb +224 -0
  125. data/lib/travis/client/request.rb +36 -0
  126. data/lib/travis/client/restartable.rb +23 -0
  127. data/lib/travis/client/session.rb +339 -0
  128. data/lib/travis/client/settings.rb +25 -0
  129. data/lib/travis/client/singleton_setting.rb +36 -0
  130. data/lib/travis/client/ssh_key.rb +11 -0
  131. data/lib/travis/client/states.rb +98 -0
  132. data/lib/travis/client/user.rb +67 -0
  133. data/lib/travis/client/weak_entity.rb +26 -0
  134. data/lib/travis/client.rb +38 -0
  135. data/lib/travis/pro/auto_login.rb +3 -0
  136. data/lib/travis/pro.rb +5 -0
  137. data/lib/travis/tools/assets.rb +21 -0
  138. data/lib/travis/tools/completion.rb +54 -0
  139. data/lib/travis/tools/formatter.rb +50 -0
  140. data/lib/travis/tools/github.rb +293 -0
  141. data/lib/travis/tools/notification.rb +69 -0
  142. data/lib/travis/tools/safe_string.rb +22 -0
  143. data/lib/travis/tools/ssl_key.rb +48 -0
  144. data/lib/travis/tools/system.rb +88 -0
  145. data/lib/travis/version.rb +3 -0
  146. data/lib/travis.rb +8 -0
  147. data/spec/cli/api_command_spec.rb +38 -0
  148. data/spec/cli/cancel_spec.rb +15 -0
  149. data/spec/cli/encrypt_spec.rb +49 -0
  150. data/spec/cli/endpoint_spec.rb +39 -0
  151. data/spec/cli/help_spec.rb +33 -0
  152. data/spec/cli/history_spec.rb +38 -0
  153. data/spec/cli/init_spec.rb +227 -0
  154. data/spec/cli/login_spec.rb +13 -0
  155. data/spec/cli/logs_spec.rb +8 -0
  156. data/spec/cli/open_spec.rb +33 -0
  157. data/spec/cli/repo_command_spec.rb +25 -0
  158. data/spec/cli/restart_spec.rb +15 -0
  159. data/spec/cli/setup_spec.rb +5 -0
  160. data/spec/cli/show_spec.rb +9 -0
  161. data/spec/cli/status_spec.rb +28 -0
  162. data/spec/cli/token_spec.rb +22 -0
  163. data/spec/cli/version_spec.rb +18 -0
  164. data/spec/cli/whoami_spec.rb +34 -0
  165. data/spec/client/account_spec.rb +32 -0
  166. data/spec/client/auto_login_spec.rb +25 -0
  167. data/spec/client/broadcast_spec.rb +10 -0
  168. data/spec/client/build_spec.rb +31 -0
  169. data/spec/client/commit_spec.rb +22 -0
  170. data/spec/client/job_spec.rb +30 -0
  171. data/spec/client/methods_spec.rb +15 -0
  172. data/spec/client/namespace_spec.rb +19 -0
  173. data/spec/client/repository_spec.rb +39 -0
  174. data/spec/client/session_spec.rb +165 -0
  175. data/spec/client/user_spec.rb +16 -0
  176. data/spec/client_spec.rb +17 -0
  177. data/spec/pro_spec.rb +10 -0
  178. data/spec/spec_helper.rb +29 -0
  179. data/spec/support/fake_api.rb +731 -0
  180. data/spec/support/fake_github.rb +24 -0
  181. data/spec/support/fake_travis_config.yml +14 -0
  182. data/spec/support/helpers.rb +45 -0
  183. data/spec/travis_spec.rb +10 -0
  184. data/travis.gemspec +371 -0
  185. metadata +534 -0
data/lib/travis/pro.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'travis/client'
2
+
3
+ module Travis
4
+ Pro = Client::Namespace.new(Client::COM_URI)
5
+ end
@@ -0,0 +1,21 @@
1
+ module Travis
2
+ module Tools
3
+ module Assets
4
+ BASE = File.expand_path('../../../../assets', __FILE__)
5
+ extend self
6
+
7
+ def asset_path(file)
8
+ File.expand_path(file, BASE)
9
+ end
10
+
11
+ def asset(file)
12
+ File.read(asset_path(file))
13
+ end
14
+
15
+ class << self
16
+ alias [] asset_path
17
+ alias read asset
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,54 @@
1
+ require 'travis/tools/assets'
2
+ require 'travis/cli'
3
+ require 'fileutils'
4
+ require 'erb'
5
+
6
+ module Travis
7
+ module Tools
8
+ module Completion
9
+ RCS = ['.zshrc', '.bashrc'].map { |f| File.expand_path(f, ENV['HOME']) }
10
+ include FileUtils
11
+ extend self
12
+
13
+ def config_path
14
+ ENV.fetch('TRAVIS_CONFIG_PATH') { File.expand_path('.travis', ENV['HOME']) }
15
+ end
16
+
17
+ def cmp_file
18
+ File.expand_path('travis.sh', config_path)
19
+ end
20
+
21
+ def install_completion
22
+ update_completion
23
+ source = "source " << cmp_file
24
+
25
+ RCS.each do |file|
26
+ next unless File.exist? file and File.writable? file
27
+ next if File.read(file).include? source
28
+ File.open(file, "a") { |f| f.puts("", "# added by travis gem", "[ -f #{cmp_file} ] && #{source}") }
29
+ end
30
+ end
31
+
32
+ def update_completion
33
+ mkdir_p(config_path)
34
+ cp(Assets['travis.sh'], cmp_file)
35
+ end
36
+
37
+ def completion_installed?
38
+ source = "source " << config_path
39
+ RCS.each do |file|
40
+ next unless File.exist? file and File.writable? file
41
+ return false unless File.read(file).include? source
42
+ end
43
+ true
44
+ end
45
+
46
+ def compile
47
+ commands = Travis::CLI.commands.sort_by { |c| c.command_name }
48
+ template = Assets.read('travis.sh.erb')
49
+ source = ERB.new(template).result(binding).gsub(/^ +\n/, '')
50
+ File.write(Assets['travis.sh'], source)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,50 @@
1
+ require 'time'
2
+
3
+ module Travis
4
+ module Tools
5
+ class Formatter
6
+ DAY = 24 * 60 * 60
7
+ TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
8
+ CONFIG_KEYS = ['rvm', 'gemfile', 'env', 'jdk', 'otp_release', 'php', 'node_js', 'perl', 'python', 'scala', 'compiler', 'os']
9
+
10
+ def duration(seconds, suffix = nil)
11
+ return "none" if seconds.nil?
12
+ seconds = (Time.now - seconds).to_i if seconds.is_a? Time
13
+ output = []
14
+ minutes, seconds = seconds.divmod(60)
15
+ hours, minutes = minutes.divmod(60)
16
+ output << "#{hours } hrs" if hours > 0
17
+ output << "#{minutes} min" if minutes > 0
18
+ output << "#{seconds} sec" if seconds > 0 or output.empty?
19
+ output << suffix if suffix
20
+ output.join(" ")
21
+ end
22
+
23
+ def file_size(input, human = true)
24
+ return "#{input} B" unless human
25
+ format = "B"
26
+ iec = %w[KiB MiB GiB TiB PiB EiB ZiB YiB]
27
+ while human and input > 512 and iec.any?
28
+ input /= 1024.0
29
+ format = iec.shift
30
+ end
31
+ input = input.round(2) if input.is_a? Float
32
+ "#{input} #{format}"
33
+ end
34
+
35
+ def time(time)
36
+ return "not yet" if time.nil? # or time > Time.now
37
+ #return duration(time, "ago") if Time.now - time < DAY
38
+ time.localtime.strftime(TIME_FORMAT)
39
+ end
40
+
41
+ def job_config(config)
42
+ output = []
43
+ config.each_pair do |key, value|
44
+ output << "#{key}: #{value}" if CONFIG_KEYS.include? key
45
+ end
46
+ output.join(", ")
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,293 @@
1
+ require 'travis/tools/system'
2
+ require 'yaml'
3
+ require 'json'
4
+
5
+ module Travis
6
+ module Tools
7
+ class Github
8
+ TOKEN_SIZE = 40
9
+ GITHUB_API = 'api.github.com'
10
+ GITHUB_HOST = 'github.com'
11
+
12
+ attr_accessor :api_url, :scopes, :github_token, :github_login, :drop_token, :callback, :explode, :after_tokens,
13
+ :ask_login, :ask_password, :ask_otp, :login_header, :auto_token, :auto_password, :manual_login, :note,
14
+ :netrc_path, :hub_path, :oauth_paths, :composer_path, :git_config_keys, :debug, :no_token, :check_token
15
+
16
+ def initialize(options = nil)
17
+ @check_token = true
18
+ @manual_login = true
19
+ @ask_login = proc { raise "ask_login callback not set" }
20
+ @after_tokens = proc { }
21
+ @ask_password = proc { |_| raise "ask_password callback not set" }
22
+ @ask_otp = proc { |_| raise "ask_otp callback not set" }
23
+ @debug = proc { |_| }
24
+ @netrc_path = '~/.netrc'
25
+ @hub_path = ENV['HUB_CONFIG'] || '~/.config/hub'
26
+ @oauth_paths = ['~/.github-oauth-token']
27
+ @composer_path = "~/.composer/config.json"
28
+ @note = 'temporary token'
29
+ @git_config_keys = %w[github.token github.oauth-token]
30
+ @scopes = ['user', 'user:email', 'repo'] # overridden by value from /config
31
+ options.each_pair { |k,v| send("#{k}=", v) if respond_to? "#{k}=" } if options
32
+ yield self if block_given?
33
+ end
34
+
35
+ def with_token
36
+ each_token { |t| break yield(t) }
37
+ end
38
+
39
+ def with_basic_auth(&block)
40
+ user, password = ask_credentials
41
+ basic_auth(user, password, true) do |gh, _|
42
+ gh['user'] # so otp kicks in
43
+ yield gh
44
+ end
45
+ end
46
+
47
+ def each_token
48
+ require 'gh' unless defined? GH
49
+ possible_tokens { |t| yield(t) if acceptable?(t) }
50
+ ensure
51
+ callback, self.callback = self.callback, nil
52
+ callback.call if callback
53
+ end
54
+
55
+ def with_session(&block)
56
+ with_token { |t| GH.with(:token => t) { yield(t) } }
57
+ end
58
+
59
+ def possible_tokens(&block)
60
+ return block[github_token] if github_token
61
+
62
+ if auto_token
63
+ netrc_tokens(&block)
64
+ git_tokens(&block)
65
+ hub_tokens(&block)
66
+ oauth_file_tokens(&block)
67
+ github_for_mac_token(&block)
68
+ issuepost_token(&block)
69
+ composer_token(&block)
70
+ end
71
+
72
+ if auto_password
73
+ possible_logins do |user, password|
74
+ yield login(user, password, false)
75
+ end
76
+ end
77
+
78
+ if manual_login
79
+ user, password = ask_credentials
80
+ yield login(user, password, true)
81
+ end
82
+
83
+ after_tokens.call
84
+ end
85
+
86
+ def ask_credentials
87
+ login_header.call if login_header
88
+ user = github_login || ask_login.call
89
+ password = ask_password.arity == 0 ? ask_password.call : ask_password.call(user)
90
+ [user, password]
91
+ end
92
+
93
+ def possible_logins(&block)
94
+ netrc_logins(&block)
95
+ hub_logins(&block)
96
+ keychain_login(&block)
97
+ end
98
+
99
+ def netrc_tokens
100
+ netrc.each do |entry|
101
+ next unless entry["machine"] == api_host or entry["machine"] == host
102
+ entry.values_at("token", "login", "password").each do |entry|
103
+ next if entry.to_s.size != TOKEN_SIZE
104
+ debug "found oauth token in netrc"
105
+ yield entry
106
+ end
107
+ end
108
+ end
109
+
110
+ def git_tokens
111
+ return unless System.has? 'git'
112
+ git_config_keys.each do |key|
113
+ `git config --get-all #{key}`.each_line do |line|
114
+ token = line.strip
115
+ yield token unless token.empty?
116
+ end
117
+ end
118
+ end
119
+
120
+ def composer_token
121
+ file(composer_path) do |content|
122
+ token = JSON.parse(content)['config'].fetch('github-oauth', {})[host]
123
+ yield token if token
124
+ end
125
+ end
126
+
127
+ def hub_tokens
128
+ hub.fetch(host, []).each do |entry|
129
+ next if github_login and github_login != entry["user"]
130
+ yield entry["oauth_token"] if entry["oauth_token"]
131
+ end
132
+ end
133
+
134
+ def oauth_file_tokens(&block)
135
+ oauth_paths.each do |path|
136
+ file(path) do |content|
137
+ token = content.strip
138
+ yield token unless token.empty?
139
+ end
140
+ end
141
+ end
142
+
143
+ def netrc_logins
144
+ netrc.each do |entry|
145
+ next unless entry["machine"] == api_host or entry["machine"] == host
146
+ next if github_login and github_login != entry["login"]
147
+ yield entry["login"], entry["password"] if entry["login"] and entry["password"]
148
+ end
149
+ end
150
+
151
+ def hub_logins
152
+ hub.fetch(host, []).each do |entry|
153
+ next if github_login and github_login != entry["user"]
154
+ yield entry["user"], entry["password"] if entry["user"] and entry["password"]
155
+ end
156
+ end
157
+
158
+ def keychain_login
159
+ if github_login
160
+ security(:internet, :w, "-s #{host} -a #{github_login}", "#{host} password for #{github_login}") do |password|
161
+ yield github_login, password if password and not password.empty?
162
+ end
163
+ else
164
+ security(:internet, :g, "-s #{host}", "#{host} login and password") do |data|
165
+ username = data[/^\s+"acct"<blob>="(.*)"$/, 1].to_s
166
+ password = data[/^password: "(.*)"$/, 1].to_s
167
+ yield username, password unless username.empty? or password.empty?
168
+ end
169
+ end
170
+ end
171
+
172
+ def netrc
173
+ file(netrc_path, []) do |contents|
174
+ contents.scan(/^\s*(\S+)\s+(\S+)\s*$/).inject([]) do |mapping, (key, value)|
175
+ mapping << {} if key == "machine"
176
+ mapping.last[key] = value if mapping.last
177
+ mapping
178
+ end
179
+ end
180
+ end
181
+
182
+ def hub
183
+ file(hub_path, {}) do |contents|
184
+ YAML.load(contents)
185
+ end
186
+ end
187
+
188
+ def issuepost_token(&block)
189
+ security(:generic, :w, "-l issuepost.github.access_token", "issuepost token", &block) if host == 'github.com'
190
+ end
191
+
192
+ def github_for_mac_token(&block)
193
+ command = '-s "github.com/mac"'
194
+ command << " -a #{github_login}" if github_login
195
+ security(:internet, :w, command, "GitHub for Mac token", &block) if host == 'github.com'
196
+ end
197
+
198
+ def host
199
+ api_host == GITHUB_API ? GITHUB_HOST : api_host
200
+ end
201
+
202
+ def api_host
203
+ return GITHUB_API unless api_url
204
+ api_url[%r{^(?:https?://)?([^/]+)}, 1]
205
+ end
206
+
207
+ def basic_auth(user, password, die = true, otp = nil, &block)
208
+ gh = GH.with(:username => user, :password => password)
209
+ with_otp(gh, user, otp, &block)
210
+ rescue GH::Error => error
211
+ raise gh_error(error) if die
212
+ end
213
+
214
+ def login(user, password, die = true, otp = nil)
215
+ basic_auth(user, password, die, otp) do |gh, new_otp|
216
+ reply = create_token(gh)
217
+ auth_href = reply['_links']['self']['href']
218
+ self.callback = proc { with_otp(gh, user, new_otp) { |g| g.delete(auth_href) } } if drop_token
219
+ reply['token']
220
+ end
221
+ end
222
+
223
+ def create_token(gh)
224
+ gh.post('/authorizations', :scopes => scopes, :note => note)
225
+ rescue GH::Error => error
226
+ # token might already exist due to bug in earlier CLI version, we'll have to delete it first
227
+ raise error unless error.info[:response_status] == 422 and error.info[:response_body].to_s =~ /already_exists/
228
+ raise error unless reply = gh['/authorizations'].detect { |a| a['note'] == note }
229
+ gh.delete(reply['_links']['self']['href'])
230
+ retry
231
+ end
232
+
233
+ def with_otp(gh, user, otp, &block)
234
+ gh = GH.with(gh.options.merge(:headers => { "X-GitHub-OTP" => otp })) if otp
235
+ block.call(gh, otp)
236
+ rescue GH::Error => error
237
+ raise error unless error.info[:response_status] == 401 and error.info[:response_headers]['x-github-otp'].to_s =~ /required/
238
+ otp = ask_otp.arity == 0 ? ask_otp.call : ask_otp.call(user)
239
+ retry
240
+ end
241
+
242
+ def acceptable?(token)
243
+ return true unless check_token
244
+ gh = GH.with(:token => token)
245
+ user = gh['user']
246
+
247
+ if github_login and github_login != user['login']
248
+ debug "token is not acceptable: identifies %p instead of %p" % [user['login'], github_login]
249
+ false
250
+ else
251
+ true
252
+ end
253
+ rescue GH::Error => error
254
+ debug "token is not acceptable: #{gh_error(error)}"
255
+ false
256
+ end
257
+
258
+ private
259
+
260
+ def gh_error(error)
261
+ raise error if explode
262
+ JSON.parse(error.info[:response_body])["message"].to_s
263
+ end
264
+
265
+ def debug(line)
266
+ return unless @debug
267
+ @debug.call "Tools::Github: #{line}"
268
+ end
269
+
270
+ def security(type, key, arg, name)
271
+ return false unless System.has? 'security'
272
+ return false unless system "security find-#{type}-password #{arg} 2>/dev/null >/dev/null"
273
+ debug "requesting to load #{name} from keychain"
274
+ result = %x[security find-#{type}-password #{arg} -#{key} 2>&1].chomp
275
+ $?.success? ? yield(result) : debug("request denied")
276
+ rescue => e
277
+ raise e if explode
278
+ end
279
+
280
+ def file(path, default = nil)
281
+ path &&= File.expand_path(path)
282
+ @file ||= {}
283
+ @file[path] ||= if path and File.readable?(path)
284
+ debug "reading #{path}"
285
+ yield File.read(path)
286
+ end
287
+ @file[path] || default
288
+ rescue => e
289
+ raise e if explode
290
+ end
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,69 @@
1
+ require "travis"
2
+ require "travis/tools/system"
3
+ require "travis/tools/assets"
4
+ require "cgi"
5
+
6
+ module Travis
7
+ module Tools
8
+ module Notification
9
+ extend self
10
+ DEFAULT = [:osx, :growl, :libnotify]
11
+ ICON = Assets['notifications/icon.png']
12
+
13
+ def new(*list)
14
+ list.concat(DEFAULT) if list.empty?
15
+ notification = list.map { |n| get(n) }.detect { |n| n.available? }
16
+ raise ArgumentError, "no notification system found (looked for #{list.join(", ")})" unless notification
17
+ notification
18
+ end
19
+
20
+ def get(name)
21
+ const = constants.detect { |c| c.to_s[/[^:]+$/].downcase == name.to_s }
22
+ raise ArgumentError, "unknown notifications type %p" % name unless const
23
+ const_get(const).new
24
+ end
25
+
26
+ class Dummy
27
+ BIN_PATH = Assets['Travis CI.app/Contents/MacOS/Travis CI']
28
+ def notify(title, body)
29
+ end
30
+
31
+ def available?
32
+ true
33
+ end
34
+ end
35
+
36
+ class OSX
37
+ BIN_PATH = Assets["notifications/Travis CI.app/Contents/MacOS/Travis CI"]
38
+
39
+ def notify(title, body)
40
+ system BIN_PATH, '-message', body.to_s, '-title', title.to_s, '-sender', 'org.travis-ci.Travis-CI'
41
+ end
42
+
43
+ def available?
44
+ System.mac? and System.recent_version?(System.os_version.to_s, '10.8') and System.running? "NotificationCenter"
45
+ end
46
+ end
47
+
48
+ class Growl
49
+ def notify(title, body)
50
+ system 'growlnotify', '-n', 'Travis', '--image', ICON, '-m', body, title
51
+ end
52
+
53
+ def available?
54
+ System.has? 'growlnotify' and System.running? "Growl"
55
+ end
56
+ end
57
+
58
+ class LibNotify
59
+ def notify(title, body)
60
+ system 'notify-send', '--expire-time=10000', '-h', 'int:transient:1', '-i', ICON, title, CGI.escapeHTML(body)
61
+ end
62
+
63
+ def available?
64
+ System.has? 'notify-send'
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,22 @@
1
+ module Travis
2
+ module Tools
3
+ module SafeString
4
+ extend self
5
+
6
+ def encoded(string)
7
+ return string unless string.respond_to? :encode
8
+ string.encode 'utf-8'
9
+ rescue Encoding::UndefinedConversionError
10
+ string.force_encoding 'utf-8'
11
+ end
12
+
13
+ def colorized(string)
14
+ encoded(string).gsub(/[^[:print:]\e\n]/, '')
15
+ end
16
+
17
+ def clean(string)
18
+ colorized(string).gsub(/\e[^m]+m/, '')
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,48 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module Travis
5
+ module Tools
6
+ module SSLKey
7
+ extend self
8
+
9
+ def generate_rsa(size = 2048)
10
+ OpenSSL::PKey::RSA.generate(size)
11
+ end
12
+
13
+ def public_rsa_key(string)
14
+ @to_rsa ||= OpenSSL::PKey::RSA.new(string)
15
+ rescue OpenSSL::PKey::RSAError
16
+ public_key = string.gsub('RSA PUBLIC KEY', 'PUBLIC KEY')
17
+ @to_rsa = OpenSSL::PKey::RSA.new(public_key)
18
+ end
19
+
20
+ def has_passphrase?(key)
21
+ OpenSSL::PKey::RSA.new(key, key)
22
+ false
23
+ rescue OpenSSL::PKey::RSAError
24
+ true
25
+ end
26
+
27
+ def remove_passphrase(key, passphrase)
28
+ OpenSSL::PKey::RSA.new(key, passphrase).to_s
29
+ rescue OpenSSL::PKey::RSAError
30
+ false
31
+ end
32
+
33
+ def rsa_ssh(key)
34
+ ['ssh-rsa ', "\0\0\0\assh-rsa#{sized_bytes(key.e)}#{sized_bytes(key.n)}"].pack('a*m').gsub("\n", '')
35
+ end
36
+
37
+ def sized_bytes(value)
38
+ bytes = to_byte_array(value.to_i)
39
+ [bytes.size, *bytes].pack('NC*')
40
+ end
41
+
42
+ def to_byte_array(num, *significant)
43
+ return significant if num.between?(-1, 0) and significant[0][7] == num[7]
44
+ to_byte_array(*num.divmod(256)) + significant
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,88 @@
1
+ module Travis
2
+ module Tools
3
+ module System
4
+ extend self
5
+
6
+ def recent_version?(version, minimum)
7
+ version = version.split('.').map { |s| s.to_i }
8
+ minimum = minimum.split('.').map { |s| s.to_i }
9
+ (version <=> minimum) >= 0
10
+ end
11
+
12
+ def windows?
13
+ File::ALT_SEPARATOR == "\\"
14
+ end
15
+
16
+ def mac?
17
+ RUBY_PLATFORM =~ /darwin/i
18
+ end
19
+
20
+ def linux?
21
+ RUBY_PLATFORM =~ /linux/i
22
+ end
23
+
24
+ def unix?
25
+ not windows?
26
+ end
27
+
28
+ def os
29
+ os_name ? "#{os_name} #{os_version}".strip : os_type
30
+ end
31
+
32
+ def full_os
33
+ os_name == os_type ? os : "#{os} like #{os_type}"
34
+ end
35
+
36
+ def os_version
37
+ @os_version ||= has?(:sw_vers) && `sw_vers -productVersion`.chomp
38
+ @os_version ||= has?(:lsb_release) && `lsb_release -r -s`.chomp
39
+ end
40
+
41
+ def os_name
42
+ @os_name ||= has?(:sw_vers) && `sw_vers -productName`.chomp
43
+ @os_name ||= has?(:lsb_release) && `lsb_release -i -s`.chomp
44
+ end
45
+
46
+ def os_type
47
+ @os_type ||= windows? ? 'Windows' : `uname`.chomp
48
+ end
49
+
50
+ def ruby_engine
51
+ defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
52
+ end
53
+
54
+ def ruby_version
55
+ "%s-p%s" % [RUBY_VERSION, RUBY_PATCHLEVEL]
56
+ end
57
+
58
+ def ruby
59
+ case ruby_engine
60
+ when 'ruby' then "Ruby #{ruby_version}"
61
+ when 'jruby' then "JRuby #{JRUBY_VERSION} like Ruby #{ruby_version}"
62
+ when 'rbx' then "Rubinius #{Rubinius.version[/\d\S+/]} like Ruby #{ruby_version}"
63
+ else "#{ruby_engine} like Ruby #{ruby_version}"
64
+ end
65
+ end
66
+
67
+ def rubygems
68
+ return "no RubyGems" unless defined? Gem
69
+ "RubyGems #{Gem::VERSION}"
70
+ end
71
+
72
+ def description(*args)
73
+ [ full_os, ruby, rubygems, *args.flatten].compact.uniq.join("; ")
74
+ end
75
+
76
+ def has?(command)
77
+ return false unless unix?
78
+ @has ||= {}
79
+ @has.fetch(command) { @has[command] = system "which #{command} 2>/dev/null >/dev/null" }
80
+ end
81
+
82
+ def running?(app)
83
+ return false unless unix?
84
+ system "pgrep -u $(whoami) #{app} >/dev/null"
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,3 @@
1
+ module Travis
2
+ VERSION = '1.8.9'
3
+ end
data/lib/travis.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Travis
2
+ autoload :Client, 'travis/client'
3
+ autoload :CLI, 'travis/cli'
4
+ autoload :Pro, 'travis/pro'
5
+ autoload :Version, 'travis/version'
6
+
7
+ include Client::Namespace.new(Client::ORG_URI)
8
+ end