droplet_kit 2.5.0 → 2.6.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 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