travis 1.0.0

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 (49) hide show
  1. data/LICENSE +22 -0
  2. data/README.md +154 -0
  3. data/Rakefile +38 -0
  4. data/bin/travis +4 -0
  5. data/lib/travis.rb +8 -0
  6. data/lib/travis/cacert.pem +3895 -0
  7. data/lib/travis/cli.rb +83 -0
  8. data/lib/travis/cli/api_command.rb +65 -0
  9. data/lib/travis/cli/command.rb +212 -0
  10. data/lib/travis/cli/encrypt.rb +57 -0
  11. data/lib/travis/cli/endpoint.rb +13 -0
  12. data/lib/travis/cli/help.rb +21 -0
  13. data/lib/travis/cli/login.rb +57 -0
  14. data/lib/travis/cli/parser.rb +43 -0
  15. data/lib/travis/cli/raw.rb +16 -0
  16. data/lib/travis/cli/repo_command.rb +54 -0
  17. data/lib/travis/cli/version.rb +12 -0
  18. data/lib/travis/cli/whoami.rb +12 -0
  19. data/lib/travis/client.rb +20 -0
  20. data/lib/travis/client/entity.rb +139 -0
  21. data/lib/travis/client/error.rb +11 -0
  22. data/lib/travis/client/methods.rb +45 -0
  23. data/lib/travis/client/namespace.rb +78 -0
  24. data/lib/travis/client/repository.rb +66 -0
  25. data/lib/travis/client/session.rb +191 -0
  26. data/lib/travis/client/user.rb +20 -0
  27. data/lib/travis/pro.rb +5 -0
  28. data/lib/travis/tools/token_finder.rb +51 -0
  29. data/lib/travis/version.rb +3 -0
  30. data/spec/cli/encrypt_spec.rb +18 -0
  31. data/spec/cli/endpoint_spec.rb +23 -0
  32. data/spec/cli/help_spec.rb +33 -0
  33. data/spec/cli/login_spec.rb +13 -0
  34. data/spec/cli/version_spec.rb +18 -0
  35. data/spec/cli/whoami_spec.rb +27 -0
  36. data/spec/client/methods_spec.rb +15 -0
  37. data/spec/client/namespace_spec.rb +19 -0
  38. data/spec/client/repository_spec.rb +15 -0
  39. data/spec/client/session_spec.rb +145 -0
  40. data/spec/client/user_spec.rb +16 -0
  41. data/spec/client_spec.rb +5 -0
  42. data/spec/pro_spec.rb +10 -0
  43. data/spec/spec_helper.rb +16 -0
  44. data/spec/support/fake_api.rb +89 -0
  45. data/spec/support/fake_github.rb +20 -0
  46. data/spec/support/helpers.rb +43 -0
  47. data/spec/travis_spec.rb +9 -0
  48. data/travis.gemspec +84 -0
  49. metadata +240 -0
@@ -0,0 +1,66 @@
1
+ require 'travis/client'
2
+ require 'openssl'
3
+ require 'base64'
4
+
5
+ module Travis
6
+ module Client
7
+ class Repository < Entity
8
+ class Key
9
+ attr_reader :to_s
10
+
11
+ def initialize(data)
12
+ @to_s = data
13
+ end
14
+
15
+ def encrypt(value)
16
+ encrypted = to_rsa.public_encrypt(value)
17
+ Base64.encode64(encrypted).strip
18
+ end
19
+
20
+ def to_rsa
21
+ @to_rsa ||= OpenSSL::PKey::RSA.new(to_s)
22
+ rescue OpenSSL::PKey::RSAError
23
+ public_key = to_s.gsub('RSA PUBLIC KEY', 'PUBLIC KEY')
24
+ @to_rsa = OpenSSL::PKey::RSA.new(public_key)
25
+ end
26
+
27
+ def ==(other)
28
+ other.to_s == self
29
+ end
30
+ end
31
+
32
+ attributes :slug, :description, :last_build_id, :last_build_number, :last_build_state, :last_build_duration, :last_build_language, :last_build_started_at, :last_build_finished_at
33
+ inspect_info :slug
34
+
35
+ one :repo
36
+ many :repos
37
+
38
+ def public_key
39
+ attributes["public_key"] ||= begin
40
+ payload = session.get_raw("/repos/#{id}/key")
41
+ Key.new(payload.fetch('key'))
42
+ end
43
+ end
44
+
45
+ def public_key=(key)
46
+ key = Key.new(key) unless key.is_a? Key
47
+ set_attribute(:public_key, key)
48
+ end
49
+
50
+ alias key public_key
51
+ alias key= public_key=
52
+
53
+ def encrypt(value)
54
+ key.encrypt(value)
55
+ end
56
+
57
+ def last_build_started_at=(time)
58
+ set_attribute(:last_build_started_at, time(time))
59
+ end
60
+
61
+ def last_build_finished_at=(time)
62
+ set_attribute(:last_build_finished_at, time(time))
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,191 @@
1
+ require 'travis/client'
2
+
3
+ require 'faraday'
4
+ require 'faraday_middleware'
5
+ require 'json'
6
+
7
+ module Travis
8
+ module Client
9
+ class Session
10
+ SSL_OPTIONS = { :ca_file => File.expand_path("../../cacert.pem", __FILE__) }
11
+ include Methods
12
+ attr_reader :connection, :headers, :access_token
13
+
14
+ def initialize(options = Travis::Client::ORG_URI)
15
+ @headers = {}
16
+ @cache = {}
17
+
18
+ options = { :uri => options } unless options.respond_to? :each_pair
19
+ options.each_pair { |key, value| public_send("#{key}=", value) }
20
+
21
+ raise ArgumentError, "neither :uri nor :connection specified" unless connection
22
+ headers['Accept'] ||= 'application/vnd.travis-ci.2+json, */*; q=0.01'
23
+ end
24
+
25
+ def uri
26
+ connection.url_prefix.to_s if connection
27
+ end
28
+
29
+ def uri=(uri)
30
+ clear_cache!
31
+ self.connection = Faraday.new(:url => uri, :ssl => SSL_OPTIONS) do |faraday|
32
+ faraday.request :json
33
+ faraday.response :json
34
+ faraday.response :follow_redirects
35
+ faraday.response :raise_error
36
+ faraday.adapter(*faraday_adapter)
37
+ end
38
+ end
39
+
40
+ def access_token=(token)
41
+ clear_cache!
42
+ @access_token = token
43
+ headers['Authorization'] = "token #{token}"
44
+ headers.delete('Authorization') unless token
45
+ end
46
+
47
+ def connection=(connection)
48
+ clear_cache!
49
+ connection.headers.merge! headers
50
+ @connection = connection
51
+ @headers = connection.headers
52
+ end
53
+
54
+ def headers=(headers)
55
+ clear_cache!
56
+ connection.headers = headers if connection
57
+ @headers = headers
58
+ end
59
+
60
+ def find_one(entity, id = nil)
61
+ raise Travis::Error, "cannot fetch #{entity}" unless entity.respond_to?(:many) and entity.many
62
+ return create_entity(entity, "id" => id) if id.is_a? Integer
63
+ cached(entity, :by, id) { fetch_one(entity, id) }
64
+ end
65
+
66
+ def find_many(entity, args = {})
67
+ raise Travis::Error, "cannot fetch #{entity}" unless entity.respond_to?(:many) and entity.many
68
+ cached(entity, :many, args) { fetch_many(entity, args) }
69
+ end
70
+
71
+ def find_one_or_many(entity, args = nil)
72
+ raise Travis::Error, "cannot fetch #{entity}" unless entity.respond_to?(:many) and entity.many
73
+ cached(entity, :one_or_many, args) do
74
+ path = "/#{entity.many}"
75
+ path, args = "#{path}/#{args}", {} unless args.is_a? Hash
76
+ result = get(path, args)
77
+ one = result[entity.one]
78
+
79
+ if result.include? entity.many
80
+ Array(one) + Array(result[entity.many])
81
+ else
82
+ one
83
+ end
84
+ end
85
+ end
86
+
87
+ def reload(entity)
88
+ result = fetch_one(entity.class, entity.id)
89
+ entity.update_attributes(result.attributes) if result.attributes != entity.attributes
90
+ result
91
+ end
92
+
93
+ def get(*args)
94
+ result = {}
95
+ get_raw(*args).each_pair do |key, value|
96
+ type = Entity.subclass_for(key)
97
+ if value.respond_to? :to_ary
98
+ result[key] = value.to_ary.map { |e| create_entity(type, e) }
99
+ else
100
+ result[key] = create_entity(type, value)
101
+ end
102
+ end
103
+ result
104
+ end
105
+
106
+ def get_raw(*args)
107
+ connection.get(*args).body
108
+ rescue Faraday::Error::ClientError => e
109
+ handle_error(e)
110
+ end
111
+
112
+ def post_raw(*args)
113
+ connection.post(*args).body
114
+ rescue Faraday::Error::ClientError => e
115
+ handle_error(e)
116
+ end
117
+
118
+ def inspect
119
+ "#<#{self.class}: #{uri}>"
120
+ end
121
+
122
+ def clear_cache
123
+ reset_entities
124
+ clear_find_cache
125
+ self
126
+ end
127
+
128
+ def clear_cache!
129
+ reset_entities
130
+ @cache.clear
131
+ self
132
+ end
133
+
134
+ def session
135
+ self
136
+ end
137
+
138
+ private
139
+
140
+ def create_entity(type, data)
141
+ id = Integer(data.fetch('id'))
142
+ entity = cached(type, :id, id) { type.new(self, id) }
143
+ entity.update_attributes(data)
144
+ entity
145
+ end
146
+
147
+ def handle_error(e)
148
+ message = e.response[:body].to_str rescue e.message
149
+ klass = Travis::Client::NotFound if e.is_a? Faraday::Error::ResourceNotFound
150
+ klass ||= Travis::Client::Error
151
+ raise klass, message, e.backtrace
152
+ end
153
+
154
+ def faraday_adapter
155
+ Faraday.default_adapter
156
+ end
157
+
158
+ def reset_entities
159
+ subcaches do |subcache|
160
+ subcache[:id].each_value { |e| e.attributes.clear } if subcache.include? :id
161
+ end
162
+ end
163
+
164
+ def clear_find_cache
165
+ subcaches do |subcache|
166
+ subcache.delete_if { |k, v| k != :id }
167
+ end
168
+ end
169
+
170
+ def subcaches
171
+ @cache.each_value do |subcache|
172
+ yield subcache if subcache.is_a? Hash
173
+ end
174
+ end
175
+
176
+ def fetch_one(entity, id = nil)
177
+ get("/#{entity.many}/#{id}")[entity.one]
178
+ end
179
+
180
+ def fetch_many(entity, params = {})
181
+ get("/#{entity.many}/", params)[entity.many]
182
+ end
183
+
184
+ def cached(*keys)
185
+ last = keys.pop
186
+ cache = keys.inject(@cache) { |store, key| store[key] ||= {} }
187
+ cache[last] ||= yield
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,20 @@
1
+ require 'travis/client'
2
+
3
+ module Travis
4
+ module Client
5
+ class User < Entity
6
+ attributes :login, :name, :email, :gravatar_id, :locale, :is_syncing, :synced_at, :correct_scopes
7
+ inspect_info :login
8
+
9
+ one :user
10
+ many :users
11
+
12
+ def synced_at=(time)
13
+ set_attribute(:synced_at, time(time))
14
+ end
15
+
16
+ alias syncing? is_syncing
17
+ alias correct_scopes? correct_scopes
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ require 'travis/client'
2
+
3
+ module Travis
4
+ Pro = Client::Namespace.new(Client::PRO_URI)
5
+ end
@@ -0,0 +1,51 @@
1
+ require 'netrc'
2
+ require 'yaml'
3
+
4
+ module Travis
5
+ module Tools
6
+ # This is used when running `travis login --auto`
7
+ class TokenFinder
8
+ attr_accessor :netrc, :hub, :explode, :github
9
+
10
+ def self.find(options = {})
11
+ new(options).find
12
+ end
13
+
14
+ def initialize(options = {})
15
+ self.netrc = options[:netrc] || Netrc.default_path
16
+ self.hub = options[:hub] || ENV['HUB_CONFIG'] || '~/.config/hub'
17
+ self.github = options[:github] || 'github.com'
18
+ self.explode = options[:explode]
19
+ end
20
+
21
+ def hub=(file)
22
+ @hub = File.expand_path(file)
23
+ end
24
+
25
+ def netrc=(file)
26
+ @netrc = File.expand_path(file)
27
+ end
28
+
29
+ def find
30
+ find_netrc || find_hub
31
+ end
32
+
33
+ def find_netrc
34
+ return unless File.readable? netrc
35
+ data = Netrc.read(netrc)[github]
36
+ data.detect { |e| e.size == 40 } if data
37
+ rescue => e
38
+ raise e if explode
39
+ end
40
+
41
+ def find_hub
42
+ return unless File.readable? hub
43
+ data = YAML.load_file(File.expand_path(hub))
44
+ data &&= Array(data[github])
45
+ data.first['oauth_token'] if data.size == 1
46
+ rescue => e
47
+ raise e if explode
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,3 @@
1
+ module Travis
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Travis::CLI::Endpoint do
4
+ example "travis encrypt foo" do
5
+ run_cli('encrypt', 'foo').should be_success
6
+ stdout.should match(/^".{60,}"\n$/)
7
+ end
8
+
9
+ example "travis encrypt foo -i" do
10
+ run_cli('encrypt', 'foo', '-i').should be_success
11
+ stdout.should start_with("Please add the following to your \e[33m.travis.yml\e[0m file:\n\n secure: ")
12
+ end
13
+
14
+ example "cat foo | travis encrypt" do
15
+ run_cli('encrypt') { |i| i.puts('foo') }
16
+ stdout.should match(/^".{60,}"\n$/)
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Travis::CLI::Endpoint do
4
+ example "travis endpoint" do
5
+ run_cli('endpoint').should be_success
6
+ stdout.should be == "https://api.travis-ci.org/\n"
7
+ end
8
+
9
+ example "travis endpoint --pro" do
10
+ run_cli('endpoint', '--pro').should be_success
11
+ stdout.should be == "https://api.travis-ci.com/\n"
12
+ end
13
+
14
+ example "travis endpoint -e http://localhost:3000/" do
15
+ run_cli('endpoint', '-e', 'http://localhost:3000/').should be_success
16
+ stdout.should be == "http://localhost:3000/\n"
17
+ end
18
+
19
+ example "travis endpoint -i" do
20
+ run_cli('endpoint', '-i').should be_success
21
+ stdout.should be == "API endpoint: \e[1m\e[4mhttps://api.travis-ci.org/\e[0m\n"
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Travis::CLI::Help do
4
+ example "travis help" do
5
+ run_cli('help').should be_success
6
+ stdout.should start_with("Usage: #$0 COMMAND")
7
+ end
8
+
9
+ example "travis --help" do
10
+ run_cli('--help').should be_success
11
+ stdout.should start_with("Usage: #$0 COMMAND")
12
+ end
13
+
14
+ example "travis -h" do
15
+ run_cli('-h').should be_success
16
+ stdout.should start_with("Usage: #$0 COMMAND")
17
+ end
18
+
19
+ example "travis -?" do
20
+ run_cli('-?').should be_success
21
+ stdout.should start_with("Usage: #$0 COMMAND")
22
+ end
23
+
24
+ example "travis help endpoint" do
25
+ run_cli('help', 'endpoint').should be_success
26
+ stdout.should start_with("Usage: #$0 endpoint [options]")
27
+ end
28
+
29
+ example "travis endpoint --help" do
30
+ run_cli('endpoint', '--help').should be_success
31
+ stdout.should start_with("Usage: #$0 endpoint [options]")
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Travis::CLI::Login do
4
+ example "travis login" do
5
+ run_cli('login') { |i| i.puts('rkh', 'password') }.should be_success
6
+ run_cli('whoami').out.should be == "rkh\n"
7
+ end
8
+
9
+ example "travis login (with bad credentials)" do
10
+ run_cli('login') { |i| i.puts('rkh', 'wrong password') }.should_not be_success
11
+ run_cli('whoami').should_not be_success
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Travis::CLI::Version do
4
+ example do
5
+ run_cli('-v').should be_success
6
+ stdout.should be == "#{Travis::VERSION}\n"
7
+ end
8
+
9
+ example do
10
+ run_cli('--version').should be_success
11
+ stdout.should be == "#{Travis::VERSION}\n"
12
+ end
13
+
14
+ example do
15
+ run_cli('version').should be_success
16
+ stdout.should be == "#{Travis::VERSION}\n"
17
+ end
18
+ end