buildkit 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +37 -0
- data/.rubocop_todo.yml +0 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +19 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/buildkit.gemspec +25 -0
- data/lib/buildkit/client/agents.rb +64 -0
- data/lib/buildkit/client/builds.rb +54 -0
- data/lib/buildkit/client/organizations.rb +29 -0
- data/lib/buildkit/client/projects.rb +30 -0
- data/lib/buildkit/client.rb +144 -0
- data/lib/buildkit/error.rb +166 -0
- data/lib/buildkit/response/raise_error.rb +19 -0
- data/lib/buildkit/version.rb +3 -0
- data/lib/buildkit.rb +8 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ffbda6ae8e3766f7b89a38105a771fa383425a60
|
4
|
+
data.tar.gz: a0b6b89b975d340521df2da08c3c9f2e04114786
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8ce9490791b9bb2e5d43e661f631c67388f971c70f7656b76294d8738f5b5fac1b6885ec228b83bf0171aa5a46e2d94661cf7845023094dc8314fbf2fa2cd7ac
|
7
|
+
data.tar.gz: 63711776362b51b3d4a571d8bd4e6b921b289f408ee33038ce95b9f257994af3cbbc23f0fb9a0499e7e693f1b217140cd845375da8e6a1ac4b199c5d3c266712
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
Metrics/LineLength:
|
4
|
+
Max: 120
|
5
|
+
|
6
|
+
Metrics/MethodLength:
|
7
|
+
Max: 25
|
8
|
+
|
9
|
+
Metrics/AbcSize:
|
10
|
+
Max: 30
|
11
|
+
|
12
|
+
Metrics/CyclomaticComplexity:
|
13
|
+
Max: 20
|
14
|
+
|
15
|
+
Metrics/PerceivedComplexity:
|
16
|
+
Max: 10
|
17
|
+
|
18
|
+
Style/GuardClause:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Style/SignalException:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Style/Documentation:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Lint/AssignmentInCondition:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
Style/PerlBackrefs:
|
31
|
+
Enabled: false
|
32
|
+
|
33
|
+
Style/SpaceInsideHashLiteralBraces:
|
34
|
+
EnforcedStyle: no_space
|
35
|
+
|
36
|
+
Style/TrailingComma:
|
37
|
+
EnforcedStyleForMultiline: comma
|
data/.rubocop_todo.yml
ADDED
File without changes
|
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'rake'
|
4
|
+
gem 'byebug'
|
5
|
+
gem 'rubocop'
|
6
|
+
gem 'yard'
|
7
|
+
|
8
|
+
group :test do
|
9
|
+
gem 'rspec', '~> 3.2'
|
10
|
+
gem 'vcr', '~> 2.9', github: 'vcr/vcr', branch: 'master', ref: '480304be6d73803e6c4a0eb21a4ab4091da558d8'
|
11
|
+
end
|
12
|
+
|
13
|
+
gemspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Shopify
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Buildkit
|
2
|
+
|
3
|
+
Ruby toolkit for the Buildkite API.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'buildkit'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
`Buildkit` follow the same patterns than [`Octokit`](https://github.com/octokit/octokit.rb), if you are familiar with it you should feel right at home.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
client = Buildkit.new(token: 't0k3n')
|
23
|
+
organization = client.organization('my-great-org')
|
24
|
+
agents = organization.rels[:agents].get.data
|
25
|
+
```
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
1. Fork it ( https://github.com/shopify/buildkit/fork )
|
36
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
39
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
require 'rubocop/rake_task'
|
7
|
+
RuboCop::RakeTask.new
|
8
|
+
|
9
|
+
task test: :spec
|
10
|
+
task default: [:spec, :rubocop]
|
11
|
+
|
12
|
+
namespace :doc do
|
13
|
+
require 'yard'
|
14
|
+
YARD::Rake::YardocTask.new do |task|
|
15
|
+
task.files = %w(LICENSE.md lib/**/*.rb)
|
16
|
+
task.options = %w(--output-dir doc/yard --markup markdown)
|
17
|
+
end
|
18
|
+
task default: :yard
|
19
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'buildkit'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/buildkit.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'buildkit/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'buildkit'
|
8
|
+
spec.version = Buildkit::VERSION
|
9
|
+
spec.authors = ['Jean Boussier']
|
10
|
+
spec.email = ['jean.boussier@shopify.com']
|
11
|
+
|
12
|
+
spec.summary = 'Ruby toolkit for working with the Buildkite API'
|
13
|
+
spec.homepage = 'https://github.com/shopify/buildkit'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = 'exe'
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 2.0'
|
22
|
+
|
23
|
+
spec.add_dependency 'sawyer', '~> 0.6.0'
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.9'
|
25
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Buildkit
|
2
|
+
class Client
|
3
|
+
# Methods for the Agents API
|
4
|
+
#
|
5
|
+
# @see https://buildkite.com/docs/api/agents
|
6
|
+
module Agents
|
7
|
+
# List agents
|
8
|
+
#
|
9
|
+
# @return [Array<Sawyer::Resource>] Array of hashes representing Buildkite agents.
|
10
|
+
# @see https://buildkite.com/docs/api/agents#list-agents
|
11
|
+
# @example
|
12
|
+
# Buildkit.agents('my-great-org')
|
13
|
+
def agents(org, options = {})
|
14
|
+
get("/v1/organizations/#{org}/agents", options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get an agent
|
18
|
+
#
|
19
|
+
# @param org [String] Organization slug.
|
20
|
+
# @param id [String] Agent id.
|
21
|
+
# @return [Sawyer::Resource] Hash representing Buildkite agent
|
22
|
+
# @see https://buildkite.com/docs/api/agents#get-an-agent
|
23
|
+
# @example
|
24
|
+
# Buildkit.agent('my-great-org', '0b461f65-e7be-4c80-888a-ef11d81fd971')
|
25
|
+
def agent(org, id, options = {})
|
26
|
+
get("/v1/organizations/#{org}/agents/#{id}", options)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Create an agent
|
30
|
+
#
|
31
|
+
# @param org [String] Organization slug.
|
32
|
+
# @param name [String] The name of the agent.
|
33
|
+
# @return [Sawyer::Resource] Your newly created agent
|
34
|
+
# @see https://buildkite.com/docs/api/agents#create-an-agent
|
35
|
+
# @example Create a new Agent for an organization
|
36
|
+
# Buildkit.create_agent('my-great-org', 'new-agent')
|
37
|
+
def create_agent(org, name, options = {})
|
38
|
+
post("/v1/organizations/#{org}/agents", options.merge(name: name))
|
39
|
+
end
|
40
|
+
|
41
|
+
# Delete an agent
|
42
|
+
#
|
43
|
+
# @param org [String] Organization slug.
|
44
|
+
# @param id [String] Agent id.
|
45
|
+
# @see https://buildkite.com/docs/api/agents#delete-an-agent
|
46
|
+
# @example Delete an existing agent
|
47
|
+
# Buildkit.delete_agent('my-great-org', '16940c91-f12d-4122-8154-0edf6c0978c2')
|
48
|
+
def delete_agent(org, id, options = {})
|
49
|
+
delete("/v1/organizations/#{org}/agents/#{id}", options)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Stop an agent
|
53
|
+
#
|
54
|
+
# @param org [String] Organization slug.
|
55
|
+
# @param id [String] Agent id.
|
56
|
+
# @see https://buildkite.com/docs/api/agents#stop-an-agent
|
57
|
+
# @example Stop an agent
|
58
|
+
# Buildkit.stop_agent('my-great-org', '16940c91-f12d-4122-8154-0edf6c0978c2')
|
59
|
+
def stop_agent(org, id, options = {})
|
60
|
+
put("/v1/organizations/#{org}/agents/#{id}/stop", options)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Buildkit
|
2
|
+
class Client
|
3
|
+
# Methods for the Builds API
|
4
|
+
#
|
5
|
+
# @see https://buildkite.com/docs/api/builds
|
6
|
+
module Builds
|
7
|
+
# List all builds
|
8
|
+
#
|
9
|
+
# @return [Array<Sawyer::Resource>] Array of hashes representing Buildkite builds.
|
10
|
+
# @see https://buildkite.com/docs/api/builds#list-all-builds
|
11
|
+
# @example
|
12
|
+
# Buildkit.builds
|
13
|
+
def builds(options = {})
|
14
|
+
get('/v1/builds', options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# List builds for an organization
|
18
|
+
#
|
19
|
+
# @param org [String] Organization slug.
|
20
|
+
# @return [Array<Sawyer::Resource>] Array of hashes representing Buildkite builds.
|
21
|
+
# @see https://buildkite.com/docs/api/builds#list-builds-for-an-organization
|
22
|
+
# @example
|
23
|
+
# Buildkit.organization_builds('my-great-org'))
|
24
|
+
def organization_builds(org, options = {})
|
25
|
+
get("/v1/organizations/#{org}/builds", options)
|
26
|
+
end
|
27
|
+
|
28
|
+
# List builds for a project
|
29
|
+
#
|
30
|
+
# @param org [String] Organization slug.
|
31
|
+
# @param project [String] Project slug.
|
32
|
+
# @return [Array<Sawyer::Resource>] Array of hashes representing Buildkite builds.
|
33
|
+
# @see https://buildkite.com/docs/api/builds#list-builds-for-a-project
|
34
|
+
# @example
|
35
|
+
# Buildkit.project_builds('my-great-org', 'great-project')
|
36
|
+
def project_builds(org, project, options = {})
|
37
|
+
get("/v1/organizations/#{org}/projects/#{project}/builds", options)
|
38
|
+
end
|
39
|
+
|
40
|
+
# List builds for a project
|
41
|
+
#
|
42
|
+
# @param org [String] Organization slug.
|
43
|
+
# @param project [String] Project slug.
|
44
|
+
# @param number [Integer] Build number.
|
45
|
+
# @return [Sawyer::Resource] Hash representing Buildkite build.
|
46
|
+
# @see https://buildkite.com/docs/api/builds#get-a-build
|
47
|
+
# @example
|
48
|
+
# Buildkit.project_builds('my-great-org', 'great-project', 42)
|
49
|
+
def build(org, project, number, options = {})
|
50
|
+
get("/v1/organizations/#{org}/projects/#{project}/builds/#{number}", options)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Buildkit
|
2
|
+
class Client
|
3
|
+
# Methods for the Organizations API
|
4
|
+
#
|
5
|
+
# @see https://buildkite.com/docs/api/organizations
|
6
|
+
module Organizations
|
7
|
+
# List organizations
|
8
|
+
#
|
9
|
+
# @return [Array<Sawyer::Resource>] Array of hashes representing Buildkite organizations.
|
10
|
+
# @see https://buildkite.com/docs/api/organizations#list-organizations
|
11
|
+
# @example
|
12
|
+
# Buildkit.organizations
|
13
|
+
def organizations(options = {})
|
14
|
+
get('/v1/organizations', options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get an organization
|
18
|
+
#
|
19
|
+
# @param org [String] Organization slug.
|
20
|
+
# @return [Sawyer::Resource] Hash representing Buildkite organization.
|
21
|
+
# @see https://buildkite.com/docs/api/organizations#get-an-organization
|
22
|
+
# @example
|
23
|
+
# Buildkit.organization('my-great-org')
|
24
|
+
def organization(org, options = {})
|
25
|
+
get("/v1/organizations/#{org}", options)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Buildkit
|
2
|
+
class Client
|
3
|
+
# Methods for the Projects API
|
4
|
+
#
|
5
|
+
# @see https://buildkite.com/docs/api/projects
|
6
|
+
module Projects
|
7
|
+
# List projects
|
8
|
+
#
|
9
|
+
# @return [Array<Sawyer::Resource>] Array of hashes representing Buildkite projects.
|
10
|
+
# @see https://buildkite.com/docs/api/projects#list-projects
|
11
|
+
# @example
|
12
|
+
# Buildkit.projects('my-great-org')
|
13
|
+
def projects(org, options = {})
|
14
|
+
get("/v1/organizations/#{org}/projects", options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get a project
|
18
|
+
#
|
19
|
+
# @param org [String] Organization slug.
|
20
|
+
# @param project [String] Project slug.
|
21
|
+
# @return [Sawyer::Resource] Hash representing Buildkite project
|
22
|
+
# @see https://buildkite.com/docs/api/projects#get-a-project
|
23
|
+
# @example
|
24
|
+
# Buildkit.project('my-great-org', 'great-project')
|
25
|
+
def project(org, project, options = {})
|
26
|
+
get("/v1/organizations/#{org}/projects/#{project}", options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'sawyer'
|
2
|
+
require 'buildkit/client/agents'
|
3
|
+
require 'buildkit/client/builds'
|
4
|
+
require 'buildkit/client/organizations'
|
5
|
+
require 'buildkit/client/projects'
|
6
|
+
require 'buildkit/response/raise_error'
|
7
|
+
|
8
|
+
module Buildkit
|
9
|
+
class Client
|
10
|
+
include Agents
|
11
|
+
include Builds
|
12
|
+
include Organizations
|
13
|
+
include Projects
|
14
|
+
|
15
|
+
# Header keys that can be passed in options hash to {#get},{#head}
|
16
|
+
CONVENIENCE_HEADERS = Set.new([:accept, :content_type])
|
17
|
+
|
18
|
+
# In Faraday 0.9, Faraday::Builder was renamed to Faraday::RackBuilder
|
19
|
+
RACK_BUILDER_CLASS = defined?(Faraday::RackBuilder) ? Faraday::RackBuilder : Faraday::Builder
|
20
|
+
|
21
|
+
# Default Faraday middleware stack
|
22
|
+
MIDDLEWARE = RACK_BUILDER_CLASS.new do |builder|
|
23
|
+
builder.use Buildkit::Response::RaiseError
|
24
|
+
builder.adapter Faraday.default_adapter
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(token:)
|
28
|
+
@token = token
|
29
|
+
end
|
30
|
+
|
31
|
+
# Make a HTTP GET request
|
32
|
+
#
|
33
|
+
# @param url [String] The path, relative to {#api_endpoint}
|
34
|
+
# @param options [Hash] Query and header params for request
|
35
|
+
# @return [Sawyer::Resource]
|
36
|
+
def get(url, options = {})
|
37
|
+
request :get, url, parse_query_and_convenience_headers(options)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Make a HTTP POST request
|
41
|
+
#
|
42
|
+
# @param url [String] The path, relative to {#api_endpoint}
|
43
|
+
# @param options [Hash] Body and header params for request
|
44
|
+
# @return [Sawyer::Resource]
|
45
|
+
def post(url, options = {})
|
46
|
+
request :post, url, options
|
47
|
+
end
|
48
|
+
|
49
|
+
# Make a HTTP PUT request
|
50
|
+
#
|
51
|
+
# @param url [String] The path, relative to {#api_endpoint}
|
52
|
+
# @param options [Hash] Body and header params for request
|
53
|
+
# @return [Sawyer::Resource]
|
54
|
+
def put(url, options = {})
|
55
|
+
request :put, url, options
|
56
|
+
end
|
57
|
+
|
58
|
+
# Make a HTTP PATCH request
|
59
|
+
#
|
60
|
+
# @param url [String] The path, relative to {#api_endpoint}
|
61
|
+
# @param options [Hash] Body and header params for request
|
62
|
+
# @return [Sawyer::Resource]
|
63
|
+
def patch(url, options = {})
|
64
|
+
request :patch, url, options
|
65
|
+
end
|
66
|
+
|
67
|
+
# Make a HTTP DELETE request
|
68
|
+
#
|
69
|
+
# @param url [String] The path, relative to {#api_endpoint}
|
70
|
+
# @param options [Hash] Query and header params for request
|
71
|
+
# @return [Sawyer::Resource]
|
72
|
+
def delete(url, options = {})
|
73
|
+
request :delete, url, options
|
74
|
+
end
|
75
|
+
|
76
|
+
# Make a HTTP HEAD request
|
77
|
+
#
|
78
|
+
# @param url [String] The path, relative to {#api_endpoint}
|
79
|
+
# @param options [Hash] Query and header params for request
|
80
|
+
# @return [Sawyer::Resource]
|
81
|
+
def head(url, options = {})
|
82
|
+
request :head, url, parse_query_and_convenience_headers(options)
|
83
|
+
end
|
84
|
+
|
85
|
+
attr_reader :last_response
|
86
|
+
|
87
|
+
# Fetch the root resource for the API
|
88
|
+
#
|
89
|
+
# @return [Sawyer::Resource]
|
90
|
+
def root
|
91
|
+
get('/')
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def request(method, path, data, options = {})
|
97
|
+
if data.is_a?(Hash)
|
98
|
+
options[:query] = data.delete(:query) || {}
|
99
|
+
options[:headers] = data.delete(:headers) || {}
|
100
|
+
if accept = data.delete(:accept)
|
101
|
+
options[:headers][:accept] = accept
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@last_response = response = sawyer_agent.call(method, URI::Parser.new.escape(path.to_s), data, options)
|
106
|
+
response.data
|
107
|
+
end
|
108
|
+
|
109
|
+
def sawyer_agent
|
110
|
+
@agent ||= Sawyer::Agent.new(api_endpoint, sawyer_options) do |http|
|
111
|
+
http.headers[:accept] = 'application/json'
|
112
|
+
http.headers[:content_type] = 'application/json'
|
113
|
+
http.headers[:user_agent] = "Buildkit v#{Buildkit::VERSION}"
|
114
|
+
http.authorization 'Bearer', @token
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def sawyer_options
|
119
|
+
{
|
120
|
+
links_parser: Sawyer::LinkParsers::Simple.new,
|
121
|
+
faraday: Faraday.new(builder: MIDDLEWARE),
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def api_endpoint
|
126
|
+
'https://api.buildkite.com/v1/'
|
127
|
+
end
|
128
|
+
|
129
|
+
def parse_query_and_convenience_headers(options)
|
130
|
+
headers = options.fetch(:headers, {})
|
131
|
+
CONVENIENCE_HEADERS.each do |h|
|
132
|
+
if header = options.delete(h)
|
133
|
+
headers[h] = header
|
134
|
+
end
|
135
|
+
end
|
136
|
+
query = options.delete(:query)
|
137
|
+
opts = {query: options}
|
138
|
+
opts[:query].merge!(query) if query && query.is_a?(Hash)
|
139
|
+
opts[:headers] = headers unless headers.empty?
|
140
|
+
|
141
|
+
opts
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Buildkit
|
2
|
+
# Custom error class for rescuing from all Buildkite errors
|
3
|
+
class Error < StandardError
|
4
|
+
# Returns the appropriate Buildkit::Error subclass based
|
5
|
+
# on status and response message
|
6
|
+
#
|
7
|
+
# @param [Hash] response HTTP response
|
8
|
+
# @return [Buildkit::Error]
|
9
|
+
def self.from_response(response)
|
10
|
+
status = response[:status].to_i
|
11
|
+
if klass = case status
|
12
|
+
when 400 then Buildkit::BadRequest
|
13
|
+
when 401 then Buildkit::Unauthorized
|
14
|
+
when 403 then Buildkit::Forbidden
|
15
|
+
when 404 then Buildkit::NotFound
|
16
|
+
when 405 then Buildkit::MethodNotAllowed
|
17
|
+
when 406 then Buildkit::NotAcceptable
|
18
|
+
when 409 then Buildkit::Conflict
|
19
|
+
when 415 then Buildkit::UnsupportedMediaType
|
20
|
+
when 422 then Buildkit::UnprocessableEntity
|
21
|
+
when 400..499 then Buildkit::ClientError
|
22
|
+
when 500 then Buildkit::InternalServerError
|
23
|
+
when 501 then Buildkit::NotImplemented
|
24
|
+
when 502 then Buildkit::BadGateway
|
25
|
+
when 503 then Buildkit::ServiceUnavailable
|
26
|
+
when 500..599 then Buildkit::ServerError
|
27
|
+
end
|
28
|
+
klass.new(response)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(response = nil)
|
33
|
+
@response = response
|
34
|
+
super(build_error_message)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Documentation URL returned by the API for some errors
|
38
|
+
#
|
39
|
+
# @return [String]
|
40
|
+
def documentation_url
|
41
|
+
data[:documentation_url] if data.is_a? Hash
|
42
|
+
end
|
43
|
+
|
44
|
+
# Array of validation errors
|
45
|
+
# @return [Array<Hash>] Error info
|
46
|
+
def errors
|
47
|
+
if data && data.is_a?(Hash)
|
48
|
+
data[:errors] || []
|
49
|
+
else
|
50
|
+
[]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def data
|
57
|
+
@data ||= parse_data
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_data
|
61
|
+
body = @response[:body]
|
62
|
+
return if body.empty?
|
63
|
+
return body unless body.is_a?(String)
|
64
|
+
|
65
|
+
headers = @response[:response_headers]
|
66
|
+
content_type = headers && headers[:content_type] || ''
|
67
|
+
if content_type =~ /json/
|
68
|
+
Sawyer::Agent.serializer.decode(body)
|
69
|
+
else
|
70
|
+
body
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def response_message
|
75
|
+
case data
|
76
|
+
when Hash
|
77
|
+
data[:message]
|
78
|
+
when String
|
79
|
+
data
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def response_error
|
84
|
+
"Error: #{data[:error]}" if data.is_a?(Hash) && data[:error]
|
85
|
+
end
|
86
|
+
|
87
|
+
def response_error_summary
|
88
|
+
return nil unless data.is_a?(Hash) && !Array(data[:errors]).empty?
|
89
|
+
|
90
|
+
summary = "\nError summary:\n"
|
91
|
+
summary << data[:errors].map do |hash|
|
92
|
+
hash.map { |k, v| " #{k}: #{v}" }
|
93
|
+
end.join("\n")
|
94
|
+
|
95
|
+
summary
|
96
|
+
end
|
97
|
+
|
98
|
+
def build_error_message
|
99
|
+
return nil if @response.nil?
|
100
|
+
|
101
|
+
message = "#{@response[:method].to_s.upcase} "
|
102
|
+
message << redact_url(@response[:url].to_s) + ': '
|
103
|
+
message << "#{@response[:status]} - "
|
104
|
+
message << "#{response_message}" unless response_message.nil?
|
105
|
+
message << "#{response_error}" unless response_error.nil?
|
106
|
+
message << "#{response_error_summary}" unless response_error_summary.nil?
|
107
|
+
message << " // See: #{documentation_url}" unless documentation_url.nil?
|
108
|
+
message
|
109
|
+
end
|
110
|
+
|
111
|
+
def redact_url(url_string)
|
112
|
+
%w(client_secret access_token).each do |token|
|
113
|
+
url_string.gsub!(/#{token}=\S+/, "#{token}=(redacted)") if url_string.include? token
|
114
|
+
end
|
115
|
+
url_string
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Raised on errors in the 400-499 range
|
120
|
+
class ClientError < Error; end
|
121
|
+
|
122
|
+
# Raised when Buildkite returns a 400 HTTP status code
|
123
|
+
class BadRequest < ClientError; end
|
124
|
+
|
125
|
+
# Raised when Buildkite returns a 401 HTTP status code
|
126
|
+
class Unauthorized < ClientError; end
|
127
|
+
|
128
|
+
# Raised when Buildkite returns a 403 HTTP status code
|
129
|
+
class Forbidden < ClientError; end
|
130
|
+
|
131
|
+
# Raised when Buildkite returns a 404 HTTP status code
|
132
|
+
class NotFound < ClientError; end
|
133
|
+
|
134
|
+
# Raised when Buildkite returns a 405 HTTP status code
|
135
|
+
class MethodNotAllowed < ClientError; end
|
136
|
+
|
137
|
+
# Raised when Buildkite returns a 406 HTTP status code
|
138
|
+
class NotAcceptable < ClientError; end
|
139
|
+
|
140
|
+
# Raised when Buildkite returns a 409 HTTP status code
|
141
|
+
class Conflict < ClientError; end
|
142
|
+
|
143
|
+
# Raised when Buildkite returns a 414 HTTP status code
|
144
|
+
class UnsupportedMediaType < ClientError; end
|
145
|
+
|
146
|
+
# Raised when Buildkite returns a 422 HTTP status code
|
147
|
+
class UnprocessableEntity < ClientError; end
|
148
|
+
|
149
|
+
# Raised on errors in the 500-599 range
|
150
|
+
class ServerError < Error; end
|
151
|
+
|
152
|
+
# Raised when Buildkite returns a 500 HTTP status code
|
153
|
+
class InternalServerError < ServerError; end
|
154
|
+
|
155
|
+
# Raised when Buildkite returns a 501 HTTP status code
|
156
|
+
class NotImplemented < ServerError; end
|
157
|
+
|
158
|
+
# Raised when Buildkite returns a 502 HTTP status code
|
159
|
+
class BadGateway < ServerError; end
|
160
|
+
|
161
|
+
# Raised when Buildkite returns a 503 HTTP status code
|
162
|
+
class ServiceUnavailable < ServerError; end
|
163
|
+
|
164
|
+
# Raised when client fails to provide valid Content-Type
|
165
|
+
class MissingContentType < ArgumentError; end
|
166
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'buildkit/error'
|
3
|
+
|
4
|
+
module Buildkit
|
5
|
+
# Faraday response middleware
|
6
|
+
module Response
|
7
|
+
# This class raises an Buildkit-flavored exception based
|
8
|
+
# HTTP status codes returned by the API
|
9
|
+
class RaiseError < Faraday::Response::Middleware
|
10
|
+
private
|
11
|
+
|
12
|
+
def on_complete(response)
|
13
|
+
if error = Buildkit::Error.from_response(response)
|
14
|
+
raise error
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/buildkit.rb
ADDED
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: buildkit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jean Boussier
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sawyer
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.6.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.6.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.9'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.9'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- jean.boussier@shopify.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- ".rspec"
|
50
|
+
- ".rubocop.yml"
|
51
|
+
- ".rubocop_todo.yml"
|
52
|
+
- Gemfile
|
53
|
+
- LICENSE.txt
|
54
|
+
- README.md
|
55
|
+
- Rakefile
|
56
|
+
- bin/console
|
57
|
+
- bin/setup
|
58
|
+
- buildkit.gemspec
|
59
|
+
- lib/buildkit.rb
|
60
|
+
- lib/buildkit/client.rb
|
61
|
+
- lib/buildkit/client/agents.rb
|
62
|
+
- lib/buildkit/client/builds.rb
|
63
|
+
- lib/buildkit/client/organizations.rb
|
64
|
+
- lib/buildkit/client/projects.rb
|
65
|
+
- lib/buildkit/error.rb
|
66
|
+
- lib/buildkit/response/raise_error.rb
|
67
|
+
- lib/buildkit/version.rb
|
68
|
+
homepage: https://github.com/shopify/buildkit
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '2.0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.4.6
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: Ruby toolkit for working with the Buildkite API
|
92
|
+
test_files: []
|
93
|
+
has_rdoc:
|