droplet_kit 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 2ec217312a19e55394c76f6f02a4e59b59525f0767405ea2e42fd5f24f5e09b8
4
- data.tar.gz: 7c0d074571a6531486ae81dd7fc8f30a020bf60bc824a266a8f2701813f4539c
2
+ SHA1:
3
+ metadata.gz: 2c4785840d709bf0fb77376b1a0bde83177bf180
4
+ data.tar.gz: bd3c1da28e541f47c2f701fed55730a618e99af9
5
5
  SHA512:
6
- metadata.gz: 1e7c4295594d705170819ced2305c2f92e20c2d497db5782c9aad227a055d2b72f910da9c84993f911dc02547a39115406a59aa359dfae489d7f1b2cc156b6e9
7
- data.tar.gz: 9148f78a78f2dbef212fd71166feaa97d5a33fe4c46678529cd70593d1130f7810e00d650a5d860c1fbc31dec4dac050221bb735e9bed95f6db0e750273db7eb
6
+ metadata.gz: e5ec1fa13b657d29485822b0b4171a39f774398bf89722bfdcf4e81db0afbf01611b689feab1f802508029715bbe4b1df0534aedbcfefa05cd1ff049dce432fd
7
+ data.tar.gz: 7db985a236a9066c49fe5403418ed0f79cc7016389320e9cb6e851ebd85dd66d5422949b5f06cf7db172d9edfab07d9b016d773ad1f9ef53bb29be8753dd47d6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ### Version 2.6.0
2
+ * Added ability to manage projects.
3
+
1
4
  ### Version 2.5.0
2
5
  * Added ability to tag images and retrieving new fields for tagged resources.
3
6
 
data/README.md CHANGED
@@ -346,6 +346,24 @@ Actions supported:
346
346
  * `client.ssh_keys.delete(id: 'id')`
347
347
  * `client.ssh_keys.update(ssh_key, id: 'id')`
348
348
 
349
+ ## Project resource
350
+
351
+ ```ruby
352
+ client = DropletKit::Client.new(access_token: 'TOKEN')
353
+ client.projects #=> DropletKit::ProjectResource
354
+ ```
355
+
356
+ Actions supported:
357
+
358
+ * `client.projects.all()`
359
+ * `client.projects.find(id: 'id')`
360
+ * `client.projects.find_default` is equivalent to `client.projects.find(id: DropletKit::Project::DEFAULT)`
361
+ * `client.projects.create(DropletKit::Project.new(name: 'name', purpose: 'Service or API'))`
362
+ * `client.projects.update(project, id: 'id')`
363
+ * `client.projects.delete(id: 'id')`
364
+ * `client.projects.list_resources(id: 'id')`
365
+ * `client.projects.assign_resources([DropletKit::Droplet.new(id: 123), "do:space:myspace.com"], id: 'id')`
366
+
349
367
  ## Tag resource
350
368
 
351
369
  ```ruby
data/lib/droplet_kit.rb CHANGED
@@ -24,6 +24,9 @@ module DropletKit
24
24
  autoload :Account, 'droplet_kit/models/account'
25
25
  autoload :DropletUpgrade, 'droplet_kit/models/droplet_upgrade'
26
26
  autoload :FloatingIp, 'droplet_kit/models/floating_ip'
27
+ autoload :Project, 'droplet_kit/models/project'
28
+ autoload :ProjectAssignment, 'droplet_kit/models/project_assignment'
29
+ autoload :Links, 'droplet_kit/models/links'
27
30
  autoload :Tag, 'droplet_kit/models/tag'
28
31
  autoload :TaggedResources, 'droplet_kit/models/tagged_resources'
29
32
  autoload :TaggedDropletsResources, 'droplet_kit/models/tagged_droplets_resources'
@@ -56,6 +59,7 @@ module DropletKit
56
59
  autoload :DropletUpgradeResource, 'droplet_kit/resources/droplet_upgrade_resource'
57
60
  autoload :FloatingIpResource, 'droplet_kit/resources/floating_ip_resource'
58
61
  autoload :FloatingIpActionResource, 'droplet_kit/resources/floating_ip_action_resource'
62
+ autoload :ProjectResource, 'droplet_kit/resources/project_resource'
59
63
  autoload :TagResource, 'droplet_kit/resources/tag_resource'
60
64
  autoload :VolumeResource, 'droplet_kit/resources/volume_resource'
61
65
  autoload :VolumeActionResource, 'droplet_kit/resources/volume_action_resource'
@@ -83,6 +87,9 @@ module DropletKit
83
87
  autoload :AccountMapping, 'droplet_kit/mappings/account_mapping'
84
88
  autoload :DropletUpgradeMapping, 'droplet_kit/mappings/droplet_upgrade_mapping'
85
89
  autoload :FloatingIpMapping, 'droplet_kit/mappings/floating_ip_mapping'
90
+ autoload :ProjectMapping, 'droplet_kit/mappings/project_mapping'
91
+ autoload :ProjectAssignmentMapping, 'droplet_kit/mappings/project_assignment_mapping'
92
+ autoload :LinksMapping, 'droplet_kit/mappings/links_mapping'
86
93
  autoload :TagMapping, 'droplet_kit/mappings/tag_mapping'
87
94
  autoload :TaggedResourcesMapping, 'droplet_kit/mappings/tagged_resources_mapping'
88
95
  autoload :TaggedDropletsResourcesMapping, 'droplet_kit/mappings/tagged_droplets_resources_mapping'
@@ -109,6 +116,7 @@ module DropletKit
109
116
  Error = Class.new(StandardError)
110
117
  FailedCreate = Class.new(DropletKit::Error)
111
118
  FailedUpdate = Class.new(DropletKit::Error)
119
+ FailedDelete = Class.new(DropletKit::Error)
112
120
 
113
121
  class RateLimitReached < DropletKit::Error
114
122
  attr_accessor :reset_at
@@ -37,6 +37,7 @@ module DropletKit
37
37
  floating_ips: FloatingIpResource,
38
38
  floating_ip_actions: FloatingIpActionResource,
39
39
  tags: TagResource,
40
+ projects: ProjectResource,
40
41
  volumes: VolumeResource,
41
42
  volume_actions: VolumeActionResource
42
43
  }
@@ -0,0 +1,16 @@
1
+ module DropletKit
2
+ class LinksMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping Links
7
+ root_key plural: 'links', singular: 'links', scopes: [:read]
8
+
9
+ property :myself, key: 'self', scopes: [:read]
10
+ property :first, scopes: [:read]
11
+ property :prev, scopes: [:read]
12
+ property :next, scopes: [:read]
13
+ property :last, scopes: [:read]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module DropletKit
2
+ class ProjectAssignmentMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping ProjectAssignment
7
+ root_key plural: 'resources', singular: 'resource', scopes: [:read]
8
+
9
+ property :urn, scopes: [:read, :create]
10
+ property :assigned_at, scopes: [:read]
11
+
12
+ property :links, scopes: [:read] do
13
+ mapping Links
14
+ property :myself, key: 'self', scopes: [:read]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ module DropletKit
2
+ class ProjectMapping
3
+ include Kartograph::DSL
4
+
5
+ kartograph do
6
+ mapping Project
7
+ root_key plural: 'projects', singular: 'project', scopes: [:read]
8
+
9
+ property :id, scopes: [:read]
10
+ property :owner_uuid, scopes: [:read]
11
+ property :owner_id, scopes: [:read]
12
+
13
+ property :name, scopes: [:read, :create, :update]
14
+ property :description, scopes: [:read, :create, :update]
15
+ property :purpose, scopes: [:read, :create, :update]
16
+ property :environment, scopes: [:read, :create, :update]
17
+ property :is_default, scopes: [:read, :create, :update]
18
+
19
+ property :created_at, scopes: [:read]
20
+ property :updated_at, scopes: [:read]
21
+ end
22
+ end
23
+ end
@@ -2,6 +2,9 @@ require 'virtus'
2
2
 
3
3
  module DropletKit
4
4
  class BaseModel
5
+ DO_NAMESPACE = 'do'
6
+ UNSUPPORTED_COLLECTIONS = ['space']
7
+
5
8
  include Virtus.model
6
9
  include Virtus::Equalizer.new(name || inspect)
7
10
 
@@ -9,5 +12,53 @@ module DropletKit
9
12
  values = Hash[instance_variables.map { |name| [name, instance_variable_get(name)] } ]
10
13
  "<#{self.class.name} #{values}>"
11
14
  end
15
+
16
+ def urn
17
+ "#{DO_NAMESPACE}:#{collection_name}:#{identifier}"
18
+ end
19
+
20
+ def collection_name
21
+ self.class.name.split('::').last.underscore
22
+ end
23
+
24
+ def identifier
25
+ identifier = attributes[:id] || attributes[:uuid] || attributes[:slug]
26
+ raise DropletKit::Error.new("#{self.class.name} doesn't support URNs") if identifier.nil?
27
+
28
+ identifier
29
+ end
30
+
31
+ def self.valid_urn?(urn)
32
+ parts = urn.split(':')
33
+ return false if parts.size != 3 || parts[0] != DO_NAMESPACE
34
+
35
+ collection = parts[1]
36
+ return true if UNSUPPORTED_COLLECTIONS.include?(collection)
37
+
38
+ begin
39
+ "DropletKit::#{collection.camelize}".constantize
40
+ rescue NameError
41
+ return false
42
+ end
43
+
44
+ true
45
+ end
46
+
47
+ def self.from_urn(urn)
48
+ DropletKit::Error.new("Invalid urn: #{urn}") unless valid_urn?(urn)
49
+
50
+ parts = urn.split(':')
51
+ collection = parts[1]
52
+ identifier = parts[2]
53
+
54
+ return nil if UNSUPPORTED_COLLECTIONS.include?(collection)
55
+
56
+ klass = "DropletKit::#{collection.camelize}".constantize
57
+ klass.from_identifier(identifier)
58
+ end
59
+
60
+ def self.from_identifier(identifier)
61
+ new(id: identifier)
62
+ end
12
63
  end
13
64
  end
@@ -6,5 +6,13 @@ module DropletKit
6
6
 
7
7
  # Used for creates
8
8
  attribute :ip_address
9
+
10
+ def identifier
11
+ name
12
+ end
13
+
14
+ def self.from_identifier(identifier)
15
+ new(name: identifier)
16
+ end
9
17
  end
10
18
  end
@@ -6,5 +6,13 @@ module DropletKit
6
6
 
7
7
  # Used for creates
8
8
  attribute :droplet_id
9
+
10
+ def identifier
11
+ ip
12
+ end
13
+
14
+ def self.from_identifier(identifier)
15
+ new(ip: identifier)
16
+ end
9
17
  end
10
18
  end
@@ -0,0 +1,9 @@
1
+ module DropletKit
2
+ class Links < BaseModel
3
+ attribute :myself
4
+ attribute :first
5
+ attribute :next
6
+ attribute :prev
7
+ attribute :last
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ module DropletKit
2
+ class Project < BaseModel
3
+ DEFAULT = 'default'.freeze
4
+
5
+ attribute :id
6
+ attribute :owner_uuid
7
+ attribute :owner_id
8
+ attribute :name
9
+ attribute :description
10
+ attribute :purpose
11
+ attribute :environment
12
+ attribute :is_default
13
+ attribute :created_at
14
+ attribute :updated_at
15
+
16
+ def self.from_identifier(identifier)
17
+ new(uuid: identifier)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ module DropletKit
2
+ class ProjectAssignment < BaseModel
3
+ attribute :urn
4
+ attribute :assigned_at
5
+ attribute :links
6
+
7
+ def self_link
8
+ links.try(:myself)
9
+ end
10
+
11
+ def to_model
12
+ BaseModel.from_urn(urn)
13
+ end
14
+ end
15
+ end
@@ -6,4 +6,8 @@ module DropletKit
6
6
  attribute :available
7
7
  attribute :features
8
8
  end
9
+
10
+ def self.from_identifier(identifier)
11
+ new(slug: identifier)
12
+ end
9
13
  end
@@ -10,4 +10,8 @@ module DropletKit
10
10
  attribute :regions
11
11
  attribute :available
12
12
  end
13
+
14
+ def self.from_identifier(identifier)
15
+ new(slug: identifier)
16
+ end
13
17
  end
@@ -2,5 +2,13 @@ module DropletKit
2
2
  class Tag < BaseModel
3
3
  attribute :name
4
4
  attribute :resources
5
+
6
+ def identifier
7
+ name
8
+ end
9
+
10
+ def self.from_identifier(identifier)
11
+ new(name: identifier)
12
+ end
5
13
  end
6
14
  end
@@ -0,0 +1,65 @@
1
+ module DropletKit
2
+ class ProjectResource < ResourceKit::Resource
3
+ include ErrorHandlingResourcable
4
+
5
+ resources do
6
+ action :all, 'GET /v2/projects' do
7
+ query_keys :per_page, :page
8
+ handler(200) { |response| ProjectMapping.extract_collection(response.body, :read) }
9
+ end
10
+
11
+ action :find_default, 'GET /v2/projects/default' do
12
+ handler(200) { |response| ProjectMapping.extract_single(response.body, :read) }
13
+ end
14
+
15
+ action :find, 'GET /v2/projects/:id' do
16
+ handler(200) { |response| ProjectMapping.extract_single(response.body, :read) }
17
+ end
18
+
19
+ action :create, 'POST /v2/projects' do
20
+ body { |project| ProjectMapping.representation_for(:create, project) }
21
+ handler(201) { |response| ProjectMapping.extract_single(response.body, :read) }
22
+ handler(422) { |response| ErrorMapping.fail_with(FailedCreate, response.body) }
23
+ end
24
+
25
+ action :update, 'PUT /v2/projects/:id' do
26
+ body { |project| ProjectMapping.representation_for(:update, project) }
27
+ handler(200) { |response| ProjectMapping.extract_single(response.body, :read) }
28
+ handler(422) { |response| ErrorMapping.fail_with(FailedUpdate, response.body) }
29
+ end
30
+
31
+ action :delete, 'DELETE /v2/projects/:id' do
32
+ handler(204) { |_| true }
33
+ handler(422) { |response| ErrorMapping.fail_with(FailedDelete, response.body) }
34
+ end
35
+
36
+ action :list_resources, 'GET /v2/projects/:id/resources' do
37
+ handler(200) { |response| ProjectAssignmentMapping.extract_collection(response.body, :read) }
38
+ end
39
+
40
+ action :assign_resources, 'POST /v2/projects/:id/resources' do
41
+ verb :post
42
+ body do |resources|
43
+ { resources: to_urn(resources).compact }.to_json
44
+ end
45
+ handler(200) { |response| ProjectAssignmentMapping.extract_collection(response.body, :read) }
46
+
47
+ def to_urn(resources)
48
+ resources.to_a.map do |resource|
49
+ if resource.is_a?(String) && DropletKit::BaseModel.valid_urn?(resource)
50
+ resource
51
+ elsif resource.try(:urn) && DropletKit::BaseModel.valid_urn?(resource.urn)
52
+ resource.urn
53
+ else
54
+ raise DropletKit::Error.new("cannot assign resource without valid urn: #{resource}")
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ def all(*args)
62
+ PaginatedResource.new(action(:all), self, *args)
63
+ end
64
+ end
65
+ end
@@ -1,3 +1,3 @@
1
1
  module DropletKit
2
- VERSION = "2.5.0"
2
+ VERSION = "2.6.0"
3
3
  end
@@ -0,0 +1,37 @@
1
+ {
2
+ "projects": [
3
+ {
4
+ "id": "ec104091-d6d3-41b6-b803-780156de20ae",
5
+ "owner_uuid": "34fc5c195b417b7157649f6b8ae273ae9b1b2970",
6
+ "owner_id": 123,
7
+ "name": "digitalocean",
8
+ "description": "Update your project information under Settings",
9
+ "purpose": "",
10
+ "environment": "",
11
+ "is_default": true,
12
+ "created_at": "2018-07-25T08:10:03Z",
13
+ "updated_at": "2018-07-25T08:10:03Z"
14
+ },
15
+ {
16
+ "id": "c177dc8c-12c1-4483-af1c-877eed0f14cb",
17
+ "owner_uuid": "34fc5c195b417b7157649f6b8ae273ae9b1b2970",
18
+ "owner_id": 123,
19
+ "name": "cloud.digitalocean.com",
20
+ "description": "Our control panel",
21
+ "purpose": "Web Application",
22
+ "environment": "Production",
23
+ "is_default": false,
24
+ "created_at": "2018-08-22T20:23:12Z",
25
+ "updated_at": "2018-08-22T21:55:34Z"
26
+ }
27
+ ],
28
+ "meta": {
29
+ "total": 2
30
+ },
31
+ "links": {
32
+ "pages": {
33
+ "first": "https://api.digitalocean.com/v2/projects",
34
+ "last": "https://api.digitalocean.com/v2/projects"
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "projects": [],
3
+ "meta": {
4
+ "total": 0
5
+ },
6
+ "links": {
7
+ "pages": {
8
+ "first": "https://api.digitalocean.com/v2/projects",
9
+ "last": "https://api.digitalocean.com/v2/projects"
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "project": {
3
+ "id": "c177dc8c-12c1-4483-af1c-877eed0f14cb",
4
+ "owner_uuid": "34fc5c195b417b7157649f6b8ae273ae9b1b2970",
5
+ "owner_id": 123,
6
+ "name": "cloud.digitalocean.com",
7
+ "description": "Our control panel",
8
+ "purpose": "Web Application",
9
+ "environment": "Production",
10
+ "is_default": false,
11
+ "created_at": "2018-08-22T20:23:12Z",
12
+ "updated_at": "2018-08-22T21:55:34Z"
13
+ }
14
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "resources": [
3
+ {
4
+ "urn": "do:space:poptarts",
5
+ "assigned_at": "2018-09-20T19:08:37Z",
6
+ "links": {
7
+ "self": "https://poptarts.nyc3.digitaloceanspaces.com"
8
+ }
9
+ },
10
+ {
11
+ "urn": "do:droplet:24535",
12
+ "assigned_at": "2018-09-19T19:08:37Z",
13
+ "links": {
14
+ "self": "https://api.digitalocean.com/v2/droplets/24535"
15
+ }
16
+ },
17
+ {
18
+ "urn": "do:droplet:182734",
19
+ "assigned_at": "2018-09-18T19:08:37Z",
20
+ "links": {
21
+ "self": "https://api.digitalocean.com/v2/droplets/182734"
22
+ }
23
+ },
24
+ {
25
+ "urn": "do:droplet:235312",
26
+ "assigned_at": "2018-09-17T19:08:37Z",
27
+ "links": {
28
+ "self": "https://api.digitalocean.com/v2/droplets/235312"
29
+ }
30
+ },
31
+ {
32
+ "urn": "do:droplet:2435246",
33
+ "assigned_at": "2018-09-16T19:08:37Z",
34
+ "links": {
35
+ "self": "https://api.digitalocean.com/v2/droplets/2435246"
36
+ }
37
+ },
38
+ {
39
+ "urn": "do:droplet:3243262",
40
+ "assigned_at": "2018-09-15T19:08:37Z",
41
+ "links": {
42
+ "self": "https://api.digitalocean.com/v2/droplets/3243262"
43
+ }
44
+ },
45
+ {
46
+ "urn": "do:droplet:245351",
47
+ "assigned_at": "2018-09-14T19:08:37Z",
48
+ "links": {
49
+ "self": "https://api.digitalocean.com/v2/droplets/245351"
50
+ }
51
+ },
52
+ {
53
+ "urn": "do:droplet:1827341",
54
+ "assigned_at": "2018-09-13T19:08:37Z",
55
+ "links": {
56
+ "self": "https://api.digitalocean.com/v2/droplets/1827341"
57
+ }
58
+ },
59
+ {
60
+ "urn": "do:droplet:2353121",
61
+ "assigned_at": "2018-09-12T19:08:37Z",
62
+ "links": {
63
+ "self": "https://api.digitalocean.com/v2/droplets/2353121"
64
+ }
65
+ },
66
+ {
67
+ "urn": "do:droplet:24352461",
68
+ "assigned_at": "2018-09-11T19:08:37Z",
69
+ "links": {
70
+ "self": "https://api.digitalocean.com/v2/droplets/24352461"
71
+ }
72
+ }
73
+ ],
74
+ "meta": {
75
+ "total": 11
76
+ },
77
+ "links": {
78
+ "pages": {
79
+ "first": "https://api.digitalocean.com/v2/projects/c177dc8c-12c1-4483-af1c-877eed0f14cb/resources?per_page=10",
80
+ "next": "https://api.digitalocean.com/v2/projects/c177dc8c-12c1-4483-af1c-877eed0f14cb/resources?page=2&per_page=10",
81
+ "last": "https://api.digitalocean.com/v2/projects/c177dc8c-12c1-4483-af1c-877eed0f14cb/resources?page=2&per_page=10"
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,126 @@
1
+ require 'spec_helper'
2
+
3
+ describe DropletKit::ProjectResource do
4
+ subject(:resource) { described_class.new(connection: connection) }
5
+ include_context 'resources'
6
+
7
+ RSpec::Matchers.define :match_project_fixture do |expected|
8
+ match do |actual|
9
+ expect(actual).to be_kind_of(DropletKit::Project)
10
+ expect(actual.name).to eq('cloud.digitalocean.com')
11
+ expect(actual.id).to eq('c177dc8c-12c1-4483-af1c-877eed0f14cb')
12
+ expect(actual.owner_uuid).to eq('34fc5c195b417b7157649f6b8ae273ae9b1b2970')
13
+ expect(actual.owner_id).to eq(123)
14
+ expect(actual.description).to eq('Our control panel')
15
+ expect(actual.purpose).to eq('Web Application')
16
+ expect(actual.environment).to eq('Production')
17
+ expect(actual.is_default).to be_falsey
18
+ expect(actual.created_at).to be_present
19
+ expect(actual.updated_at).to be_present
20
+ end
21
+ end
22
+ describe '#all' do
23
+ it 'returns all of the projects' do
24
+ stub_do_api('/v2/projects', :get)
25
+ .to_return(body: api_fixture('projects/all'))
26
+ projects = resource.all
27
+
28
+ expect(projects).to all(be_kind_of(DropletKit::Project))
29
+ expect(projects.collection.size).to eq(2)
30
+
31
+ default = projects[0]
32
+ expect(default.name).to eq('digitalocean')
33
+ expect(default.id).to eq('ec104091-d6d3-41b6-b803-780156de20ae')
34
+ expect(default.owner_uuid).to eq('34fc5c195b417b7157649f6b8ae273ae9b1b2970')
35
+ expect(default.owner_id).to eq(123)
36
+ expect(default.description).to eq('Update your project information under Settings')
37
+ expect(default.purpose).to be_empty
38
+ expect(default.environment).to be_empty
39
+ expect(default.is_default).to be_truthy
40
+ expect(default.created_at).to be_present
41
+ expect(default.updated_at).to be_present
42
+
43
+ cloud = projects[1]
44
+ expect(cloud).to match_project_fixture
45
+ end
46
+
47
+ context 'when empty' do
48
+ it 'returns an empty array of projects' do
49
+ stub_do_api('/v2/projects', :get)
50
+ .to_return(body: api_fixture('projects/all_empty'))
51
+ projects = resource.all.map(&:id)
52
+
53
+ expect(projects).to be_empty
54
+ end
55
+ end
56
+
57
+ it_behaves_like 'a paginated index' do
58
+ let(:fixture_path) { 'projects/all' }
59
+ let(:api_path) { '/v2/projects' }
60
+ end
61
+ end
62
+
63
+ describe '#find' do
64
+ it 'returns a singular tag' do
65
+ stub_do_api('/v2/projects/c177dc8c-12c1-4483-af1c-877eed0f14cb', :get)
66
+ .to_return(body: api_fixture('projects/find'))
67
+
68
+ project = resource.find(id: 'c177dc8c-12c1-4483-af1c-877eed0f14cb')
69
+
70
+ expect(project).to match_project_fixture
71
+ end
72
+ end
73
+
74
+ describe '#create' do
75
+ it 'returns the created project' do
76
+ project = DropletKit::Project.new(name: 'cloud.digitalocean.com', description: 'Our control panel', purpose: 'Web Application', environment: 'Production')
77
+
78
+ as_string = DropletKit::ProjectMapping.representation_for(:create, project)
79
+
80
+ stub_do_api('/v2/projects', :post).with(body: as_string)
81
+ .to_return(body: api_fixture('projects/find'), status: 201)
82
+ created_project = resource.create(project)
83
+
84
+ expect(created_project).to match_project_fixture
85
+ end
86
+ end
87
+
88
+ describe '#delete' do
89
+ it 'deletes a project' do
90
+ request = stub_do_api('/v2/projects/c177dc8c-12c1-4483-af1c-877eed0f14cb', :delete)
91
+ .to_return(body: '', status: 204)
92
+
93
+ resource.delete(id: 'c177dc8c-12c1-4483-af1c-877eed0f14cb')
94
+ expect(request).to have_been_made
95
+ end
96
+ end
97
+
98
+ describe '#list_resources' do
99
+ it 'list resources in the specified project' do
100
+ request = stub_do_api('/v2/projects/c177dc8c-12c1-4483-af1c-877eed0f14cb/resources', :get)
101
+ .to_return(body: api_fixture('projects/resources'), status: 200)
102
+
103
+ resources = resource.list_resources(id: 'c177dc8c-12c1-4483-af1c-877eed0f14cb')
104
+
105
+ expect(request).to have_been_made
106
+ expect(resources.to_a.size).to eq(10)
107
+ resources.each do |resource|
108
+ expect(resource[:urn]).to start_with('do:')
109
+ expect(resource[:self_link]).to_not be_empty
110
+ end
111
+
112
+ objects = resources.map(&:to_model)
113
+ expect(objects.first).to be_nil # Can't map spaces
114
+ droplets = objects[1..-1]
115
+ droplets.each do |droplet|
116
+ expect(droplet).to be_a(DropletKit::Droplet)
117
+ expect(droplet.id).to_not be_empty
118
+ end
119
+ end
120
+
121
+ it_behaves_like 'a paginated index' do
122
+ let(:fixture_path) { 'projects/resources' }
123
+ let(:api_path) { '/v2/projects/c177dc8c-12c1-4483-af1c-877eed0f14cb/resources' }
124
+ end
125
+ end
126
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: droplet_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Ross
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-01 00:00:00.000000000 Z
11
+ date: 2018-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: virtus
@@ -222,9 +222,12 @@ files:
222
222
  - lib/droplet_kit/mappings/health_check_mapping.rb
223
223
  - lib/droplet_kit/mappings/image_mapping.rb
224
224
  - lib/droplet_kit/mappings/kernel_mapping.rb
225
+ - lib/droplet_kit/mappings/links_mapping.rb
225
226
  - lib/droplet_kit/mappings/load_balancer_mapping.rb
226
227
  - lib/droplet_kit/mappings/network_detail_mapping.rb
227
228
  - lib/droplet_kit/mappings/network_mapping.rb
229
+ - lib/droplet_kit/mappings/project_assignment_mapping.rb
230
+ - lib/droplet_kit/mappings/project_mapping.rb
228
231
  - lib/droplet_kit/mappings/region_mapping.rb
229
232
  - lib/droplet_kit/mappings/size_mapping.rb
230
233
  - lib/droplet_kit/mappings/snapshot_mapping.rb
@@ -254,11 +257,14 @@ files:
254
257
  - lib/droplet_kit/models/health_check.rb
255
258
  - lib/droplet_kit/models/image.rb
256
259
  - lib/droplet_kit/models/kernel.rb
260
+ - lib/droplet_kit/models/links.rb
257
261
  - lib/droplet_kit/models/load_balancer.rb
258
262
  - lib/droplet_kit/models/meta_information.rb
259
263
  - lib/droplet_kit/models/network.rb
260
264
  - lib/droplet_kit/models/network_hash.rb
261
265
  - lib/droplet_kit/models/pagination_information.rb
266
+ - lib/droplet_kit/models/project.rb
267
+ - lib/droplet_kit/models/project_assignment.rb
262
268
  - lib/droplet_kit/models/region.rb
263
269
  - lib/droplet_kit/models/size.rb
264
270
  - lib/droplet_kit/models/snapshot.rb
@@ -285,6 +291,7 @@ files:
285
291
  - lib/droplet_kit/resources/image_action_resource.rb
286
292
  - lib/droplet_kit/resources/image_resource.rb
287
293
  - lib/droplet_kit/resources/load_balancer_resource.rb
294
+ - lib/droplet_kit/resources/project_resource.rb
288
295
  - lib/droplet_kit/resources/region_resource.rb
289
296
  - lib/droplet_kit/resources/size_resource.rb
290
297
  - lib/droplet_kit/resources/snapshot_resource.rb
@@ -360,6 +367,10 @@ files:
360
367
  - spec/fixtures/images/type.json
361
368
  - spec/fixtures/load_balancers/all.json
362
369
  - spec/fixtures/load_balancers/find.json
370
+ - spec/fixtures/projects/all.json
371
+ - spec/fixtures/projects/all_empty.json
372
+ - spec/fixtures/projects/find.json
373
+ - spec/fixtures/projects/resources.json
363
374
  - spec/fixtures/regions/all.json
364
375
  - spec/fixtures/sizes/all.json
365
376
  - spec/fixtures/snapshots/all.json
@@ -401,6 +412,7 @@ files:
401
412
  - spec/lib/droplet_kit/resources/image_action_resource_spec.rb
402
413
  - spec/lib/droplet_kit/resources/image_resource_spec.rb
403
414
  - spec/lib/droplet_kit/resources/load_balancer_resource_spec.rb
415
+ - spec/lib/droplet_kit/resources/project_resource_spec.rb
404
416
  - spec/lib/droplet_kit/resources/region_resource_spec.rb
405
417
  - spec/lib/droplet_kit/resources/size_resource_spec.rb
406
418
  - spec/lib/droplet_kit/resources/snapshot_resource_spec.rb
@@ -435,7 +447,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
435
447
  version: '0'
436
448
  requirements: []
437
449
  rubyforge_project:
438
- rubygems_version: 2.7.6
450
+ rubygems_version: 2.6.11
439
451
  signing_key:
440
452
  specification_version: 4
441
453
  summary: Droplet Kit is the official Ruby library for DigitalOcean's API
@@ -506,6 +518,10 @@ test_files:
506
518
  - spec/fixtures/images/type.json
507
519
  - spec/fixtures/load_balancers/all.json
508
520
  - spec/fixtures/load_balancers/find.json
521
+ - spec/fixtures/projects/all.json
522
+ - spec/fixtures/projects/all_empty.json
523
+ - spec/fixtures/projects/find.json
524
+ - spec/fixtures/projects/resources.json
509
525
  - spec/fixtures/regions/all.json
510
526
  - spec/fixtures/sizes/all.json
511
527
  - spec/fixtures/snapshots/all.json
@@ -547,6 +563,7 @@ test_files:
547
563
  - spec/lib/droplet_kit/resources/image_action_resource_spec.rb
548
564
  - spec/lib/droplet_kit/resources/image_resource_spec.rb
549
565
  - spec/lib/droplet_kit/resources/load_balancer_resource_spec.rb
566
+ - spec/lib/droplet_kit/resources/project_resource_spec.rb
550
567
  - spec/lib/droplet_kit/resources/region_resource_spec.rb
551
568
  - spec/lib/droplet_kit/resources/size_resource_spec.rb
552
569
  - spec/lib/droplet_kit/resources/snapshot_resource_spec.rb