travis-client 0.1.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -2
  3. data/.rspec +3 -2
  4. data/.travis.yml +2 -9
  5. data/.yardopts +2 -0
  6. data/Gemfile +1 -3
  7. data/Gemfile.lock +59 -0
  8. data/lib/travis/client.rb +20 -104
  9. data/lib/travis/client/action.rb +128 -0
  10. data/lib/travis/client/collection.rb +66 -0
  11. data/lib/travis/client/connection.rb +104 -0
  12. data/lib/travis/client/context.rb +52 -0
  13. data/lib/travis/client/entity.rb +77 -0
  14. data/lib/travis/client/error.rb +47 -0
  15. data/lib/travis/client/generated.rb +2073 -0
  16. data/lib/travis/client/link.rb +34 -0
  17. data/lib/travis/client/session.rb +101 -0
  18. data/lib/travis/client/unknown.rb +5 -0
  19. data/lib/travis/client/version.rb +6 -0
  20. data/readme.md +187 -0
  21. data/script/generate +44 -0
  22. data/spec/http_responses/default/branches.http +715 -0
  23. data/spec/http_responses/default/find_owner.http +23 -0
  24. data/spec/http_responses/default/index.http +1518 -0
  25. data/spec/http_responses/default/repo.http +44 -0
  26. data/spec/http_responses/default/repo_branches_10.http +347 -0
  27. data/spec/http_responses/default/repo_branches_10_0.http +347 -0
  28. data/spec/http_responses/default/repo_branches_10_10.http +351 -0
  29. data/spec/http_responses/default/repo_branches_10_20.http +99 -0
  30. data/spec/http_responses/default/sync.http +12 -0
  31. data/spec/http_responses/default/user_repos.http +6315 -0
  32. data/spec/spec_helper.rb +4 -2
  33. data/spec/support/coverage.rb +8 -0
  34. data/spec/support/generate_http_response.rb +16 -0
  35. data/spec/support/http.rb +54 -0
  36. data/spec/travis/collection_spec.rb +19 -0
  37. data/spec/travis/connection_spec.rb +26 -0
  38. data/spec/travis/entity_spec.rb +27 -0
  39. data/spec/travis_spec.rb +18 -0
  40. data/travis-client.gemspec +21 -21
  41. metadata +103 -75
  42. data/README.textile +0 -111
  43. data/Rakefile +0 -8
  44. data/bin/travis +0 -21
  45. data/features/repositories.feature +0 -117
  46. data/features/step_definitions/repositories_steps.rb +0 -51
  47. data/features/support/env.rb +0 -2
  48. data/lib/travis.rb +0 -2
  49. data/lib/travis/api.rb +0 -3
  50. data/lib/travis/api/client.rb +0 -95
  51. data/lib/travis/api/client/repositories.rb +0 -234
  52. data/lib/travis/api/entity.rb +0 -44
  53. data/lib/travis/api/entity/build.rb +0 -129
  54. data/lib/travis/api/entity/repository.rb +0 -79
  55. data/lib/travis/client/repositories.rb +0 -345
  56. data/spec/travis/api/client/repositories_spec.rb +0 -2
  57. data/spec/travis/api/client_spec.rb +0 -15
  58. data/spec/travis/api/entity/build_spec.rb +0 -84
  59. data/spec/travis/api/entity/repository_spec.rb +0 -79
  60. data/spec/travis/api/entity_spec.rb +0 -46
  61. data/spec/travis/api/shared_client_examples.rb +0 -3
  62. data/spec/travis/api/shared_entity_examples.rb +0 -16
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ module Travis::Client
3
+ class Link
4
+ attr_reader :session, :href
5
+
6
+ def initialize(session, href, payload = {})
7
+ @session, @href, @payload = session, href, payload
8
+ end
9
+
10
+ def to_entity
11
+ fetch
12
+ end
13
+
14
+ def fetch
15
+ session.fetch(href)
16
+ end
17
+
18
+ def to_h
19
+ @payload.dup
20
+ end
21
+
22
+ def offset
23
+ @payload['offset']
24
+ end
25
+
26
+ def limit
27
+ @payload['limit']
28
+ end
29
+
30
+ def inspect
31
+ "#<%p:%p>" % [ self.class, href.omit(:scheme, :authority).to_s ]
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+ module Travis::Client
3
+ class Session
4
+ LINK_ATTRIBUTES = %w[@href offset limit]
5
+ private_constant :LINK_ATTRIBUTES
6
+
7
+ attr_reader :connection, :response_cache, :request_headers
8
+
9
+ def initialize(connection, access_token: nil, request_headers: {})
10
+ @connection = connection
11
+ @http_connections = {}
12
+ @response_cache = {}
13
+ @request_headers = connection.request_headers.merge(request_headers)
14
+ @request_headers['Authorization'] = "token #{access_token}" if access_token
15
+ end
16
+
17
+ def inspect
18
+ "#<#{Session}>"
19
+ end
20
+
21
+ def request(method, uri, params = {})
22
+ method = method.to_s.upcase
23
+ options = {}
24
+ options[:json] = params if params.any?
25
+ uri = Addressable::URI.parse(uri) unless uri.is_a? Addressable::URI
26
+ response = connection.notify(method, uri, params) { http_connection(uri).request(method, uri, options) }
27
+ payload = JSON.load(response.body)
28
+ wrap(payload, uri)
29
+ end
30
+
31
+ def call(resource_type, action_name, variables = {})
32
+ action(resource_type, action_name).call(self, variables)
33
+ end
34
+
35
+ def error_types
36
+ # we currently don't allow/need to override error types
37
+ connection.error_types
38
+ end
39
+
40
+ def resource_types
41
+ return @resource_types if defined? @resource_types and @resource_types
42
+ connection.resource_types
43
+ end
44
+
45
+ def set_default_types
46
+ @resource_types ||= connection.resource_types.map { |k,v| [k,v.for_session(self)] }.to_h
47
+ end
48
+
49
+ def define_constants(container)
50
+ set_default_types
51
+ error_types.merge(resource_types).each do |key, factory|
52
+ constant = key.split('_').map(&:capitalize).join
53
+ container.const_set(constant, factory) unless container.const_defined?(constant, false)
54
+ end
55
+ container.extend connection.mixin
56
+ container
57
+ end
58
+
59
+ def fetch(link)
60
+ response_cache.fetch(link) { request('GET', link) }
61
+ end
62
+
63
+ private def session
64
+ self
65
+ end
66
+
67
+ private def http_connection(uri)
68
+ raise ArgumentError, 'request URI needs to be absolute' unless uri.absolute?
69
+ @http_connections[uri.authority] ||= connection.http_factory.persistent(uri.join('/')).headers(request_headers)
70
+ end
71
+
72
+ private def wrap(payload, uri)
73
+ case payload
74
+ when Array then payload.map { |e| wrap(e, uri) }
75
+ when Hash then load(payload.map { |k,v| [k, wrap(v, uri)] }.to_h, uri)
76
+ else payload
77
+ end
78
+ end
79
+
80
+ private def load(payload, uri)
81
+ return payload unless payload['@type'] or payload['@href']
82
+
83
+ if payload['@type'] == 'error'
84
+ factory = error_types.fetch(payload['error_type']) { resource_types.fetch('error', Error) }
85
+ error = factory.new(self, payload['error_message'] || factory.default_message)
86
+ error.merge! payload
87
+ raise error
88
+ end
89
+
90
+ if payload['@href']
91
+ href = uri.join(payload['@href'])
92
+ return response_cache[href] || Link.new(self, href, payload) if payload.all? { |a, _| LINK_ATTRIBUTES.include?(a) }
93
+ current = response_cache[href]
94
+ end
95
+
96
+ current ||= resource_types.fetch(payload['@type'], Unknown).new(self, href)
97
+ current.merge! payload
98
+ response_cache[href] = current
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ module Travis::Client
3
+ class Unknown < Entity
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ module Travis
3
+ module Client
4
+ VERSION = '3.0.0'
5
+ end
6
+ end
@@ -0,0 +1,187 @@
1
+ # Travis CI API Client
2
+
3
+ Ruby client for the [Travis CI API, version 3](https://developer.travis-ci.com/).
4
+
5
+ ## Installation
6
+
7
+ You can install it as a RubyGem via:
8
+
9
+ ``` console
10
+ $ gem install travis-client
11
+ ```
12
+
13
+ Note that it does conflict with [travis.rb](https://github.com/travis-ci/travis.rb) at the moment, as both of them add a `travis/client` file. It is highly recommended to use [Bundler](http://bundler.io/) to avoid accidentally loading the wrong gem in your scripts.
14
+
15
+ ## Getting Started
16
+
17
+ This library has two general ways to use it. An interface based on globals, that should feel quite natural to Ruby developers:
18
+
19
+ ``` ruby
20
+ require 'travis/client'
21
+ Travis.connect # call before interacting with anything else
22
+ repository = Travis::Repository.find(slug: 'travis-ci/travis-web')
23
+ ```
24
+
25
+ Or an approach based on sessions, which helps avoiding global state, and easily allows multiple connections in parallel with different credentials or even different Travis CI installations:
26
+
27
+ ``` ruby
28
+ require 'travis/client'
29
+ connection = Travis.new
30
+ session = connection.create_session
31
+ repository = session.find_repository(slug: 'travis-ci/travis-web')
32
+ ```
33
+
34
+ Objects returned by `Repository.find` and `find_repository` are identical. You can access the underlying session object used by `Travis::Repository.find` via `Travis.session`.
35
+
36
+ Each session will have its own cache, and HTTP connections. Recreating connection objects (by either calling `Travis.connect` or `Travis.new`) frequently should be avoided, as it will rebuild internal factories based on the API auto-discovery.
37
+
38
+ Both `Travis.new` and `Travis.connect` accept the following options:
39
+
40
+ * **endpoint:** URI for the entry point to the Travis CI API, defaults to `https://api.travis-ci.org`. Set this to `https://api.travis-ci.com` for the Pro version of Travis CI, `https://travis.your-domain.com/api` for Travis CI Enterprise (assuming your Enterprise web UI is reachable under `https://travis.your-domain.com`).
41
+ * **request_headers:** Allows defining additional headers to be sent to Travis CI with every HTTP request. Can also be used to override headers, like `User-Agent`.
42
+ * **access_token:** API access token to use for authentication.
43
+
44
+ ## Advanced Features
45
+
46
+ ### Authentication
47
+
48
+ You'll need an API token to authenticate. The library currently does not offer a way to obtain such a token, the easiest way to obtain such a token is to visit the developer pages and hover over the token in a code example and copy the value. Please note that there are separate tokens for [travis-ci.org](https://developer.travis-ci.org/explore/user) and [travis-ci.com](https://developer.travis-ci.com/explore/user), and you will have to use the appropriate token depending on which API you interact with.
49
+
50
+ Alternatively, you can use the [`token` command](https://github.com/travis-ci/travis.rb#token) from the CLI.
51
+
52
+ ``` ruby
53
+ # connecting to travis-ci.org with a token stored in TRAVIS_TOKEN env var
54
+ Travis.connect(access_token: ENV['TRAVIS_TOKEN'])
55
+
56
+ # connecting to travis-ci.com with a token stored in TRAVIS_PRO_TOKEN env var
57
+ Travis.connect(api_endpoint: 'https://api.travis-ci.com' access_token: ENV['TRAVIS_PRO_TOKEN'])
58
+ ```
59
+
60
+ When using multiple sessions, the token may either be passed to the connection (in which case it will be used fo all sessions) or each session individually:
61
+
62
+ ``` ruby
63
+ connection = Travis.new(access_token: ENV['TRAVIS_TOKEN'])
64
+ puts connection.create_session.current_user.login
65
+
66
+
67
+ # for a list of tokens, output which user is associated with it
68
+ access_tokens = [ ... list of tokens ... ]
69
+ connection = Travis.new(api_endpoint: 'https://api.travis-ci.com')
70
+ access_tokens.each do |token|
71
+ session = connection.create_session(access_token: token)
72
+ puts session.current_user.login
73
+ end
74
+ ```
75
+
76
+ ### Caching and Session Renewal
77
+
78
+ Each session will have it's own cache. If you have long running processes and concerns about cache size or stale caches, then the easiest and cleanest way to deal with this is to discard session objects after a while and not hold on to any entities associated with it.
79
+
80
+ In a web application (like Rails or Sinatra), it is recommended to use a new session per request, or per background job. This will also greatly decrease threading issues (see below).
81
+
82
+ ``` ruby
83
+ require 'sinatra'
84
+ require 'travis/client'
85
+
86
+ # create connection once, but create one session per request
87
+ connection = Travis.new(access_token: ENV['TRAVIS_TOKEN'])
88
+ before { @travis = connection.create_session }
89
+
90
+ get '/' do
91
+ "Hello, #{@travis.current_user.name}!"
92
+ end
93
+ ```
94
+
95
+ If you do have to clear a session's cache, you can do so via `session.response_cache.clear` or `Travis.clear_cache`. However, this is not recommended and any response objects that might still be referenced somewhere will probably end up with a mix of outdated and recent data.
96
+
97
+ ### Thread Safety
98
+
99
+ Neither `Travis.connect` nor loading resources is currently thread-safe, with the notable exception of `Connection#create_session`. You still can (and should) use it in a threaded environment.
100
+
101
+ To use with a threaded environment:
102
+
103
+ * Initialize a new connection once, via `Travis.new`.
104
+ * From this connection, create one session per thread via `#create_session`.
105
+
106
+ Example that fetches repositories in parallel:
107
+
108
+ ``` ruby
109
+ require 'travis/client'
110
+
111
+ repositories = ['travis-ci/travis-web', 'travis-ci/travis-api', 'sinatra/sinatra']
112
+ connection = Travis.new
113
+ threads = repositories.map do |slug|
114
+ Thread.new { connection.create_session.find_repository(slug: slug) }
115
+ end
116
+
117
+ threads.each do |thread|
118
+ puts thread.value.name
119
+ end
120
+ ```
121
+
122
+ ### Permission Checks
123
+
124
+ You can check permissions on any entity object via the `permission?` method:
125
+
126
+ ``` ruby
127
+ Travis::User.current.permission? :sync # => true
128
+ Travis::Owner.find(login: 'svenfuchs').permission? :sync # => false
129
+
130
+ user = Travis::User.current
131
+ user.sync if user.permission? :sync
132
+ ```
133
+
134
+ You can find a full list of permission in the [developer documentation](https://developer.travis-ci.org/).
135
+
136
+ ### Eager Loading
137
+
138
+ The following code will trigger two HTTP requests, one to fetch the repository, and one to fetch the last build on the default branch:
139
+
140
+ ``` ruby
141
+ repository = Travis::Repository.find(slug: 'travis-ci/travis-api')
142
+ puts repository.default_branch.last_build.state
143
+ ```
144
+
145
+ You can reduce this to a single HTTP request by eager loading `branch.last_build`:
146
+
147
+ ``` ruby
148
+ repository = Travis::Repository.find(slug: 'travis-ci/travis-api', include: 'branch.last_build')
149
+ puts repository.default_branch.last_build.state
150
+ ```
151
+
152
+ ### Pagination
153
+
154
+ Each object representing a collection is an Enumerable and will handle pagination in a transparent way:
155
+
156
+ ``` ruby
157
+ # will automatically paginate if necessary
158
+ repository.branches.map { |branch| branch.name }
159
+ ```
160
+
161
+ Just like with missing attributes, the code will trigger any additional HTTP requests lazily, but only once, so exiting a loop over a collection prematurely (for instance, by using `break` or `return`) might reduce the number of HTTP requests.
162
+
163
+ You can also use the `limit`, `offset` and `sort` parameters to fine-tune requests.
164
+
165
+ ### Request Hooks and Instrumentation
166
+
167
+ You can add hooks that will trigger before or after any HTTP request:
168
+
169
+ ``` ruby
170
+ Travis.before_request { |r| puts "** #{r.request_method} #{r.uri}"}
171
+ Travis::Repository.find(slug: 'rails/rails')
172
+ ```
173
+
174
+ You can use the `meta_data` hash to share data between hooks:
175
+
176
+ ``` ruby
177
+ Travis.before_request do |request|
178
+ request.meta_data[:start] = Time.now
179
+ end
180
+
181
+ Travis.after_request do |request|
182
+ duration = Time.now - request.meta_data[:start]
183
+ puts "** #{request.request_method} #{request.uri} - #{request.response.status} - #{duration}s"
184
+ end
185
+
186
+ Travis::Repository.find(slug: 'rails/rails')
187
+ ```
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ require 'bundler/setup'
4
+ require 'travis/client'
5
+ require 'yaml'
6
+
7
+ unless ARGV.first and File.exist? ARGV.first
8
+ $stderr.puts "Please specify path to attributes.yml (from data directory in developer repo)."
9
+ exit 1
10
+ end
11
+
12
+ info = YAML.load_file(ARGV.first)
13
+ Travis.connect
14
+
15
+ signature = Proc.new do |dev_info, method_name, method, klass|
16
+ docs = dev_info['description']
17
+ docs &&= docs.sub(/^(\w)/) { |s| s.upcase }.sub(/\w$/, '\0.')
18
+ docs ||= "Wheather or not ##{method_name.to_s.sub(/\?$/, '')} returns a truthy value (anything but `nil` or `false`)." if method_name.to_s.end_with? '?'
19
+ args = method.parameters.map { |mode, name| mode == :opt ? "#{name} = #{name == :params ? '{}' : 'nil'}" : name }.join(', ')
20
+ args = "(#{args})" unless args.empty?
21
+
22
+ puts "# # #{docs}" if docs
23
+ puts "# def #{method_name}#{args}", "# # This is a placeholder.", "# end"
24
+ end
25
+
26
+ puts '# @!parse'
27
+
28
+ Travis.session.resource_types.each_with_index do |(type, klass), klass_index|
29
+ puts "# " if klass_index > 0
30
+ superclass = klass < Travis::Client::Collection ? Travis::Client::Collection : Travis::Client::Entity
31
+ puts "# class #{klass} < #{superclass}"
32
+
33
+ (klass.methods - superclass.methods - [:session]).each do |method|
34
+ signature[info["#{type}.#{method}"] || {}, "self.#{method}", klass.method(method), klass]
35
+ puts "# "
36
+ end
37
+
38
+ (klass.instance_methods - superclass.instance_methods).each_with_index do |method, method_index|
39
+ next if superclass == Travis::Client::Collection and method.to_s.sub(/\?$/, '') == type
40
+ puts "# " if method_index > 0
41
+ signature[info["#{type}.#{method}"] || {}, method, klass.instance_method(method), klass]
42
+ end
43
+ puts "# end"
44
+ end
@@ -0,0 +1,715 @@
1
+ GET https://api.travis-ci.org/repo/409371/branches HTTP/1.1
2
+ Accept: application/json
3
+ Travis-API-Version: 3
4
+
5
+ HTTP/1.1 200 OK
6
+ Content-Type: application/json
7
+
8
+ {
9
+ "@type": "branches",
10
+ "@href": "/repo/409371/branches",
11
+ "@representation": "standard",
12
+ "@pagination": {
13
+ "limit": 25,
14
+ "offset": 0,
15
+ "count": 22,
16
+ "is_first": true,
17
+ "is_last": true,
18
+ "next": null,
19
+ "prev": null,
20
+ "first": {
21
+ "@href": "/repo/409371/branches",
22
+ "offset": 0,
23
+ "limit": 25
24
+ },
25
+ "last": {
26
+ "@href": "/repo/409371/branches",
27
+ "offset": 0,
28
+ "limit": 25
29
+ }
30
+ },
31
+ "branches": [
32
+ {
33
+ "@type": "branch",
34
+ "@href": "/repo/409371/branch/master",
35
+ "@representation": "standard",
36
+ "name": "master",
37
+ "repository": {
38
+ "@type": "repository",
39
+ "@href": "/repo/409371",
40
+ "@representation": "minimal",
41
+ "id": 409371,
42
+ "name": "travis.rb",
43
+ "slug": "travis-ci/travis.rb"
44
+ },
45
+ "default_branch": true,
46
+ "exists_on_github": true,
47
+ "last_build": {
48
+ "@type": "build",
49
+ "@href": "/build/207350319",
50
+ "@representation": "minimal",
51
+ "id": 207350319,
52
+ "number": "826",
53
+ "state": "passed",
54
+ "duration": 523,
55
+ "event_type": "push",
56
+ "previous_state": "passed",
57
+ "pull_request_title": null,
58
+ "pull_request_number": null,
59
+ "started_at": "2017-03-03T13:03:34Z",
60
+ "finished_at": "2017-03-03T13:16:52Z"
61
+ }
62
+ },
63
+ {
64
+ "@type": "branch",
65
+ "@href": "/repo/409371/branch/ag-bump-version",
66
+ "@representation": "standard",
67
+ "name": "ag-bump-version",
68
+ "repository": {
69
+ "@type": "repository",
70
+ "@href": "/repo/409371",
71
+ "@representation": "minimal",
72
+ "id": 409371,
73
+ "name": "travis.rb",
74
+ "slug": "travis-ci/travis.rb"
75
+ },
76
+ "default_branch": false,
77
+ "exists_on_github": true,
78
+ "last_build": {
79
+ "@type": "build",
80
+ "@href": "/build/207345748",
81
+ "@representation": "minimal",
82
+ "id": 207345748,
83
+ "number": "824",
84
+ "state": "passed",
85
+ "duration": 498,
86
+ "event_type": "push",
87
+ "previous_state": null,
88
+ "pull_request_title": null,
89
+ "pull_request_number": null,
90
+ "started_at": "2017-03-03T12:49:48Z",
91
+ "finished_at": "2017-03-03T12:56:13Z"
92
+ }
93
+ },
94
+ {
95
+ "@type": "branch",
96
+ "@href": "/repo/409371/branch/ag-test-autologin",
97
+ "@representation": "standard",
98
+ "name": "ag-test-autologin",
99
+ "repository": {
100
+ "@type": "repository",
101
+ "@href": "/repo/409371",
102
+ "@representation": "minimal",
103
+ "id": 409371,
104
+ "name": "travis.rb",
105
+ "slug": "travis-ci/travis.rb"
106
+ },
107
+ "default_branch": false,
108
+ "exists_on_github": true,
109
+ "last_build": {
110
+ "@type": "build",
111
+ "@href": "/build/207337389",
112
+ "@representation": "minimal",
113
+ "id": 207337389,
114
+ "number": "821",
115
+ "state": "passed",
116
+ "duration": 531,
117
+ "event_type": "push",
118
+ "previous_state": "failed",
119
+ "pull_request_title": null,
120
+ "pull_request_number": null,
121
+ "started_at": "2017-03-03T12:09:38Z",
122
+ "finished_at": "2017-03-03T12:25:36Z"
123
+ }
124
+ },
125
+ {
126
+ "@type": "branch",
127
+ "@href": "/repo/409371/branch/rkh-2fa-login",
128
+ "@representation": "standard",
129
+ "name": "rkh-2fa-login",
130
+ "repository": {
131
+ "@type": "repository",
132
+ "@href": "/repo/409371",
133
+ "@representation": "minimal",
134
+ "id": 409371,
135
+ "name": "travis.rb",
136
+ "slug": "travis-ci/travis.rb"
137
+ },
138
+ "default_branch": false,
139
+ "exists_on_github": true,
140
+ "last_build": {
141
+ "@type": "build",
142
+ "@href": "/build/178040816",
143
+ "@representation": "minimal",
144
+ "id": 178040816,
145
+ "number": "792",
146
+ "state": "passed",
147
+ "duration": 655,
148
+ "event_type": "push",
149
+ "previous_state": "errored",
150
+ "pull_request_title": null,
151
+ "pull_request_number": null,
152
+ "started_at": "2016-11-22T17:17:50Z",
153
+ "finished_at": "2016-11-22T18:01:23Z"
154
+ }
155
+ },
156
+ {
157
+ "@type": "branch",
158
+ "@href": "/repo/409371/branch/cd-login",
159
+ "@representation": "standard",
160
+ "name": "cd-login",
161
+ "repository": {
162
+ "@type": "repository",
163
+ "@href": "/repo/409371",
164
+ "@representation": "minimal",
165
+ "id": 409371,
166
+ "name": "travis.rb",
167
+ "slug": "travis-ci/travis.rb"
168
+ },
169
+ "default_branch": false,
170
+ "exists_on_github": true,
171
+ "last_build": {
172
+ "@type": "build",
173
+ "@href": "/build/177697219",
174
+ "@representation": "minimal",
175
+ "id": 177697219,
176
+ "number": "786",
177
+ "state": "passed",
178
+ "duration": 562,
179
+ "event_type": "push",
180
+ "previous_state": "passed",
181
+ "pull_request_title": null,
182
+ "pull_request_number": null,
183
+ "started_at": "2016-11-21T16:11:41Z",
184
+ "finished_at": "2016-11-21T16:20:48Z"
185
+ }
186
+ },
187
+ {
188
+ "@type": "branch",
189
+ "@href": "/repo/409371/branch/debug",
190
+ "@representation": "standard",
191
+ "name": "debug",
192
+ "repository": {
193
+ "@type": "repository",
194
+ "@href": "/repo/409371",
195
+ "@representation": "minimal",
196
+ "id": 409371,
197
+ "name": "travis.rb",
198
+ "slug": "travis-ci/travis.rb"
199
+ },
200
+ "default_branch": false,
201
+ "exists_on_github": true,
202
+ "last_build": {
203
+ "@type": "build",
204
+ "@href": "/build/102107694",
205
+ "@representation": "minimal",
206
+ "id": 102107694,
207
+ "number": "726",
208
+ "state": "passed",
209
+ "duration": 343,
210
+ "event_type": "push",
211
+ "previous_state": null,
212
+ "pull_request_title": null,
213
+ "pull_request_number": null,
214
+ "started_at": "2016-01-13T14:15:11Z",
215
+ "finished_at": "2016-01-13T14:17:48Z"
216
+ }
217
+ },
218
+ {
219
+ "@type": "branch",
220
+ "@href": "/repo/409371/branch/db-fix-encrypt-repo-arg-detection",
221
+ "@representation": "standard",
222
+ "name": "db-fix-encrypt-repo-arg-detection",
223
+ "repository": {
224
+ "@type": "repository",
225
+ "@href": "/repo/409371",
226
+ "@representation": "minimal",
227
+ "id": 409371,
228
+ "name": "travis.rb",
229
+ "slug": "travis-ci/travis.rb"
230
+ },
231
+ "default_branch": false,
232
+ "exists_on_github": true,
233
+ "last_build": {
234
+ "@type": "build",
235
+ "@href": "/build/49090056",
236
+ "@representation": "minimal",
237
+ "id": 49090056,
238
+ "number": "666",
239
+ "state": "failed",
240
+ "duration": 349,
241
+ "event_type": "push",
242
+ "previous_state": null,
243
+ "pull_request_title": null,
244
+ "pull_request_number": null,
245
+ "started_at": "2015-02-01T15:54:33Z",
246
+ "finished_at": "2015-02-01T15:56:17Z"
247
+ }
248
+ },
249
+ {
250
+ "@type": "branch",
251
+ "@href": "/repo/409371/branch/rkh-heroku-special-token",
252
+ "@representation": "standard",
253
+ "name": "rkh-heroku-special-token",
254
+ "repository": {
255
+ "@type": "repository",
256
+ "@href": "/repo/409371",
257
+ "@representation": "minimal",
258
+ "id": 409371,
259
+ "name": "travis.rb",
260
+ "slug": "travis-ci/travis.rb"
261
+ },
262
+ "default_branch": false,
263
+ "exists_on_github": true,
264
+ "last_build": {
265
+ "@type": "build",
266
+ "@href": "/build/37817833",
267
+ "@representation": "minimal",
268
+ "id": 37817833,
269
+ "number": "648",
270
+ "state": "passed",
271
+ "duration": 431,
272
+ "event_type": "push",
273
+ "previous_state": null,
274
+ "pull_request_title": null,
275
+ "pull_request_number": null,
276
+ "started_at": "2014-10-13T12:02:10Z",
277
+ "finished_at": "2014-10-13T12:05:19Z"
278
+ }
279
+ },
280
+ {
281
+ "@type": "branch",
282
+ "@href": "/repo/409371/branch/ha-bug-deploy_problems",
283
+ "@representation": "standard",
284
+ "name": "ha-bug-deploy_problems",
285
+ "repository": {
286
+ "@type": "repository",
287
+ "@href": "/repo/409371",
288
+ "@representation": "minimal",
289
+ "id": 409371,
290
+ "name": "travis.rb",
291
+ "slug": "travis-ci/travis.rb"
292
+ },
293
+ "default_branch": false,
294
+ "exists_on_github": true,
295
+ "last_build": {
296
+ "@type": "build",
297
+ "@href": "/build/23672116",
298
+ "@representation": "minimal",
299
+ "id": 23672116,
300
+ "number": "497",
301
+ "state": "passed",
302
+ "duration": 1381,
303
+ "event_type": "push",
304
+ "previous_state": "errored",
305
+ "pull_request_title": null,
306
+ "pull_request_number": null,
307
+ "started_at": "2014-04-24T12:54:26Z",
308
+ "finished_at": "2014-04-24T13:00:37Z"
309
+ }
310
+ },
311
+ {
312
+ "@type": "branch",
313
+ "@href": "/repo/409371/branch/v1.8.8",
314
+ "@representation": "standard",
315
+ "name": "v1.8.8",
316
+ "repository": {
317
+ "@type": "repository",
318
+ "@href": "/repo/409371",
319
+ "@representation": "minimal",
320
+ "id": 409371,
321
+ "name": "travis.rb",
322
+ "slug": "travis-ci/travis.rb"
323
+ },
324
+ "default_branch": false,
325
+ "exists_on_github": false,
326
+ "last_build": {
327
+ "@type": "build",
328
+ "@href": "/build/207350503",
329
+ "@representation": "minimal",
330
+ "id": 207350503,
331
+ "number": "827",
332
+ "state": "passed",
333
+ "duration": 538,
334
+ "event_type": "push",
335
+ "previous_state": null,
336
+ "pull_request_title": null,
337
+ "pull_request_number": null,
338
+ "started_at": "2017-03-03T13:04:25Z",
339
+ "finished_at": "2017-03-03T13:19:38Z"
340
+ }
341
+ },
342
+ {
343
+ "@type": "branch",
344
+ "@href": "/repo/409371/branch/v1.8.6",
345
+ "@representation": "standard",
346
+ "name": "v1.8.6",
347
+ "repository": {
348
+ "@type": "repository",
349
+ "@href": "/repo/409371",
350
+ "@representation": "minimal",
351
+ "id": 409371,
352
+ "name": "travis.rb",
353
+ "slug": "travis-ci/travis.rb"
354
+ },
355
+ "default_branch": false,
356
+ "exists_on_github": false,
357
+ "last_build": {
358
+ "@type": "build",
359
+ "@href": "/build/195648126",
360
+ "@representation": "minimal",
361
+ "id": 195648126,
362
+ "number": "810",
363
+ "state": "passed",
364
+ "duration": 591,
365
+ "event_type": "push",
366
+ "previous_state": null,
367
+ "pull_request_title": null,
368
+ "pull_request_number": null,
369
+ "started_at": "2017-01-26T19:46:38Z",
370
+ "finished_at": "2017-01-26T22:59:01Z"
371
+ }
372
+ },
373
+ {
374
+ "@type": "branch",
375
+ "@href": "/repo/409371/branch/fix_report",
376
+ "@representation": "standard",
377
+ "name": "fix_report",
378
+ "repository": {
379
+ "@type": "repository",
380
+ "@href": "/repo/409371",
381
+ "@representation": "minimal",
382
+ "id": 409371,
383
+ "name": "travis.rb",
384
+ "slug": "travis-ci/travis.rb"
385
+ },
386
+ "default_branch": false,
387
+ "exists_on_github": false,
388
+ "last_build": {
389
+ "@type": "build",
390
+ "@href": "/build/194281685",
391
+ "@representation": "minimal",
392
+ "id": 194281685,
393
+ "number": "804",
394
+ "state": "passed",
395
+ "duration": 479,
396
+ "event_type": "push",
397
+ "previous_state": null,
398
+ "pull_request_title": null,
399
+ "pull_request_number": null,
400
+ "started_at": "2017-01-22T20:25:57Z",
401
+ "finished_at": "2017-01-22T20:29:06Z"
402
+ }
403
+ },
404
+ {
405
+ "@type": "branch",
406
+ "@href": "/repo/409371/branch/v1.8.5",
407
+ "@representation": "standard",
408
+ "name": "v1.8.5",
409
+ "repository": {
410
+ "@type": "repository",
411
+ "@href": "/repo/409371",
412
+ "@representation": "minimal",
413
+ "id": 409371,
414
+ "name": "travis.rb",
415
+ "slug": "travis-ci/travis.rb"
416
+ },
417
+ "default_branch": false,
418
+ "exists_on_github": false,
419
+ "last_build": {
420
+ "@type": "build",
421
+ "@href": "/build/182323691",
422
+ "@representation": "minimal",
423
+ "id": 182323691,
424
+ "number": "795",
425
+ "state": "passed",
426
+ "duration": 651,
427
+ "event_type": "push",
428
+ "previous_state": null,
429
+ "pull_request_title": null,
430
+ "pull_request_number": null,
431
+ "started_at": "2016-12-08T16:14:19Z",
432
+ "finished_at": "2016-12-08T16:45:18Z"
433
+ }
434
+ },
435
+ {
436
+ "@type": "branch",
437
+ "@href": "/repo/409371/branch/v1.8.4",
438
+ "@representation": "standard",
439
+ "name": "v1.8.4",
440
+ "repository": {
441
+ "@type": "repository",
442
+ "@href": "/repo/409371",
443
+ "@representation": "minimal",
444
+ "id": 409371,
445
+ "name": "travis.rb",
446
+ "slug": "travis-ci/travis.rb"
447
+ },
448
+ "default_branch": false,
449
+ "exists_on_github": false,
450
+ "last_build": {
451
+ "@type": "build",
452
+ "@href": "/build/174556256",
453
+ "@representation": "minimal",
454
+ "id": 174556256,
455
+ "number": "780",
456
+ "state": "passed",
457
+ "duration": 489,
458
+ "event_type": "push",
459
+ "previous_state": null,
460
+ "pull_request_title": null,
461
+ "pull_request_number": null,
462
+ "started_at": "2016-11-09T17:45:45Z",
463
+ "finished_at": "2016-11-09T18:09:30Z"
464
+ }
465
+ },
466
+ {
467
+ "@type": "branch",
468
+ "@href": "/repo/409371/branch/v1.8.3",
469
+ "@representation": "standard",
470
+ "name": "v1.8.3",
471
+ "repository": {
472
+ "@type": "repository",
473
+ "@href": "/repo/409371",
474
+ "@representation": "minimal",
475
+ "id": 409371,
476
+ "name": "travis.rb",
477
+ "slug": "travis-ci/travis.rb"
478
+ },
479
+ "default_branch": false,
480
+ "exists_on_github": false,
481
+ "last_build": {
482
+ "@type": "build",
483
+ "@href": "/build/174531237",
484
+ "@representation": "minimal",
485
+ "id": 174531237,
486
+ "number": "778",
487
+ "state": "passed",
488
+ "duration": 508,
489
+ "event_type": "push",
490
+ "previous_state": "errored",
491
+ "pull_request_title": null,
492
+ "pull_request_number": null,
493
+ "started_at": "2016-11-09T16:13:15Z",
494
+ "finished_at": "2016-11-09T16:30:28Z"
495
+ }
496
+ },
497
+ {
498
+ "@type": "branch",
499
+ "@href": "/repo/409371/branch/sec-incident-20161007",
500
+ "@representation": "standard",
501
+ "name": "sec-incident-20161007",
502
+ "repository": {
503
+ "@type": "repository",
504
+ "@href": "/repo/409371",
505
+ "@representation": "minimal",
506
+ "id": 409371,
507
+ "name": "travis.rb",
508
+ "slug": "travis-ci/travis.rb"
509
+ },
510
+ "default_branch": false,
511
+ "exists_on_github": false,
512
+ "last_build": {
513
+ "@type": "build",
514
+ "@href": "/build/166763571",
515
+ "@representation": "minimal",
516
+ "id": 166763571,
517
+ "number": "772",
518
+ "state": "passed",
519
+ "duration": 578,
520
+ "event_type": "push",
521
+ "previous_state": "errored",
522
+ "pull_request_title": null,
523
+ "pull_request_number": null,
524
+ "started_at": "2016-10-11T14:10:26Z",
525
+ "finished_at": "2016-10-11T14:15:30Z"
526
+ }
527
+ },
528
+ {
529
+ "@type": "branch",
530
+ "@href": "/repo/409371/branch/v1.8.2",
531
+ "@representation": "standard",
532
+ "name": "v1.8.2",
533
+ "repository": {
534
+ "@type": "repository",
535
+ "@href": "/repo/409371",
536
+ "@representation": "minimal",
537
+ "id": 409371,
538
+ "name": "travis.rb",
539
+ "slug": "travis-ci/travis.rb"
540
+ },
541
+ "default_branch": false,
542
+ "exists_on_github": false,
543
+ "last_build": {
544
+ "@type": "build",
545
+ "@href": "/build/101827353",
546
+ "@representation": "minimal",
547
+ "id": 101827353,
548
+ "number": "725",
549
+ "state": "passed",
550
+ "duration": 282,
551
+ "event_type": "push",
552
+ "previous_state": null,
553
+ "pull_request_title": null,
554
+ "pull_request_number": null,
555
+ "started_at": "2016-01-12T12:56:48Z",
556
+ "finished_at": "2016-01-12T12:57:22Z"
557
+ }
558
+ },
559
+ {
560
+ "@type": "branch",
561
+ "@href": "/repo/409371/branch/v1.8.1",
562
+ "@representation": "standard",
563
+ "name": "v1.8.1",
564
+ "repository": {
565
+ "@type": "repository",
566
+ "@href": "/repo/409371",
567
+ "@representation": "minimal",
568
+ "id": 409371,
569
+ "name": "travis.rb",
570
+ "slug": "travis-ci/travis.rb"
571
+ },
572
+ "default_branch": false,
573
+ "exists_on_github": false,
574
+ "last_build": {
575
+ "@type": "build",
576
+ "@href": "/build/101827328",
577
+ "@representation": "minimal",
578
+ "id": 101827328,
579
+ "number": "723",
580
+ "state": "passed",
581
+ "duration": 284,
582
+ "event_type": "push",
583
+ "previous_state": null,
584
+ "pull_request_title": null,
585
+ "pull_request_number": null,
586
+ "started_at": "2016-01-12T12:54:23Z",
587
+ "finished_at": "2016-01-12T12:55:07Z"
588
+ }
589
+ },
590
+ {
591
+ "@type": "branch",
592
+ "@href": "/repo/409371/branch/ha-feature-logger",
593
+ "@representation": "standard",
594
+ "name": "ha-feature-logger",
595
+ "repository": {
596
+ "@type": "repository",
597
+ "@href": "/repo/409371",
598
+ "@representation": "minimal",
599
+ "id": 409371,
600
+ "name": "travis.rb",
601
+ "slug": "travis-ci/travis.rb"
602
+ },
603
+ "default_branch": false,
604
+ "exists_on_github": false,
605
+ "last_build": {
606
+ "@type": "build",
607
+ "@href": "/build/101148156",
608
+ "@representation": "minimal",
609
+ "id": 101148156,
610
+ "number": "720",
611
+ "state": "passed",
612
+ "duration": 333,
613
+ "event_type": "push",
614
+ "previous_state": null,
615
+ "pull_request_title": null,
616
+ "pull_request_number": null,
617
+ "started_at": "2016-01-08T20:13:05Z",
618
+ "finished_at": "2016-01-08T20:13:57Z"
619
+ }
620
+ },
621
+ {
622
+ "@type": "branch",
623
+ "@href": "/repo/409371/branch/v1.8.0",
624
+ "@representation": "standard",
625
+ "name": "v1.8.0",
626
+ "repository": {
627
+ "@type": "repository",
628
+ "@href": "/repo/409371",
629
+ "@representation": "minimal",
630
+ "id": 409371,
631
+ "name": "travis.rb",
632
+ "slug": "travis-ci/travis.rb"
633
+ },
634
+ "default_branch": false,
635
+ "exists_on_github": false,
636
+ "last_build": {
637
+ "@type": "build",
638
+ "@href": "/build/71051560",
639
+ "@representation": "minimal",
640
+ "id": 71051560,
641
+ "number": "690",
642
+ "state": "passed",
643
+ "duration": 300,
644
+ "event_type": "push",
645
+ "previous_state": null,
646
+ "pull_request_title": null,
647
+ "pull_request_number": null,
648
+ "started_at": "2015-07-15T10:07:19Z",
649
+ "finished_at": "2015-07-15T10:09:45Z"
650
+ }
651
+ },
652
+ {
653
+ "@type": "branch",
654
+ "@href": "/repo/409371/branch/v1.7.7",
655
+ "@representation": "standard",
656
+ "name": "v1.7.7",
657
+ "repository": {
658
+ "@type": "repository",
659
+ "@href": "/repo/409371",
660
+ "@representation": "minimal",
661
+ "id": 409371,
662
+ "name": "travis.rb",
663
+ "slug": "travis-ci/travis.rb"
664
+ },
665
+ "default_branch": false,
666
+ "exists_on_github": false,
667
+ "last_build": {
668
+ "@type": "build",
669
+ "@href": "/build/64086905",
670
+ "@representation": "minimal",
671
+ "id": 64086905,
672
+ "number": "685",
673
+ "state": "passed",
674
+ "duration": 360,
675
+ "event_type": "push",
676
+ "previous_state": null,
677
+ "pull_request_title": null,
678
+ "pull_request_number": null,
679
+ "started_at": "2015-05-26T12:52:46Z",
680
+ "finished_at": "2015-05-26T12:54:55Z"
681
+ }
682
+ },
683
+ {
684
+ "@type": "branch",
685
+ "@href": "/repo/409371/branch/v1.7.6",
686
+ "@representation": "standard",
687
+ "name": "v1.7.6",
688
+ "repository": {
689
+ "@type": "repository",
690
+ "@href": "/repo/409371",
691
+ "@representation": "minimal",
692
+ "id": 409371,
693
+ "name": "travis.rb",
694
+ "slug": "travis-ci/travis.rb"
695
+ },
696
+ "default_branch": false,
697
+ "exists_on_github": false,
698
+ "last_build": {
699
+ "@type": "build",
700
+ "@href": "/build/57651617",
701
+ "@representation": "minimal",
702
+ "id": 57651617,
703
+ "number": "679",
704
+ "state": "passed",
705
+ "duration": 669,
706
+ "event_type": "push",
707
+ "previous_state": null,
708
+ "pull_request_title": null,
709
+ "pull_request_number": null,
710
+ "started_at": "2015-04-08T14:28:31Z",
711
+ "finished_at": "2015-04-08T14:34:03Z"
712
+ }
713
+ }
714
+ ]
715
+ }