diff --git a/doc/api/environments.md b/doc/api/environments.md index f86349a55296f487d036b73f33b9d3bdc258934a..81f40cc9ec4cabdb7a454e03158f525b4f7b52f2 100644 --- a/doc/api/environments.md +++ b/doc/api/environments.md @@ -192,12 +192,13 @@ It returns `201` if the environment was successfully created, `400` for wrong pa POST /projects/:id/environments ``` -| Attribute | Type | Required | Description | -|----------------|----------------|----------|---------------------------------------------------------------------------------------------------------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path](rest/index.md#namespaced-path-encoding) of the project. | -| `name` | string | yes | The name of the environment. | -| `external_url` | string | no | Place to link to for this environment. | -| `tier` | string | no | The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`. | +| Attribute | Type | Required | Description | +|--------------------|----------------|----------|---------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path](rest/index.md#namespaced-path-encoding) of the project. | +| `name` | string | yes | The name of the environment. | +| `external_url` | string | no | Place to link to for this environment. | +| `tier` | string | no | The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`. | +| `cluster_agent_id` | integer | no | The cluster agent to associate with this environment. | ```shell curl --data "name=deploy&external_url=https://deploy.gitlab.example.com" \ @@ -231,12 +232,13 @@ It returns `200` if the environment was successfully updated. In case of an erro PUT /projects/:id/environments/:environments_id ``` -| Attribute | Type | Required | Description | -|------------------|----------------|----------|---------------------------------------------------------------------------------------------------------------------| -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). | -| `environment_id` | integer | yes | The ID of the environment. | -| `external_url` | string | no | The new `external_url`. | -| `tier` | string | no | The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`. | +| Attribute | Type | Required | Description | +|--------------------|-----------------|----------|---------------------------------------------------------------------------------------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-path-encoding). | +| `environment_id` | integer | yes | The ID of the environment. | +| `external_url` | string | no | The new `external_url`. | +| `tier` | string | no | The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`. | +| `cluster_agent_id` | integer or null | no | The cluster agent to associate with this environment or `null` to remove it. | ```shell curl --request PUT --data "external_url=https://staging.gitlab.example.com" \ diff --git a/lib/api/environments.rb b/lib/api/environments.rb index 9b9d35e3cc9783de9bd98eb708ffd9c5163341f1..0b69611d651fb6cf4f61eb6ecbe36968b1430126 100644 --- a/lib/api/environments.rb +++ b/lib/api/environments.rb @@ -66,12 +66,21 @@ class Environments < ::API::Base optional :external_url, type: String, desc: 'Place to link to for this environment' optional :slug, absence: { message: "is automatically generated and cannot be changed" }, documentation: { hidden: true } optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`' + optional :cluster_agent_id, type: Integer, desc: 'The ID of the Cluster Agent to associate with this environment' end route_setting :authentication, job_token_allowed: true post ':id/environments' do authorize! :create_environment, user_project - environment = user_project.environments.create(declared_params) + params = declared_params + + if params[:cluster_agent_id] + agent = ::Clusters::AgentsFinder.new(user_project, current_user).execute.find_by_id(params[:cluster_agent_id]) + + bad_request!("cluster agent doesn't exist or cannot be associated with this environment") unless agent + end + + environment = user_project.environments.create(params) if environment.persisted? present environment, with: Entities::Environment, current_user: current_user @@ -95,6 +104,7 @@ class Environments < ::API::Base optional :external_url, type: String, desc: 'The new URL on which this deployment is viewable' optional :slug, absence: { message: "is automatically generated and cannot be changed" }, documentation: { hidden: true } optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`' + optional :cluster_agent_id, type: Integer, desc: 'The ID of the Cluster Agent to associate with this environment' end route_setting :authentication, job_token_allowed: true put ':id/environments/:environment_id' do @@ -102,7 +112,13 @@ class Environments < ::API::Base environment = user_project.environments.find(params[:environment_id]) - update_params = declared_params(include_missing: false).extract!(:external_url, :tier) + update_params = declared_params(include_missing: false).extract!(:external_url, :tier, :cluster_agent_id) + + if update_params[:cluster_agent_id] + agent = ::Clusters::AgentsFinder.new(user_project, current_user).execute.find_by_id(params[:cluster_agent_id]) + + bad_request!("cluster agent doesn't exist or cannot be associated with this environment") unless agent + end environment.assign_attributes(update_params) diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index 3c2c92510e0891d314ee791475a92ea4810f0353..d04a3be4cd9ad53b6868a3fc8a3b8e5f2858a362 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -136,6 +136,33 @@ expect(json_response['external']).to be nil end + context 'when associating a cluster agent' do + let_it_be(:cluster_agent) { create(:cluster_agent, project: project) } + let_it_be(:foreign_cluster_agent) { create(:cluster_agent) } + + it 'creates a environment with associated cluster agent' do + post api("/projects/#{project.id}/environments", user), params: { name: "mepmep", cluster_agent_id: cluster_agent.id } + + expect(response).to have_gitlab_http_status(:created) + expect(response).to match_response_schema('public_api/v4/environment') + expect(json_response['cluster_agent']).to be_present + end + + it 'fails to create environment with a non existing cluster agent' do + post api("/projects/#{project.id}/environments", user), params: { name: "mepmep", cluster_agent_id: non_existing_record_id } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq("400 Bad request - cluster agent doesn't exist or cannot be associated with this environment") + end + + it 'fails to create environment with a foreign cluster agent' do + post api("/projects/#{project.id}/environments", user), params: { name: "mepmep", cluster_agent_id: foreign_cluster_agent.id } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq("400 Bad request - cluster agent doesn't exist or cannot be associated with this environment") + end + end + it 'returns 200 HTTP status when using JOB-TOKEN auth' do job = create(:ci_build, :running, project: project, user: user) @@ -231,8 +258,9 @@ end describe 'PUT /projects/:id/environments/:environment_id' do + let_it_be(:url) { 'https://mepmep.whatever.ninja' } + it 'returns a 200 if external_url is changed' do - url = 'https://mepmep.whatever.ninja' put api("/projects/#{project.id}/environments/#{environment.id}", user), params: { external_url: url } @@ -259,6 +287,53 @@ expect(response).to have_gitlab_http_status(:ok) end + context 'when associating a cluster agent' do + let_it_be(:cluster_agent) { create(:cluster_agent, project: project) } + let_it_be(:foreign_cluster_agent) { create(:cluster_agent) } + + it 'updates an environment with associated cluster agent' do + put api("/projects/#{project.id}/environments/#{environment.id}", user), params: { cluster_agent_id: cluster_agent.id } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/environment') + expect(json_response['cluster_agent']).to be_present + end + + it 'updates an environment to remove cluster agent' do + environment.update!(cluster_agent_id: cluster_agent.id) + + put api("/projects/#{project.id}/environments/#{environment.id}", user), params: { cluster_agent_id: nil } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/environment') + expect(json_response['cluster_agent']).not_to be_present + end + + it 'leaves cluster agent unchanged when not specified in update' do + environment.update!(cluster_agent_id: cluster_agent.id) + + put api("/projects/#{project.id}/environments/#{environment.id}", user), params: { external_url: url } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/environment') + expect(json_response['cluster_agent']).to be_present + end + + it 'fails to create environment with a non existing cluster agent' do + put api("/projects/#{project.id}/environments/#{environment.id}", user), params: { cluster_agent_id: non_existing_record_id } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq("400 Bad request - cluster agent doesn't exist or cannot be associated with this environment") + end + + it 'fails to create environment with a foreign cluster agent' do + put api("/projects/#{project.id}/environments/#{environment.id}", user), params: { cluster_agent_id: foreign_cluster_agent.id } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq("400 Bad request - cluster agent doesn't exist or cannot be associated with this environment") + end + end + it "won't allow slug to be changed" do slug = environment.slug api_url = api("/projects/#{project.id}/environments/#{environment.id}", user)