From 2a7e6e1b132c6378de5a6c53d6664013cd616903 Mon Sep 17 00:00:00 2001 From: Caio Ramos Date: Fri, 11 Oct 2024 18:45:41 -0300 Subject: [PATCH] Add apps resource (#330) * Add apps resource * Update .rubocop_todo.yml * Update README.md --- .rubocop_todo.yml | 11 +- README.md | 13 + lib/droplet_kit.rb | 107 ++++ lib/droplet_kit/client.rb | 3 +- lib/droplet_kit/mappings/app_mapping.rb | 121 ++++ lib/droplet_kit/mappings/app_spec_mapping.rb | 549 ++++++++++++++++ .../mappings/deployment_mapping.rb | 136 ++++ lib/droplet_kit/models/app.rb | 70 ++ lib/droplet_kit/models/app_spec.rb | 290 +++++++++ lib/droplet_kit/models/deployment.rb | 73 +++ lib/droplet_kit/resources/app_resource.rb | 36 ++ spec/fixtures/apps/all.json | 604 ++++++++++++++++++ spec/fixtures/apps/delete.json | 1 + spec/fixtures/apps/find.json | 317 +++++++++ .../resources/app_resource_spec.rb | 172 +++++ 15 files changed, 2497 insertions(+), 6 deletions(-) create mode 100644 lib/droplet_kit/mappings/app_mapping.rb create mode 100644 lib/droplet_kit/mappings/app_spec_mapping.rb create mode 100644 lib/droplet_kit/mappings/deployment_mapping.rb create mode 100644 lib/droplet_kit/models/app.rb create mode 100644 lib/droplet_kit/models/app_spec.rb create mode 100644 lib/droplet_kit/models/deployment.rb create mode 100644 lib/droplet_kit/resources/app_resource.rb create mode 100644 spec/fixtures/apps/all.json create mode 100644 spec/fixtures/apps/delete.json create mode 100644 spec/fixtures/apps/find.json create mode 100644 spec/lib/droplet_kit/resources/app_resource_spec.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index f199769..ff176f8 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2024-10-07 22:05:47 UTC using RuboCop version 1.66.1. +# on 2024-10-09 19:14:26 UTC using RuboCop version 1.66.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -70,7 +70,7 @@ Metrics/MethodLength: # Offense count: 1 # Configuration parameters: CountComments, CountAsOne. Metrics/ModuleLength: - Max: 188 + Max: 295 # Offense count: 1 # This cop supports unsafe autocorrection (--autocorrect-all). @@ -110,7 +110,7 @@ RSpec/ContextWording: - 'spec/lib/droplet_kit/resources/vpc_resource_spec.rb' - 'spec/support/resource_context.rb' -# Offense count: 130 +# Offense count: 131 # Configuration parameters: CountAsOne. RSpec/ExampleLength: Max: 43 @@ -125,7 +125,7 @@ RSpec/LeakyConstantDeclaration: Exclude: - 'spec/lib/droplet_kit/client_spec.rb' -# Offense count: 129 +# Offense count: 131 RSpec/MultipleExpectations: Max: 30 @@ -145,7 +145,7 @@ RSpec/NestedGroups: RSpec/SpecFilePathFormat: Enabled: false -# Offense count: 186 +# Offense count: 293 # Configuration parameters: AllowedConstants. Style/Documentation: Enabled: false @@ -168,6 +168,7 @@ Style/MissingRespondToMissing: # AllowedMethods: define_method Style/SymbolProc: Exclude: + - 'lib/droplet_kit/resources/app_resource.rb' - 'lib/droplet_kit/resources/container_registry_resource.rb' - 'lib/droplet_kit/resources/droplet_action_resource.rb' - 'lib/droplet_kit/resources/kubernetes_cluster_resource.rb' diff --git a/README.md b/README.md index 565c2b3..e956a99 100644 --- a/README.md +++ b/README.md @@ -685,6 +685,19 @@ Actions supported: * `client.one_clicks.all(type: 'kubernetes|droplet')` * `client.one_clicks.create_kubernetes(one_click_kubernetes)` +## App resource + + client = DropletKit::Client.new(access_token: 'TOKEN') + client.apps #=> DropletKit::AppResource + +Actions supported: + +* `client.apps.all(with_projects: bool)` +* `client.apps.find(id: 'id')` +* `client.apps.create(app)` +* `client.apps.update(app, id: 'id')` +* `client.apps.delete(id: 'id')` + ## Contributing 1. Fork it ( https://github.com/digitalocean/droplet_kit/fork ) diff --git a/lib/droplet_kit.rb b/lib/droplet_kit.rb index 50679e0..c645ad4 100644 --- a/lib/droplet_kit.rb +++ b/lib/droplet_kit.rb @@ -81,6 +81,59 @@ module DropletKit autoload :VPCPeering, 'droplet_kit/models/vpc_peering' autoload :OneClick, 'droplet_kit/models/one_click' autoload :OneClickKubernetes, 'droplet_kit/models/one_click_kubernetes' + autoload :AppDomainSpec, 'droplet_kit/models/app_spec' + autoload :AppGitSourceSpec, 'droplet_kit/models/app_spec' + autoload :AppGitHubSourceSpec, 'droplet_kit/models/app_spec' + autoload :AppGitLabSourceSpec, 'droplet_kit/models/app_spec' + autoload :AppImageDeployOnPush, 'droplet_kit/models/app_spec' + autoload :AppImageSourceSpec, 'droplet_kit/models/app_spec' + autoload :AppVariableDefinition, 'droplet_kit/models/app_spec' + autoload :AppLogDestinationSpecPapertrail, 'droplet_kit/models/app_spec' + autoload :AppLogDestinationSpecDatadog, 'droplet_kit/models/app_spec' + autoload :AppLogDestinationSpecLogtail, 'droplet_kit/models/app_spec' + autoload :OpenSearchBasicAuth, 'droplet_kit/models/app_spec' + autoload :AppLogDestinationSpecOpenSearch, 'droplet_kit/models/app_spec' + autoload :AppLogDestinationSpec, 'droplet_kit/models/app_spec' + autoload :AppAutoscalingSpecMetricCPU, 'droplet_kit/models/app_spec' + autoload :AppAutoscalingSpecMetrics, 'droplet_kit/models/app_spec' + autoload :AppAutoscalingSpec, 'droplet_kit/models/app_spec' + autoload :AppServiceSpecHealthCheck, 'droplet_kit/models/app_spec' + autoload :AppServiceSpecTermination, 'droplet_kit/models/app_spec' + autoload :AppServiceSpec, 'droplet_kit/models/app_spec' + autoload :AppStaticSiteSpec, 'droplet_kit/models/app_spec' + autoload :AppJobSpecTermination, 'droplet_kit/models/app_spec' + autoload :AppJobSpec, 'droplet_kit/models/app_spec' + autoload :AppWorkerSpecTermination, 'droplet_kit/models/app_spec' + autoload :AppWorkerSpec, 'droplet_kit/models/app_spec' + autoload :AppAlertSpec, 'droplet_kit/models/app_spec' + autoload :AppFunctionSpec, 'droplet_kit/models/app_spec' + autoload :AppDatabaseSpec, 'droplet_kit/models/app_spec' + autoload :AppIngressSpecRuleStringMatch, 'droplet_kit/models/app_spec' + autoload :AppIngressSpecRuleMatch, 'droplet_kit/models/app_spec' + autoload :AppStringMatch, 'droplet_kit/models/app_spec' + autoload :AppCorsPolicy, 'droplet_kit/models/app_spec' + autoload :AppIngressSpecRuleRoutingComponent, 'droplet_kit/models/app_spec' + autoload :AppIngressSpecRuleRoutingRedirect, 'droplet_kit/models/app_spec' + autoload :AppIngressSpecRule, 'droplet_kit/models/app_spec' + autoload :AppIngressSpec, 'droplet_kit/models/app_spec' + autoload :AppEgressSpec, 'droplet_kit/models/app_spec' + autoload :AppSpec, 'droplet_kit/models/app_spec' + autoload :DeploymentJob, 'droplet_kit/models/deployment' + autoload :DeploymentFunction, 'droplet_kit/models/deployment' + autoload :DeploymentProgressStepReason, 'droplet_kit/models/deployment' + autoload :DeploymentProgressStep, 'droplet_kit/models/deployment' + autoload :DeploymentProgress, 'droplet_kit/models/deployment' + autoload :DeploymentService, 'droplet_kit/models/deployment' + autoload :DeploymentStaticSite, 'droplet_kit/models/deployment' + autoload :DeploymentWorker, 'droplet_kit/models/deployment' + autoload :Deployment, 'droplet_kit/models/deployment' + autoload :AppDomainProgress, 'droplet_kit/models/app' + autoload :AppDomainSpec, 'droplet_kit/models/app' + autoload :AppDomainValidation, 'droplet_kit/models/app' + autoload :AppDomain, 'droplet_kit/models/app' + autoload :AppRegion, 'droplet_kit/models/app' + autoload :AppDedicatedIp, 'droplet_kit/models/app' + autoload :App, 'droplet_kit/models/app' # Resources autoload :DropletResource, 'droplet_kit/resources/droplet_resource' @@ -118,6 +171,7 @@ module DropletKit autoload :VPCResource, 'droplet_kit/resources/vpc_resource' autoload :VPCPeeringResource, 'droplet_kit/resources/vpc_peering_resource' autoload :OneClickResource, 'droplet_kit/resources/one_click_resource' + autoload :AppResource, 'droplet_kit/resources/app_resource' # JSON Maps autoload :DropletMapping, 'droplet_kit/mappings/droplet_mapping' @@ -192,6 +246,59 @@ module DropletKit autoload :VPCPeeringMapping, 'droplet_kit/mappings/vpc_peering_mapping' autoload :OneClickMapping, 'droplet_kit/mappings/one_click_mapping' autoload :OneClickKubernetesMapping, 'droplet_kit/mappings/one_click_kubernetes_mapping' + autoload :AppDomainSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppGitSourceSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppGitHubSourceSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppGitLabSourceSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppImageDeployOnPushMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppImageSourceSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppVariableDefinitionMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppLogDestinationSpecPapertrailMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppLogDestinationSpecDatadogMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppLogDestinationSpecLogtailMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :OpenSearchBasicAuthMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppLogDestinationSpecOpenSearchMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppLogDestinationSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppAutoscalingSpecMetricCPUMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppAutoscalingSpecMetricsMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppAutoscalingSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppServiceSpecHealthCheckMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppServiceSpecTerminationMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppServiceSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppStaticSiteSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppJobSpecTerminationMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppJobSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppWorkerSpecTerminationMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppWorkerSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppAlertSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppFunctionSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppDatabaseSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppIngressSpecRuleStringMatchMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppIngressSpecRuleMatchMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppStringMatchMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppCorsPolicyMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppIngressSpecRuleRoutingComponentMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppIngressSpecRuleRoutingRedirectMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppIngressSpecRuleMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppIngressSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppEgressSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :AppSpecMapping, 'droplet_kit/mappings/app_spec_mapping' + autoload :DeploymentJobMapping, 'droplet_kit/mappings/deployment_mapping' + autoload :DeploymentFunctionMapping, 'droplet_kit/mappings/deployment_mapping' + autoload :DeploymentProgressStepReasonMapping, 'droplet_kit/mappings/deployment_mapping' + autoload :DeploymentProgressStepMapping, 'droplet_kit/mappings/deployment_mapping' + autoload :DeploymentProgressMapping, 'droplet_kit/mappings/deployment_mapping' + autoload :DeploymentServiceMapping, 'droplet_kit/mappings/deployment_mapping' + autoload :DeploymentStaticSiteMapping, 'droplet_kit/mappings/deployment_mapping' + autoload :DeploymentWorkerMapping, 'droplet_kit/mappings/deployment_mapping' + autoload :DeploymentMapping, 'droplet_kit/mappings/deployment_mapping' + autoload :AppDomainProgressMapping, 'droplet_kit/mappings/app_mapping' + autoload :AppDomainSpecMapping, 'droplet_kit/mappings/app_mapping' + autoload :AppDomainValidationMapping, 'droplet_kit/mappings/app_mapping' + autoload :AppDomainMapping, 'droplet_kit/mappings/app_mapping' + autoload :AppRegionMapping, 'droplet_kit/mappings/app_mapping' + autoload :AppDedicatedIpMapping, 'droplet_kit/mappings/app_mapping' + autoload :AppMapping, 'droplet_kit/mappings/app_mapping' # Utils autoload :PaginatedResource, 'droplet_kit/paginated_resource' diff --git a/lib/droplet_kit/client.rb b/lib/droplet_kit/client.rb index a9b307a..04d4e32 100644 --- a/lib/droplet_kit/client.rb +++ b/lib/droplet_kit/client.rb @@ -82,7 +82,8 @@ def self.resources volume_actions: VolumeActionResource, vpcs: VPCResource, vpc_peerings: VPCPeeringResource, - one_clicks: OneClickResource + one_clicks: OneClickResource, + apps: AppResource } end diff --git a/lib/droplet_kit/mappings/app_mapping.rb b/lib/droplet_kit/mappings/app_mapping.rb new file mode 100644 index 0000000..e1fbfc7 --- /dev/null +++ b/lib/droplet_kit/mappings/app_mapping.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +module DropletKit + class AppDomainProgressMapping + include Kartograph::DSL + + kartograph do + mapping AppDomainProgress + scoped :read do + property :steps + end + end + end + + class AppDomainSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppDomainSpec + scoped :read do + property :domain + property :type + property :wildcard + property :zone + property :minimum_tls_version + end + end + end + + class AppDomainValidationMapping + include Kartograph::DSL + + kartograph do + mapping AppDomainValidation + scoped :read do + property :txt_name + property :txt_value + end + end + end + + class AppDomainMapping + include Kartograph::DSL + + kartograph do + mapping AppDomain + scoped :read do + property :id + property :phase + property :progress, include: AppDomainProgressMapping + property :spec, include: AppDomainSpecMapping + property :validation, plural: true, include: AppDomainValidationMapping + property :rotate_validation_records + property :certificate_expires_at + end + end + end + + class AppRegionMapping + include Kartograph::DSL + + kartograph do + mapping AppRegion + scoped :read do + property :continent + property :data_centers + property :default + property :disabled + property :flag + property :label + property :reason + property :slug + end + end + end + + class AppDedicatedIpMapping + include Kartograph::DSL + + kartograph do + mapping AppDedicatedIp + scoped :read do + property :ip + property :id + property :status + end + end + end + + class AppMapping + include Kartograph::DSL + + kartograph do + mapping App + root_key plural: 'apps', singular: 'app', scopes: [:read] + + property :spec, include: AppSpecMapping, scopes: %i[create update read] + property :project_id, scopes: %i[create read] + property :update_all_source_versions, scopes: [:update] + scoped :read do + property :active_deployment, include: DeploymentMapping + property :created_at + property :default_ingress + property :domains, plural: true, include: AppDomainMapping + property :id + property :in_progress_deployment, include: DeploymentMapping + property :last_deployment_created_at + property :live_domain + property :live_url + property :live_url_base + property :owner_uuid + property :pending_deployment, include: DeploymentMapping + property :region, include: AppRegionMapping + property :tier_slug + property :updated_at + property :pinned_deployment, include: DeploymentMapping + property :dedicated_ips, plural: true, include: AppDedicatedIpMapping + end + end + end +end diff --git a/lib/droplet_kit/mappings/app_spec_mapping.rb b/lib/droplet_kit/mappings/app_spec_mapping.rb new file mode 100644 index 0000000..20b05eb --- /dev/null +++ b/lib/droplet_kit/mappings/app_spec_mapping.rb @@ -0,0 +1,549 @@ +# frozen_string_literal: true + +module DropletKit + class AppDomainSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppDomainSpec + scoped :read, :create, :update do + property :domain + property :type + property :wildcard + property :zone + property :minimum_tls_version + end + end + end + + class AppGitSourceSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppGitSourceSpec + scoped :read, :create, :update do + property :branch + property :repo_clone_url + end + end + end + + class AppGitHubSourceSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppGitHubSourceSpec + scoped :read, :create, :update do + property :branch + property :deploy_on_push + property :repo + end + end + end + + class AppGitLabSourceSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppGitLabSourceSpec + scoped :read, :create, :update do + property :branch + property :deploy_on_push + property :repo + end + end + end + + class AppImageDeployOnPushMapping + include Kartograph::DSL + + kartograph do + mapping AppImageDeployOnPush + scoped :read, :create, :update do + property :enabled + end + end + end + + class AppImageSourceSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppImageSourceSpec + scoped :read, :create, :update do + property :registry + property :registry_type + property :registry_credentials + property :repository + property :tag + property :digest + property :deploy_on_push, include: AppImageDeployOnPushMapping + end + end + end + + class AppVariableDefinitionMapping + include Kartograph::DSL + + kartograph do + mapping AppVariableDefinition + scoped :read, :create, :update do + property :key + property :scope + property :type + property :value + end + end + end + + class AppLogDestinationSpecPapertrailMapping + include Kartograph::DSL + + kartograph do + mapping AppLogDestinationSpecPapertrail + scoped :read, :create, :update do + property :endpoint + end + end + end + + class AppLogDestinationSpecDatadogMapping + include Kartograph::DSL + + kartograph do + mapping AppLogDestinationSpecDatadog + scoped :read, :create, :update do + property :endpoint + property :api_key + end + end + end + + class AppLogDestinationSpecLogtailMapping + include Kartograph::DSL + + kartograph do + mapping AppLogDestinationSpecLogtail + scoped :read, :create, :update do + property :token + end + end + end + + class OpenSearchBasicAuthMapping + include Kartograph::DSL + + kartograph do + mapping OpenSearchBasicAuth + scoped :read, :create, :update do + property :username + property :password + end + end + end + + class AppLogDestinationSpecOpenSearchMapping + include Kartograph::DSL + + kartograph do + mapping AppLogDestinationSpecOpenSearch + scoped :read, :create, :update do + property :endpoint + property :basic_auth, include: OpenSearchBasicAuthMapping + property :index_name + property :cluster_name + end + end + end + + class AppLogDestinationSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppLogDestinationSpec + scoped :read, :create, :update do + property :name + property :papertrail, include: AppLogDestinationSpecPapertrailMapping + property :datadog, include: AppLogDestinationSpecDatadogMapping + property :logtail, include: AppLogDestinationSpecLogtailMapping + property :open_search, include: AppLogDestinationSpecOpenSearchMapping + end + end + end + + class AppAutoscalingSpecMetricCPUMapping + include Kartograph::DSL + + kartograph do + mapping AppAutoscalingSpecMetricCPU + scoped :read, :create, :update do + property :percent + end + end + end + + class AppAutoscalingSpecMetricsMapping + include Kartograph::DSL + + kartograph do + mapping AppAutoscalingSpecMetrics + scoped :read, :create, :update do + property :cpu, include: AppAutoscalingSpecMetricCPUMapping + end + end + end + + class AppAutoscalingSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppAutoscalingSpec + scoped :read, :create, :update do + property :min_instance_count + property :max_instance_count + property :metrics, include: AppAutoscalingSpecMetricsMapping + end + end + end + + class AppServiceSpecHealthCheckMapping + include Kartograph::DSL + + kartograph do + mapping AppServiceSpecHealthCheck + scoped :read, :create, :update do + property :failure_threshold + property :port + property :http_path + property :initial_delay_seconds + property :period_seconds + property :success_threshold + property :timeout_seconds + end + end + end + + class AppServiceSpecTerminationMapping + include Kartograph::DSL + + kartograph do + mapping AppServiceSpecTermination + scoped :read, :create, :update do + property :drain_seconds + property :grace_period_seconds + end + end + end + + class AppServiceSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppServiceSpec + scoped :read, :create, :update do + property :name + property :git, include: AppGitSourceSpecMapping + property :github, include: AppGitHubSourceSpecMapping + property :gitlab, include: AppGitLabSourceSpecMapping + property :image, include: AppImageSourceSpecMapping + property :dockerfile_path + property :build_command + property :run_command + property :source_dir + property :envs, plural: true, include: AppVariableDefinitionMapping + property :environment_slug + property :log_destinations, plural: true, include: AppLogDestinationSpecMapping + property :instance_count + property :instance_size_slug + property :autoscaling, include: AppAutoscalingSpecMapping + property :health_check, include: AppServiceSpecHealthCheckMapping + property :http_port + property :internal_ports + property :termination, include: AppServiceSpecTerminationMapping + end + end + end + + class AppStaticSiteSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppStaticSiteSpec + scoped :read, :create, :update do + property :name + property :git, include: AppGitSourceSpecMapping + property :github, include: AppGitHubSourceSpecMapping + property :gitlab, include: AppGitLabSourceSpecMapping + property :image, include: AppImageSourceSpecMapping + property :dockerfile_path + property :build_command + property :run_command + property :source_dir + property :envs, plural: true, include: AppVariableDefinitionMapping + property :environment_slug + property :log_destinations, plural: true, include: AppLogDestinationSpecMapping + property :index_document + property :error_document + property :catchall_document + property :output_dir + end + end + end + + class AppJobSpecTerminationMapping + include Kartograph::DSL + + kartograph do + mapping AppJobSpecTermination + scoped :read, :create, :update do + property :grace_period_seconds + end + end + end + + class AppJobSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppJobSpec + scoped :read, :create, :update do + property :name + property :git, include: AppGitSourceSpecMapping + property :github, include: AppGitHubSourceSpecMapping + property :gitlab, include: AppGitLabSourceSpecMapping + property :image, include: AppImageSourceSpecMapping + property :dockerfile_path + property :build_command + property :run_command + property :source_dir + property :envs, plural: true, include: AppVariableDefinitionMapping + property :environment_slug + property :log_destinations, plural: true, include: AppLogDestinationSpecMapping + property :instance_count + property :instance_size_slug + property :autoscaling, include: AppAutoscalingSpecMapping + property :kind + property :termination, include: AppJobSpecTerminationMapping + end + end + end + + class AppWorkerSpecTerminationMapping + include Kartograph::DSL + + kartograph do + mapping AppWorkerSpecTermination + scoped :read, :create, :update do + property :grace_period_seconds + end + end + end + + class AppWorkerSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppWorkerSpec + scoped :read, :create, :update do + property :name + property :git, include: AppGitSourceSpecMapping + property :github, include: AppGitHubSourceSpecMapping + property :gitlab, include: AppGitLabSourceSpecMapping + property :image, include: AppImageSourceSpecMapping + property :dockerfile_path + property :build_command + property :run_command + property :source_dir + property :envs, plural: true, include: AppVariableDefinitionMapping + property :environment_slug + property :log_destinations, plural: true, include: AppLogDestinationSpecMapping + property :instance_count + property :instance_size_slug + property :autoscaling, include: AppAutoscalingSpecMapping + property :termination, include: AppWorkerSpecTerminationMapping + end + end + end + + class AppAlertSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppAlertSpec + scoped :read, :create, :update do + property :rule + property :disabled + property :operator + property :value + property :window + end + end + end + + class AppFunctionSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppFunctionSpec + scoped :read, :create, :update do + property :name + property :source_dir + property :alerts, plural: true, include: AppAlertSpecMapping + property :envs, plural: true, include: AppVariableDefinitionMapping + property :log_destinations, plural: true, include: AppLogDestinationSpecMapping + end + end + end + + class AppDatabaseSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppDatabaseSpec + scoped :read, :create, :update do + property :cluster_name + property :db_name + property :db_user + property :engine + property :name + property :production + property :version + end + end + end + + class AppIngressSpecRuleStringMatchMapping + include Kartograph::DSL + + kartograph do + mapping AppIngressSpecRuleStringMatch + scoped :read, :create, :update do + property :prefix + end + end + end + + class AppIngressSpecRuleMatchMapping + include Kartograph::DSL + + kartograph do + mapping AppIngressSpecRuleMatch + scoped :read, :create, :update do + property :path, include: AppIngressSpecRuleStringMatchMapping + end + end + end + + class AppStringMatchMapping + include Kartograph::DSL + + kartograph do + mapping AppStringMatch + scoped :read, :create, :update do + property :exact + property :regex + end + end + end + + class AppCorsPolicyMapping + include Kartograph::DSL + + kartograph do + mapping AppCorsPolicy + scoped :read, :create, :update do + property :allow_origins, plural: true, include: AppStringMatchMapping + property :allow_methods + property :allow_headers + property :expose_headers + property :max_age + property :allow_credentials + end + end + end + + class AppIngressSpecRuleRoutingComponentMapping + include Kartograph::DSL + + kartograph do + mapping AppIngressSpecRuleRoutingComponent + scoped :read, :create, :update do + property :name + property :preserve_path_prefix + property :rewrite + end + end + end + + class AppIngressSpecRuleRoutingRedirectMapping + include Kartograph::DSL + + kartograph do + mapping AppIngressSpecRuleRoutingRedirect + scoped :read, :create, :update do + property :uri + property :authority + property :port + property :scheme + property :redirect_code + end + end + end + + class AppIngressSpecRuleMapping + include Kartograph::DSL + + kartograph do + mapping AppIngressSpecRule + scoped :read, :create, :update do + property :match, include: AppIngressSpecRuleMatchMapping + property :cors, include: AppCorsPolicyMapping + property :component, include: AppIngressSpecRuleRoutingComponentMapping + property :redirect, include: AppIngressSpecRuleRoutingRedirectMapping + end + end + end + + class AppIngressSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppIngressSpec + scoped :read, :create, :update do + property :rules, plural: true, include: AppIngressSpecRuleMapping + end + end + end + + class AppEgressSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppEgressSpec + scoped :read, :create, :update do + property :type + end + end + end + + class AppSpecMapping + include Kartograph::DSL + + kartograph do + mapping AppSpec + scoped :read, :create, :update do + property :name + property :region + property :domains, plural: true, include: AppDomainSpecMapping + property :services, plural: true, include: AppServiceSpecMapping + property :static_sites, plural: true, include: AppStaticSiteSpecMapping + property :jobs, plural: true, include: AppJobSpecMapping + property :workers, plural: true, include: AppWorkerSpecMapping + property :functions, plural: true, include: AppFunctionSpecMapping + property :databases, plural: true, include: AppDatabaseSpecMapping + property :ingress, include: AppIngressSpecMapping + property :egress, include: AppEgressSpecMapping + end + end + end +end diff --git a/lib/droplet_kit/mappings/deployment_mapping.rb b/lib/droplet_kit/mappings/deployment_mapping.rb new file mode 100644 index 0000000..ac3da52 --- /dev/null +++ b/lib/droplet_kit/mappings/deployment_mapping.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true + +module DropletKit + class DeploymentJobMapping + include Kartograph::DSL + + kartograph do + mapping DeploymentJob + scoped :read do + property :name + property :source_commit_hash + end + end + end + + class DeploymentFunctionMapping + include Kartograph::DSL + + kartograph do + mapping DeploymentFunction + scoped :read do + property :name + property :source_commit_hash + property :namespace + end + end + end + + class DeploymentProgressStepReasonMapping + include Kartograph::DSL + + kartograph do + mapping DeploymentProgressStepReason + scoped :read do + property :code + property :message + end + end + end + + class DeploymentProgressStepMapping + include Kartograph::DSL + + kartograph do + mapping DeploymentProgressStep + scoped :read do + property :component_name + property :ended_at + property :message_base + property :name + property :reason, include: DeploymentProgressStepReasonMapping + property :started_at + property :status + property :steps + end + end + end + + class DeploymentProgressMapping + include Kartograph::DSL + + kartograph do + mapping DeploymentProgress + scoped :read do + property :error_steps + property :pending_steps + property :running_steps + property :steps, plural: true, include: DeploymentProgressStepMapping + property :success_steps + property :summary_steps, plural: true, include: DeploymentProgressStepMapping + property :total_steps + end + end + end + + class DeploymentServiceMapping + include Kartograph::DSL + + kartograph do + mapping DeploymentService + scoped :read do + property :name + property :source_commit_hash + end + end + end + + class DeploymentStaticSiteMapping + include Kartograph::DSL + + kartograph do + mapping DeploymentStaticSite + scoped :read do + property :name + property :source_commit_hash + end + end + end + + class DeploymentWorkerMapping + include Kartograph::DSL + + kartograph do + mapping DeploymentWorker + scoped :read do + property :name + property :source_commit_hash + end + end + end + + class DeploymentMapping + include Kartograph::DSL + + kartograph do + mapping Deployment + scoped :read do + property :cause + property :cloned_from + property :created_at + property :id + property :jobs, plural: true, include: DeploymentJobMapping + property :functions, plural: true, include: DeploymentFunctionMapping + property :phase + property :phase_last_updated_at + property :progress, include: DeploymentProgressMapping + property :services, plural: true, include: DeploymentServiceMapping + property :spec, include: AppSpecMapping + property :static_sites, plural: true, include: DeploymentStaticSiteMapping + property :tier_slug + property :updated_at + property :workers, plural: true, include: DeploymentWorkerMapping + end + end + end +end diff --git a/lib/droplet_kit/models/app.rb b/lib/droplet_kit/models/app.rb new file mode 100644 index 0000000..b71f1ae --- /dev/null +++ b/lib/droplet_kit/models/app.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module DropletKit + class AppDomainProgress < BaseModel + attribute :steps + end + + class AppDomainSpec < BaseModel + attribute :domain + attribute :type + attribute :wildcard + attribute :zone + attribute :minimum_tls_version + end + + class AppDomainValidation < BaseModel + attribute :txt_name + attribute :txt_value + end + + class AppDomain < BaseModel + attribute :id + attribute :phase + attribute :progress, AppDomainProgress + attribute :spec, AppDomainSpec + attribute :validation, [AppDomainValidation] + attribute :rotate_validation_records + attribute :certificate_expires_at + end + + class AppRegion < BaseModel + attribute :continent + attribute :data_centers + attribute :default + attribute :disabled + attribute :flag + attribute :label + attribute :reason + attribute :slug + end + + class AppDedicatedIp < BaseModel + attribute :ip + attribute :id + attribute :status + end + + class App < BaseModel + attribute :active_deployment, Deployment + attribute :created_at + attribute :default_ingress + attribute :domains, [AppDomain] + attribute :id + attribute :in_progress_deployment, Deployment + attribute :last_deployment_created_at + attribute :live_domain + attribute :live_url + attribute :live_url_base + attribute :owner_uuid + attribute :pending_deployment, Deployment + attribute :project_id + attribute :region, AppRegion + attribute :spec, AppSpec + attribute :tier_slug + attribute :updated_at + attribute :pinned_deployment, Deployment + attribute :dedicated_ips, [AppDedicatedIp] + attribute :update_all_source_versions + end +end diff --git a/lib/droplet_kit/models/app_spec.rb b/lib/droplet_kit/models/app_spec.rb new file mode 100644 index 0000000..26546de --- /dev/null +++ b/lib/droplet_kit/models/app_spec.rb @@ -0,0 +1,290 @@ +# frozen_string_literal: true + +module DropletKit + class AppDomainSpec < BaseModel + attribute :domain + attribute :type + attribute :wildcard + attribute :zone + attribute :minimum_tls_version + end + + class AppGitSourceSpec < BaseModel + attribute :branch + attribute :repo_clone_url + end + + class AppGitHubSourceSpec < BaseModel + attribute :branch + attribute :deploy_on_push + attribute :repo + end + + class AppGitLabSourceSpec < BaseModel + attribute :branch + attribute :deploy_on_push + attribute :repo + end + + class AppImageDeployOnPush < BaseModel + attribute :enabled + end + + class AppImageSourceSpec < BaseModel + attribute :registry + attribute :registry_type + attribute :registry_credentials + attribute :repository + attribute :tag + attribute :digest + attribute :deploy_on_push, AppImageDeployOnPush + end + + class AppVariableDefinition < BaseModel + attribute :key + attribute :scope + attribute :type + attribute :value + end + + class AppLogDestinationSpecPapertrail < BaseModel + attribute :endpoint + end + + class AppLogDestinationSpecDatadog < BaseModel + attribute :endpoint + attribute :api_key + end + + class AppLogDestinationSpecLogtail < BaseModel + attribute :token + end + + class OpenSearchBasicAuth < BaseModel + attribute :username + attribute :password + end + + class AppLogDestinationSpecOpenSearch < BaseModel + attribute :endpoint + attribute :basic_auth, OpenSearchBasicAuth + attribute :index_name + attribute :cluster_name + end + + class AppLogDestinationSpec < BaseModel + attribute :name + attribute :papertrail, AppLogDestinationSpecPapertrail + attribute :datadog, AppLogDestinationSpecDatadog + attribute :logtail, AppLogDestinationSpecLogtail + attribute :open_search, AppLogDestinationSpecOpenSearch + end + + class AppAutoscalingSpecMetricCPU < BaseModel + attribute :percent + end + + class AppAutoscalingSpecMetrics < BaseModel + attribute :cpu, AppAutoscalingSpecMetricCPU + end + + class AppAutoscalingSpec < BaseModel + attribute :min_instance_count + attribute :max_instance_count + attribute :metrics, AppAutoscalingSpecMetrics + end + + class AppServiceSpecHealthCheck < BaseModel + attribute :failure_threshold + attribute :port + attribute :http_path + attribute :initial_delay_seconds + attribute :period_seconds + attribute :success_threshold + attribute :timeout_seconds + end + + class AppServiceSpecTermination < BaseModel + attribute :drain_seconds + attribute :grace_period_seconds + end + + class AppServiceSpec < BaseModel + attribute :name + attribute :git, AppGitSourceSpec + attribute :github, AppGitHubSourceSpec + attribute :gitlab, AppGitLabSourceSpec + attribute :image, AppImageSourceSpec + attribute :dockerfile_path + attribute :build_command + attribute :run_command + attribute :source_dir + attribute :envs, [AppVariableDefinition] + attribute :environment_slug + attribute :log_destinations, [AppLogDestinationSpec] + attribute :instance_count + attribute :instance_size_slug + attribute :autoscaling, AppAutoscalingSpec + attribute :health_check, AppServiceSpecHealthCheck + attribute :http_port + attribute :internal_ports + attribute :termination, AppServiceSpecTermination + end + + class AppStaticSiteSpec < BaseModel + attribute :name + attribute :git, AppGitSourceSpec + attribute :github, AppGitHubSourceSpec + attribute :gitlab, AppGitLabSourceSpec + attribute :image, AppImageSourceSpec + attribute :dockerfile_path + attribute :build_command + attribute :run_command + attribute :source_dir + attribute :envs, [AppVariableDefinition] + attribute :environment_slug + attribute :log_destinations, [AppLogDestinationSpec] + attribute :index_document + attribute :error_document + attribute :catchall_document + attribute :output_dir + end + + class AppJobSpecTermination < BaseModel + attribute :grace_period_seconds + end + + class AppJobSpec < BaseModel + attribute :name + attribute :git, AppGitSourceSpec + attribute :github, AppGitHubSourceSpec + attribute :gitlab, AppGitLabSourceSpec + attribute :image, AppImageSourceSpec + attribute :dockerfile_path + attribute :build_command + attribute :run_command + attribute :source_dir + attribute :envs, [AppVariableDefinition] + attribute :environment_slug + attribute :log_destinations, [AppLogDestinationSpec] + attribute :instance_count + attribute :instance_size_slug + attribute :autoscaling, AppAutoscalingSpec + attribute :kind + attribute :termination, AppJobSpecTermination + end + + class AppWorkerSpecTermination < BaseModel + attribute :grace_period_seconds + end + + class AppWorkerSpec < BaseModel + attribute :name + attribute :git, AppGitSourceSpec + attribute :github, AppGitHubSourceSpec + attribute :gitlab, AppGitLabSourceSpec + attribute :image, AppImageSourceSpec + attribute :dockerfile_path + attribute :build_command + attribute :run_command + attribute :source_dir + attribute :envs, [AppVariableDefinition] + attribute :environment_slug + attribute :log_destinations, [AppLogDestinationSpec] + attribute :instance_count + attribute :instance_size_slug + attribute :autoscaling, AppAutoscalingSpec + attribute :termination, AppWorkerSpecTermination + end + + class AppAlertSpec < BaseModel + attribute :rule + attribute :disabled + attribute :operator + attribute :value + attribute :window + end + + class AppFunctionSpec < BaseModel + attribute :name + attribute :source_dir + attribute :alerts, [AppAlertSpec] + attribute :envs, [AppVariableDefinition] + attribute :log_destinations, [AppLogDestinationSpec] + end + + class AppDatabaseSpec < BaseModel + attribute :cluster_name + attribute :db_name + attribute :db_user + attribute :engine + attribute :name + attribute :production + attribute :version + end + + class AppIngressSpecRuleStringMatch < BaseModel + attribute :prefix + end + + class AppIngressSpecRuleMatch < BaseModel + attribute :path, AppIngressSpecRuleStringMatch + end + + class AppStringMatch < BaseModel + attribute :exact + attribute :regex + end + + class AppCorsPolicy < BaseModel + attribute :allow_origins, [AppStringMatch] + attribute :allow_methods + attribute :allow_headers + attribute :expose_headers + attribute :max_age + attribute :allow_credentials + end + + class AppIngressSpecRuleRoutingComponent < BaseModel + attribute :name + attribute :preserve_path_prefix + attribute :rewrite + end + + class AppIngressSpecRuleRoutingRedirect < BaseModel + attribute :uri + attribute :authority + attribute :port + attribute :scheme + attribute :redirect_code + end + + class AppIngressSpecRule < BaseModel + attribute :match, AppIngressSpecRuleMatch + attribute :cors, AppCorsPolicy + attribute :component, AppIngressSpecRuleRoutingComponent + attribute :redirect, AppIngressSpecRuleRoutingRedirect + end + + class AppIngressSpec < BaseModel + attribute :rules, [AppIngressSpecRule] + end + + class AppEgressSpec < BaseModel + attribute :type + end + + class AppSpec < BaseModel + attribute :name + attribute :region + attribute :domains, [AppDomainSpec] + attribute :services, [AppServiceSpec] + attribute :static_sites, [AppStaticSiteSpec] + attribute :jobs, [AppJobSpec] + attribute :workers, [AppWorkerSpec] + attribute :functions, [AppFunctionSpec] + attribute :databases, [AppDatabaseSpec] + attribute :ingress, AppIngressSpec + attribute :egress, AppEgressSpec + end +end diff --git a/lib/droplet_kit/models/deployment.rb b/lib/droplet_kit/models/deployment.rb new file mode 100644 index 0000000..69d8e75 --- /dev/null +++ b/lib/droplet_kit/models/deployment.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +module DropletKit + class DeploymentJob < BaseModel + attribute :name + attribute :source_commit_hash + end + + class DeploymentFunction < BaseModel + attribute :name + attribute :source_commit_hash + attribute :namespace + end + + class DeploymentProgressStepReason < BaseModel + attribute :code + attribute :message + end + + class DeploymentProgressStep < BaseModel + attribute :component_name + attribute :ended_at + attribute :message_base + attribute :name + attribute :reason, DeploymentProgressStepReason + attribute :started_at + attribute :status + attribute :steps + end + + class DeploymentProgress < BaseModel + attribute :error_steps + attribute :pending_steps + attribute :running_steps + attribute :steps, [DeploymentProgressStep] + attribute :success_steps + attribute :summary_steps, [DeploymentProgressStep] + attribute :total_steps + end + + class DeploymentService < BaseModel + attribute :name + attribute :source_commit_hash + end + + class DeploymentStaticSite < BaseModel + attribute :name + attribute :source_commit_hash + end + + class DeploymentWorker < BaseModel + attribute :name + attribute :source_commit_hash + end + + class Deployment < BaseModel + attribute :cause + attribute :cloned_from + attribute :created_at + attribute :id + attribute :jobs, [DeploymentJob] + attribute :functions, [DeploymentFunction] + attribute :phase + attribute :phase_last_updated_at + attribute :progress, DeploymentProgress + attribute :services, [DeploymentService] + attribute :spec, AppSpec + attribute :static_sites, [DeploymentStaticSite] + attribute :tier_slug + attribute :updated_at + attribute :workers, [DeploymentWorker] + end +end diff --git a/lib/droplet_kit/resources/app_resource.rb b/lib/droplet_kit/resources/app_resource.rb new file mode 100644 index 0000000..31ffaeb --- /dev/null +++ b/lib/droplet_kit/resources/app_resource.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module DropletKit + class AppResource < ResourceKit::Resource + include ErrorHandlingResourcable + + resources do + action :all, 'GET /v2/apps' do + query_keys :per_page, :page, :with_projects + handler(200) { |response| AppMapping.extract_collection(response.body, :read) } + end + + action :find, 'GET /v2/apps/:id' do + handler(200) { |response| AppMapping.extract_single(response.body, :read) } + end + + action :create, 'POST /v2/apps' do + body { |app| AppMapping.representation_for(:create, app) } + handler(200) { |response| AppMapping.extract_single(response.body, :read) } + end + + action :update, 'PUT /v2/apps/:id' do + body { |app| AppMapping.representation_for(:update, app) } + handler(200) { |response| AppMapping.extract_single(response.body, :read) } + end + + action :delete, 'DELETE /v2/apps/:id' do + handler(200) { |response| response.body } + end + end + + def all(*args) + PaginatedResource.new(action(:all), self, *args) + end + end +end diff --git a/spec/fixtures/apps/all.json b/spec/fixtures/apps/all.json new file mode 100644 index 0000000..f62d88a --- /dev/null +++ b/spec/fixtures/apps/all.json @@ -0,0 +1,604 @@ +{ + "apps": [ + { + "id": "c2a93513-8d9b-4223-9d61-5e7272c81cf5", + "owner_uuid": "a4e16f25-cdd1-4483-b246-d77f283c9209", + "spec": { + "name": "sample-golang", + "services": [ + { + "name": "web", + "github": { + "repo": "ChiefMateStarbuck/sample-golang", + "branch": "main" + }, + "run_command": "bin/sample-golang", + "environment_slug": "go", + "instance_size_slug": "apps-s-1vcpu-0.5gb", + "instance_count": 1, + "http_port": 8080 + } + ], + "region": "ams", + "domains": [ + { + "domain": "sample-golang.example.com", + "zone": "example.com", + "minimum_tls_version": "1.3" + } + ] + }, + "default_ingress": "https://sample-golang-zyhgn.ondigitalocean.app", + "created_at": "2021-02-10T16:45:14Z", + "updated_at": "2021-02-10T17:06:56Z", + "active_deployment": { + "id": "991dfa59-6a23-459f-86d6-67dfa2c6f1e3", + "spec": { + "name": "sample-golang", + "services": [ + { + "name": "web", + "github": { + "repo": "ChiefMateStarbuck/sample-golang", + "branch": "main" + }, + "run_command": "bin/sample-golang", + "environment_slug": "go", + "instance_size_slug": "apps-s-1vcpu-0.5gb", + "instance_count": 1, + "http_port": 8080 + } + ], + "region": "ams", + "domains": [ + { + "domain": "sample-golang.example.com", + "zone": "example.com", + "minimum_tls_version": "1.3" + } + ] + }, + "services": [ + { + "name": "web", + "source_commit_hash": "db6936cb46047c576962962eed81ad52c21f35d7" + } + ], + "phase_last_updated_at": "2021-02-10T17:06:53Z", + "created_at": "2021-02-10T17:05:30Z", + "updated_at": "2021-02-10T17:06:53Z", + "cause": "manual", + "progress": { + "success_steps": 6, + "total_steps": 6, + "steps": [ + { + "name": "build", + "status": "SUCCESS", + "steps": [ + { + "name": "initialize", + "status": "SUCCESS", + "started_at": "2021-02-10T17:05:35.572347485Z", + "ended_at": "2021-02-10T17:05:36.093995229Z" + }, + { + "name": "components", + "status": "SUCCESS", + "steps": [ + { + "name": "web", + "status": "SUCCESS", + "component_name": "web", + "message_base": "Building service" + } + ], + "started_at": "2021-02-10T17:05:36.094015928Z", + "ended_at": "2021-02-10T17:06:19.461737040Z" + } + ], + "started_at": "2021-02-10T17:05:35.572287990Z", + "ended_at": "2021-02-10T17:06:19.807834070Z" + }, + { + "name": "deploy", + "status": "SUCCESS", + "steps": [ + { + "name": "initialize", + "status": "SUCCESS", + "started_at": "2021-02-10T17:06:25.143957508Z", + "ended_at": "2021-02-10T17:06:26.120343872Z" + }, + { + "name": "components", + "status": "SUCCESS", + "steps": [ + { + "name": "web", + "status": "SUCCESS", + "steps": [ + { + "name": "deploy", + "status": "SUCCESS", + "component_name": "web", + "message_base": "Deploying service" + }, + { + "name": "wait", + "status": "SUCCESS", + "component_name": "web", + "message_base": "Waiting for service" + } + ], + "component_name": "web" + } + ], + "started_at": "2021-02-10T17:06:26.120385561Z", + "ended_at": "2021-02-10T17:06:50.029695913Z" + }, + { + "name": "finalize", + "status": "SUCCESS", + "started_at": "2021-02-10T17:06:50.348459495Z", + "ended_at": "2021-02-10T17:06:53.404065961Z" + } + ], + "started_at": "2021-02-10T17:06:25.143932418Z", + "ended_at": "2021-02-10T17:06:53.404104185Z" + } + ] + }, + "phase": "ACTIVE", + "tier_slug": "basic" + }, + "last_deployment_created_at": "2021-02-10T17:05:30Z", + "live_url": "https://sample-golang-zyhgn.ondigitalocean.app", + "pending_deployment": { + "id": "3aa4d20e-5527-4c00-b496-601fbd22520a", + "spec": { + "name": "sample-php", + "services": [ + { + "name": "sample-php", + "git": { + "repo_clone_url": "https://github.com/digitalocean/sample-php.git", + "branch": "main" + }, + "run_command": "heroku-php-apache2", + "environment_slug": "php", + "instance_size_slug": "apps-s-1vcpu-0.5gb", + "instance_count": 1, + "http_port": 8080 + } + ], + "region": "fra", + "domains": [ + { + "domain": "sample-php.example.com", + "type": "PRIMARY", + "zone": "example.com", + "minimum_tls_version": "1.3" + } + ] + } + }, + "region": { + "slug": "ams", + "label": "Amsterdam", + "flag": "netherlands", + "continent": "Europe", + "data_centers": ["ams3"] + }, + "tier_slug": "basic", + "live_url_base": "https://sample-golang-zyhgn.ondigitalocean.app", + "live_domain": "sample-golang-zyhgn.ondigitalocean.app", + "project_id": "88b72d1a-b78a-4d9f-9090-b53c4399073f", + "domains": [ + { + "id": "e206c64e-a1a3-11ed-9e6e-9b7b6dc9a52b", + "phase": "CONFIGURING", + "spec": { + "domain": "sample-golang.example.com", + "type": "PRIMARY", + "zone": "example.com", + "minimum_tls_version": "1.3" + }, + "rotate_validation_records": false, + "certificate_expires_at": "2024-01-29T23:59:59Z", + "progress": { + "steps": [ + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "default-ingress-ready", + "started_at": "2023-01-30T22:15:45.021896292Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-zone", + "started_at": "2023-01-30T22:15:45.022017004Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:42:28.50752065Z", + "name": "ensure-ns-records", + "started_at": "2023-01-30T22:15:45.025567874Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "verify-nameservers", + "started_at": "2023-01-30T22:15:45.033591906Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-record", + "started_at": "2023-01-30T22:15:45.156750604Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.258626422Z", + "name": "ensure-alias-record", + "started_at": "2023-01-30T22:15:45.165933869Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.258808279Z", + "name": "ensure-wildcard-record", + "started_at": "2023-01-30T22:15:45.166093422Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "verify-cname", + "started_at": "2023-01-30T22:15:45.166205559Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.475903785Z", + "name": "ensure-ssl-txt-record-saved", + "started_at": "2023-01-30T22:15:45.295237186Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.476017236Z", + "name": "ensure-ssl-txt-record", + "started_at": "2023-01-30T22:15:45.295315291Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.476094058Z", + "name": "ensure-renewal-email", + "started_at": "2023-01-30T22:15:45.295374087Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-CA-authorization", + "started_at": "2023-01-30T22:15:45.295428101Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-certificate", + "started_at": "2023-01-30T22:15:45.978756406Z", + "status": "RUNNING" + }, + { + "ended_at": "0001-01-01T00:00:00", + "name": "create-deployment", + "started_at": "0001-01-01T00:00:00Z", + "status": "PENDING" + }, + { + "ended_at": "0001-01-01T00:00:00", + "name": "configuration-alert", + "started_at": "0001-01-01T00:00:00", + "status": "PENDING" + } + ] + } + } + ], + "dedicated_ips": [ + { + "ip": "192.168.1.1", + "id": "c24d8f48-3bc4-49f5-8ca0-58e8164427ac", + "status": "ASSIGNED" + }, + { + "ip": "192.168.1.2", + "id": "4768fb15-2837-4dda-9be5-3951df4bc3d0", + "status": "ASSIGNED" + } + ] + }, + { + "id": "4f6c71e2-1e90-4762-9fee-6cc4a0a9f2cf", + "owner_uuid": "ff36cbc6fd350fe12577f5123133bb5ba01a2419", + "spec": { + "name": "sample-php", + "services": [ + { + "name": "sample-php", + "git": { + "repo_clone_url": "https://github.com/digitalocean/sample-php.git", + "branch": "main" + }, + "run_command": "heroku-php-apache2", + "environment_slug": "php", + "instance_size_slug": "apps-s-1vcpu-0.5gb", + "instance_count": 1, + "http_port": 8080 + } + ], + "domains": [ + { + "domain": "sample-php.example.com", + "type": "PRIMARY", + "zone": "example.com", + "minimum_tls_version": "1.3" + } + ] + }, + "default_ingress": "https://sample-php-iaj87.ondigitalocean.app", + "created_at": "2020-11-19T20:27:18Z", + "updated_at": "2020-12-01T00:42:16Z", + "active_deployment": { + "id": "3aa4d20e-5527-4c00-b496-601fbd22520a", + "spec": { + "name": "sample-php", + "services": [ + { + "name": "sample-php", + "git": { + "repo_clone_url": "https://github.com/digitalocean/sample-php.git", + "branch": "main" + }, + "run_command": "heroku-php-apache2", + "environment_slug": "php", + "instance_size_slug": "apps-s-1vcpu-0.5gb", + "instance_count": 1, + "http_port": 8080 + } + ], + "region": "fra", + "domains": [ + { + "domain": "sample-php.example.com", + "type": "PRIMARY", + "zone": "example.com", + "minimum_tls_version": "1.3" + } + ] + }, + "services": [ + { + "name": "sample-php", + "source_commit_hash": "54d4a727f457231062439895000d45437c7bb405" + } + ], + "phase_last_updated_at": "2020-12-01T00:42:12Z", + "created_at": "2020-12-01T00:40:05Z", + "updated_at": "2020-12-01T00:42:12Z" + }, + "cause": "app spec updated", + "pending_deployment": { + "id": "3aa4d20e-5527-4c00-b496-601fbd22520a", + "spec": { + "name": "sample-php", + "services": [ + { + "name": "sample-php", + "git": { + "repo_clone_url": "https://github.com/digitalocean/sample-php.git", + "branch": "main" + }, + "run_command": "heroku-php-apache2", + "environment_slug": "php", + "instance_size_slug": "apps-s-1vcpu-0.5gb", + "instance_count": 1, + "http_port": 8080 + } + ], + "region": "fra", + "domains": [ + { + "domain": "sample-php.example.com", + "type": "PRIMARY", + "zone": "example.com", + "minimum_tls_version": "1.3" + } + ] + }, + "services": [ + { + "name": "sample-php", + "source_commit_hash": "54d4a727f457231062439895000d45437c7bb405" + } + ], + "phase_last_updated_at": "2020-12-01T00:42:12Z", + "created_at": "2020-12-01T00:40:05Z", + "updated_at": "2020-12-01T00:42:12Z" + }, + "progress": { + "success_steps": 6, + "total_steps": 6, + "steps": [ + { + "name": "build", + "status": "SUCCESS", + "steps": [ + { + "name": "initialize", + "status": "SUCCESS", + "started_at": "2020-12-01T00:40:11.979305214Z", + "ended_at": "2020-12-01T00:40:12.470972033Z" + }, + { + "name": "components", + "status": "SUCCESS", + "steps": [ + { + "name": "sample-php", + "status": "SUCCESS", + "started_at": "0001-01-01T00:00:00Z", + "ended_at": "0001-01-01T00:00:00Z", + "component_name": "sample-php", + "message_base": "Building service" + } + ], + "started_at": "2020-12-01T00:40:12.470996857Z", + "ended_at": "2020-12-01T00:41:26.180360487Z" + } + ], + "started_at": "2020-12-01T00:40:11.979257919Z", + "ended_at": "2020-12-01T00:41:26.653989756Z" + } + ], + "phase": "ACTIVE", + "tier_slug": "basic" + }, + "last_deployment_created_at": "2020-12-01T00:40:05Z", + "live_url": "https://sample-php.example.com", + "region": { + "slug": "fra", + "label": "Frankfurt", + "flag": "germany", + "continent": "Europe", + "data_centers": ["fra1"] + }, + "tier_slug": "basic", + "live_url_base": "https://sample-php.example.com", + "live_domain": "sample-php.example.com", + "domains": [ + { + "id": "0831f444-a1a7-11ed-828c-ef59494480b5", + "phase": "ACTIVE", + "spec": { + "domain": "sample-php.example.com", + "type": "PRIMARY", + "zone": "example.com", + "minimum_tls_version": "1.3" + }, + "rotate_validation_records": false, + "certificate_expires_at": "2024-01-29T23:59:59Z", + "progress": { + "steps": [ + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "default-ingress-ready", + "started_at": "2023-01-30T22:15:45.021896292Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-zone", + "started_at": "2023-01-30T22:15:45.022017004Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:42:28.50752065Z", + "name": "ensure-ns-records", + "started_at": "2023-01-30T22:15:45.025567874Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "verify-nameservers", + "started_at": "2023-01-30T22:15:45.033591906Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-record", + "started_at": "2023-01-30T22:15:45.156750604Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.258626422Z", + "name": "ensure-alias-record", + "started_at": "2023-01-30T22:15:45.165933869Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.258808279Z", + "name": "ensure-wildcard-record", + "started_at": "2023-01-30T22:15:45.166093422Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "verify-cname", + "started_at": "2023-01-30T22:15:45.166205559Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.475903785Z", + "name": "ensure-ssl-txt-record-saved", + "started_at": "2023-01-30T22:15:45.295237186Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.476017236Z", + "name": "ensure-ssl-txt-record", + "started_at": "2023-01-30T22:15:45.295315291Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.476094058Z", + "name": "ensure-renewal-email", + "started_at": "2023-01-30T22:15:45.295374087Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-CA-authorization", + "started_at": "2023-01-30T22:15:45.295428101Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-certificate", + "started_at": "2023-01-30T22:15:45.978756406Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:52.570612857Z", + "name": "create-deployment", + "started_at": "0001-01-01T00:00:00Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:31.333582377Z", + "name": "configuration-alert", + "started_at": "2023-01-30T22:15:46.278987808Z", + "status": "SUCCESS" + } + ] + } + } + ], + "dedicated_ips": [ + { + "ip": "192.168.1.1", + "id": "c24d8f48-3bc4-49f5-8ca0-58e8164427ac", + "status": "ASSIGNED" + }, + { + "ip": "192.168.1.2", + "id": "4768fb15-2837-4dda-9be5-3951df4bc3d0", + "status": "ASSIGNED" + } + ] + } + ], + "links": { + "pages": {} + }, + "meta": { + "total": 1 + } +} diff --git a/spec/fixtures/apps/delete.json b/spec/fixtures/apps/delete.json new file mode 100644 index 0000000..0191af5 --- /dev/null +++ b/spec/fixtures/apps/delete.json @@ -0,0 +1 @@ +{"id": "b7d64052-3706-4cb7-b21a-c5a2f44e63b3"} \ No newline at end of file diff --git a/spec/fixtures/apps/find.json b/spec/fixtures/apps/find.json new file mode 100644 index 0000000..2c52ffc --- /dev/null +++ b/spec/fixtures/apps/find.json @@ -0,0 +1,317 @@ +{ + "app": { + "id": "c2a93513-8d9b-4223-9d61-5e7272c81cf5", + "owner_uuid": "a4e16f25-cdd1-4483-b246-d77f283c9209", + "spec": { + "name": "sample-golang", + "services": [ + { + "name": "web", + "github": { + "repo": "ChiefMateStarbuck/sample-golang", + "branch": "main" + }, + "run_command": "bin/sample-golang", + "environment_slug": "go", + "instance_size_slug": "apps-s-1vcpu-0.5gb", + "instance_count": 1, + "http_port": 8080 + } + ], + "region": "ams", + "domains": [ + { + "domain": "sample-golang.example.com", + "zone": "example.com", + "minimum_tls_version": "1.3" + } + ] + }, + "default_ingress": "https://sample-golang-zyhgn.ondigitalocean.app", + "created_at": "2021-02-10T16:45:14Z", + "updated_at": "2021-02-10T17:06:56Z", + "active_deployment": { + "id": "991dfa59-6a23-459f-86d6-67dfa2c6f1e3", + "spec": { + "name": "sample-golang", + "services": [ + { + "name": "web", + "github": { + "repo": "ChiefMateStarbuck/sample-golang", + "branch": "main" + }, + "run_command": "bin/sample-golang", + "environment_slug": "go", + "instance_size_slug": "apps-s-1vcpu-0.5gb", + "instance_count": 1, + "http_port": 8080 + } + ], + "region": "ams", + "domains": [ + { + "domain": "sample-golang.example.com", + "zone": "example.com", + "minimum_tls_version": "1.3" + } + ] + }, + "services": [ + { + "name": "web", + "source_commit_hash": "db6936cb46047c576962962eed81ad52c21f35d7" + } + ], + "phase_last_updated_at": "2021-02-10T17:06:53Z", + "created_at": "2021-02-10T17:05:30Z", + "updated_at": "2021-02-10T17:06:53Z", + "cause": "manual", + "progress": { + "success_steps": 6, + "total_steps": 6, + "steps": [ + { + "name": "build", + "status": "SUCCESS", + "steps": [ + { + "name": "initialize", + "status": "SUCCESS", + "started_at": "2021-02-10T17:05:35.572347485Z", + "ended_at": "2021-02-10T17:05:36.093995229Z" + }, + { + "name": "components", + "status": "SUCCESS", + "steps": [ + { + "name": "web", + "status": "SUCCESS", + "component_name": "web", + "message_base": "Building service" + } + ], + "started_at": "2021-02-10T17:05:36.094015928Z", + "ended_at": "2021-02-10T17:06:19.461737040Z" + } + ], + "started_at": "2021-02-10T17:05:35.572287990Z", + "ended_at": "2021-02-10T17:06:19.807834070Z" + }, + { + "name": "deploy", + "status": "SUCCESS", + "steps": [ + { + "name": "initialize", + "status": "SUCCESS", + "started_at": "2021-02-10T17:06:25.143957508Z", + "ended_at": "2021-02-10T17:06:26.120343872Z" + }, + { + "name": "components", + "status": "SUCCESS", + "steps": [ + { + "name": "web", + "status": "SUCCESS", + "steps": [ + { + "name": "deploy", + "status": "SUCCESS", + "component_name": "web", + "message_base": "Deploying service" + }, + { + "name": "wait", + "status": "SUCCESS", + "component_name": "web", + "message_base": "Waiting for service" + } + ], + "component_name": "web" + } + ], + "started_at": "2021-02-10T17:06:26.120385561Z", + "ended_at": "2021-02-10T17:06:50.029695913Z" + }, + { + "name": "finalize", + "status": "SUCCESS", + "started_at": "2021-02-10T17:06:50.348459495Z", + "ended_at": "2021-02-10T17:06:53.404065961Z" + } + ], + "started_at": "2021-02-10T17:06:25.143932418Z", + "ended_at": "2021-02-10T17:06:53.404104185Z" + } + ] + }, + "phase": "ACTIVE", + "tier_slug": "basic" + }, + "last_deployment_created_at": "2021-02-10T17:05:30Z", + "live_url": "https://sample-golang-zyhgn.ondigitalocean.app", + "pending_deployment": { + "id": "3aa4d20e-5527-4c00-b496-601fbd22520a", + "spec": { + "name": "sample-php", + "services": [ + { + "name": "sample-php", + "git": { + "repo_clone_url": "https://github.com/digitalocean/sample-php.git", + "branch": "main" + }, + "run_command": "heroku-php-apache2", + "environment_slug": "php", + "instance_size_slug": "apps-s-1vcpu-0.5gb", + "instance_count": 1, + "http_port": 8080 + } + ], + "region": "fra", + "domains": [ + { + "domain": "sample-php.example.com", + "type": "PRIMARY", + "zone": "example.com", + "minimum_tls_version": "1.3" + } + ] + } + }, + "region": { + "slug": "ams", + "label": "Amsterdam", + "flag": "netherlands", + "continent": "Europe", + "data_centers": ["ams3"] + }, + "tier_slug": "basic", + "live_url_base": "https://sample-golang-zyhgn.ondigitalocean.app", + "live_domain": "sample-golang-zyhgn.ondigitalocean.app", + "project_id": "88b72d1a-b78a-4d9f-9090-b53c4399073f", + "domains": [ + { + "id": "e206c64e-a1a3-11ed-9e6e-9b7b6dc9a52b", + "phase": "CONFIGURING", + "spec": { + "domain": "sample-golang.example.com", + "type": "PRIMARY", + "zone": "example.com", + "minimum_tls_version": "1.3" + }, + "rotate_validation_records": false, + "certificate_expires_at": "2024-01-29T23:59:59Z", + "progress": { + "steps": [ + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "default-ingress-ready", + "started_at": "2023-01-30T22:15:45.021896292Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-zone", + "started_at": "2023-01-30T22:15:45.022017004Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:42:28.50752065Z", + "name": "ensure-ns-records", + "started_at": "2023-01-30T22:15:45.025567874Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "verify-nameservers", + "started_at": "2023-01-30T22:15:45.033591906Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-record", + "started_at": "2023-01-30T22:15:45.156750604Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.258626422Z", + "name": "ensure-alias-record", + "started_at": "2023-01-30T22:15:45.165933869Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.258808279Z", + "name": "ensure-wildcard-record", + "started_at": "2023-01-30T22:15:45.166093422Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "verify-cname", + "started_at": "2023-01-30T22:15:45.166205559Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.475903785Z", + "name": "ensure-ssl-txt-record-saved", + "started_at": "2023-01-30T22:15:45.295237186Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.476017236Z", + "name": "ensure-ssl-txt-record", + "started_at": "2023-01-30T22:15:45.295315291Z", + "status": "SUCCESS" + }, + { + "ended_at": "2023-01-30T15:43:30.476094058Z", + "name": "ensure-renewal-email", + "started_at": "2023-01-30T22:15:45.295374087Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-CA-authorization", + "started_at": "2023-01-30T22:15:45.295428101Z", + "status": "SUCCESS" + }, + { + "ended_at": "0001-01-01T00:00:00Z", + "name": "ensure-certificate", + "started_at": "2023-01-30T22:15:45.978756406Z", + "status": "RUNNING" + }, + { + "ended_at": "0001-01-01T00:00:00", + "name": "create-deployment", + "started_at": "0001-01-01T00:00:00Z", + "status": "PENDING" + }, + { + "ended_at": "0001-01-01T00:00:00", + "name": "configuration-alert", + "started_at": "0001-01-01T00:00:00", + "status": "PENDING" + } + ] + } + } + ], + "dedicated_ips": [ + { + "ip": "192.168.1.1", + "id": "c24d8f48-3bc4-49f5-8ca0-58e8164427ac", + "status": "ASSIGNED" + }, + { + "ip": "192.168.1.2", + "id": "4768fb15-2837-4dda-9be5-3951df4bc3d0", + "status": "ASSIGNED" + } + ] + } +} diff --git a/spec/lib/droplet_kit/resources/app_resource_spec.rb b/spec/lib/droplet_kit/resources/app_resource_spec.rb new file mode 100644 index 0000000..f26ba71 --- /dev/null +++ b/spec/lib/droplet_kit/resources/app_resource_spec.rb @@ -0,0 +1,172 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe DropletKit::AppResource do + subject(:resource) { described_class.new(connection: connection) } + + include_context 'resources' + + let(:app_uuid) { 'c2a93513-8d9b-4223-9d61-5e7272c81cf5' } + + RSpec::Matchers.define :match_app_fixture do + match do |app| + expect(app.id).to eq('c2a93513-8d9b-4223-9d61-5e7272c81cf5') + expect(app.owner_uuid).to eq('a4e16f25-cdd1-4483-b246-d77f283c9209') + expect(app.spec.name).to eq('sample-golang') + expect(app.spec.services.first.name).to eq('web') + expect(app.spec.services.first.github.repo).to eq('ChiefMateStarbuck/sample-golang') + expect(app.spec.services.first.github.branch).to eq('main') + expect(app.spec.services.first.run_command).to eq('bin/sample-golang') + expect(app.spec.services.first.environment_slug).to eq('go') + expect(app.spec.services.first.instance_size_slug).to eq('apps-s-1vcpu-0.5gb') + expect(app.spec.services.first.instance_count).to eq(1) + expect(app.spec.services.first.http_port).to eq(8080) + expect(app.spec.region).to eq('ams') + expect(app.spec.domains.first.domain).to eq('sample-golang.example.com') + expect(app.spec.domains.first.zone).to eq('example.com') + expect(app.spec.domains.first.minimum_tls_version).to eq('1.3') + expect(app.default_ingress).to eq('https://sample-golang-zyhgn.ondigitalocean.app') + expect(app.created_at).to eq('2021-02-10T16:45:14Z') + expect(app.updated_at).to eq('2021-02-10T17:06:56Z') + expect(app.active_deployment.id).to eq('991dfa59-6a23-459f-86d6-67dfa2c6f1e3') + expect(app.active_deployment.spec.services.first.name).to eq('web') + expect(app.active_deployment.services.first.source_commit_hash).to eq('db6936cb46047c576962962eed81ad52c21f35d7') + expect(app.active_deployment.phase).to eq('ACTIVE') + expect(app.last_deployment_created_at).to eq('2021-02-10T17:05:30Z') + expect(app.live_url).to eq('https://sample-golang-zyhgn.ondigitalocean.app') + expect(app.pending_deployment.id).to eq('3aa4d20e-5527-4c00-b496-601fbd22520a') + expect(app.pending_deployment.spec.services.first.name).to eq('sample-php') + expect(app.pending_deployment.spec.services.first.git.repo_clone_url).to eq( + 'https://github.com/digitalocean/sample-php.git' + ) + expect(app.pending_deployment.spec.services.first.git.branch).to eq('main') + expect(app.pending_deployment.spec.services.first.run_command).to eq('heroku-php-apache2') + expect(app.pending_deployment.spec.services.first.environment_slug).to eq('php') + expect(app.pending_deployment.spec.services.first.instance_size_slug).to eq('apps-s-1vcpu-0.5gb') + expect(app.pending_deployment.spec.services.first.instance_count).to eq(1) + expect(app.pending_deployment.spec.services.first.http_port).to eq(8080) + expect(app.pending_deployment.spec.region).to eq('fra') + expect(app.pending_deployment.spec.domains.first.domain).to eq('sample-php.example.com') + expect(app.pending_deployment.spec.domains.first.type).to eq('PRIMARY') + expect(app.pending_deployment.spec.domains.first.zone).to eq('example.com') + expect(app.pending_deployment.spec.domains.first.minimum_tls_version).to eq('1.3') + expect(app.region.slug).to eq('ams') + expect(app.region.label).to eq('Amsterdam') + expect(app.region.flag).to eq('netherlands') + expect(app.region.continent).to eq('Europe') + expect(app.region.data_centers).to eq(['ams3']) + expect(app.tier_slug).to eq('basic') + expect(app.live_url_base).to eq('https://sample-golang-zyhgn.ondigitalocean.app') + expect(app.live_domain).to eq('sample-golang-zyhgn.ondigitalocean.app') + expect(app.project_id).to eq('88b72d1a-b78a-4d9f-9090-b53c4399073f') + expect(app.domains.first.id).to eq('e206c64e-a1a3-11ed-9e6e-9b7b6dc9a52b') + expect(app.domains.first.phase).to eq('CONFIGURING') + expect(app.domains.first.spec.domain).to eq('sample-golang.example.com') + expect(app.domains.first.spec.type).to eq('PRIMARY') + expect(app.domains.first.spec.zone).to eq('example.com') + expect(app.domains.first.spec.minimum_tls_version).to eq('1.3') + expect(app.domains.first.rotate_validation_records).to be_falsey + expect(app.domains.first.certificate_expires_at).to eq('2024-01-29T23:59:59Z') + expect(app.dedicated_ips.map(&:ip)).to contain_exactly('192.168.1.1', '192.168.1.2') + expect(app.dedicated_ips.map(&:status)).to all(eq('ASSIGNED')) + end + end + + describe '#find' do + it 'returns app' do + stub_do_api("/v2/apps/#{app_uuid}", :get).to_return(body: api_fixture('apps/find')) + app = resource.find(id: app_uuid) + + expect(app).to match_app_fixture + end + end + + describe '#all' do + it 'returns all of the apps' do + stub_do_api('/v2/apps', :get).to_return(body: api_fixture('apps/all')) + apps = resource.all + + expect(apps).to all(be_a(DropletKit::App)) + expect(apps.first).to match_app_fixture + end + + it 'returns all of the apps with with projects' do + stub_do_api('/v2/apps', :get).with(query: hash_including({ 'with_projects' => 'true' })).to_return( + body: api_fixture('apps/all') + ) + apps = resource.all(with_projects: true) + + expect(apps).to all(be_a(DropletKit::App)) + expect(apps.first).to match_app_fixture + end + + it_behaves_like 'a paginated index' do + let(:fixture_path) { 'apps/all' } + let(:api_path) { '/v2/apps' } + end + end + + context 'when creating, updating, and deleting' do + let(:app) do + DropletKit::App.new( + spec: DropletKit::AppSpec.new( + name: 'web-app', + region: 'nyc', + services: [ + DropletKit::AppServiceSpec.new( + name: 'api', + github: DropletKit::AppGitHubSourceSpec.new( + branch: 'main', + deploy_on_push: true, + repo: 'digitalocean/sample-golang' + ), + run_command: 'bin/api', + environment_slug: 'node-js', + instance_count: 2, + instance_size_slug: 'apps-s-1vcpu-0.5gb' + ) + ], + egress: DropletKit::AppEgressSpec.new( + type: 'DEDICATED_IP' + ) + ), + project_id: '88b72d1a-b78a-4d9f-9090-b53c4399073f', + update_all_source_versions: true + ) + end + + describe '#create' do + let(:path) { '/v2/apps' } + + it 'returns created app' do + json_body = DropletKit::AppMapping.representation_for(:create, app) + stub_do_api(path, :post).with(body: json_body).to_return(body: api_fixture('apps/find'), status: 200) + + expect(resource.create(app)).to match_app_fixture + end + end + + describe '#update' do + let(:path) { '/v2/apps' } + + it 'returns updated app' do + json_body = DropletKit::AppMapping.representation_for(:update, app) + stub_do_api("/v2/apps/#{app_uuid}", :put).with(body: json_body).to_return( + body: api_fixture('apps/find'), status: 200 + ) + + expect(resource.update(app, id: app_uuid)).to match_app_fixture + end + end + + describe '#delete' do + it 'returns the deleted app id' do + stub_do_api("/v2/apps/#{app_uuid}", :delete).to_return(body: api_fixture('apps/delete'), status: 200) + + result = resource.delete(id: app_uuid) + expect(result).to eq('{"id": "b7d64052-3706-4cb7-b21a-c5a2f44e63b3"}') + end + end + end +end