travis 1.0.0

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