Commit bcf2d2c2 authored by Alishan Ladhani's avatar Alishan Ladhani

Add approvals and pending_approval_count to deployments API

parent 53314815
......@@ -23,7 +23,7 @@ GET /projects/:id/deployments
| `updated_after` | datetime | no | Return deployments updated after the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
| `updated_before` | datetime | no | Return deployments updated before the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
| `environment` | string | no | The [name of the environment](../ci/environments/index.md) to filter deployments by. |
| `status` | string | no | The status to filter deployments by. One of `created`, `running`, `success`, `failed`, `canceled`.
| `status` | string | no | The status to filter deployments by. One of `created`, `running`, `success`, `failed`, `canceled`, `blocked`.
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/deployments"
......@@ -201,6 +201,7 @@ Example response:
"sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
"created_at": "2016-08-11T11:32:35.444Z",
"updated_at": "2016-08-11T11:34:01.123Z",
"status": "success",
"user": {
"name": "Administrator",
"username": "root",
......@@ -264,6 +265,29 @@ Example response:
}
```
Deployments created by users on GitLab Premium or higher include the `approvals` and `pending_approval_count` properties:
```json
{
"status": "created",
"pending_approval_count": 0,
"approvals": [
{
"user": {
"id": 49,
"username": "project_6_bot",
"name": "****",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/e83ac685f68ea07553ad3054c738c709?s=80&d=identicon",
"web_url": "http://localhost:3000/project_6_bot"
},
"status": "approved"
}
],
...
}
```
## Create a deployment
```plaintext
......@@ -311,6 +335,29 @@ Example response:
}
```
Deployments created by users on GitLab Premium or higher include the `approvals` and `pending_approval_count` properties:
```json
{
"status": "created",
"pending_approval_count": 0,
"approvals": [
{
"user": {
"id": 49,
"username": "project_6_bot",
"name": "****",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/e83ac685f68ea07553ad3054c738c709?s=80&d=identicon",
"web_url": "http://localhost:3000/project_6_bot"
},
"status": "approved"
}
],
...
}
```
## Update a deployment
```plaintext
......@@ -354,6 +401,29 @@ Example response:
}
```
Deployments created by users on GitLab Premium or higher include the `approvals` and `pending_approval_count` properties:
```json
{
"status": "created",
"pending_approval_count": 0,
"approvals": [
{
"user": {
"id": 49,
"username": "project_6_bot",
"name": "****",
"state": "active",
"avatar_url": "https://www.gravatar.com/avatar/e83ac685f68ea07553ad3054c738c709?s=80&d=identicon",
"web_url": "http://localhost:3000/project_6_bot"
},
"status": "approved"
}
],
...
}
```
## List of merge requests associated with a deployment
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35739) in GitLab 12.7.
......
......@@ -95,7 +95,11 @@ curl --data "status=approved" \
#### Using the API
Use the [Deployments API](../../api/deployments.md) to see deployments. The `status` field indicates if a deployment is blocked.
Use the [Deployments API](../../api/deployments.md) to see deployments.
- The `status` field indicates if a deployment is blocked.
- The `pending_approval_count` field indicates how many approvals are remaining to run a deployment.
- The `approvals` field contains the deployment's approvals.
## Related features
......
......@@ -32,7 +32,9 @@ module EE
end
def pending_approval_count
environment.required_approval_count - approvals.approved.count
return 0 unless blocked?
environment.required_approval_count - approvals.count
end
end
end
# frozen_string_literal: true
module EE
module API
module Entities
module DeploymentExtended
extend ActiveSupport::Concern
prepended do
expose :pending_approval_count
expose :approvals, using: ::API::Entities::Deployments::Approval
end
end
end
end
end
{
"type": "object",
"allOf": [
{
"$ref": "../../../../../../../spec/fixtures/api/schemas/public_api/v4/deployment.json"
},
{
"required": [
"pending_approval_count",
"approvals"
],
"properties": {
"pending_approval_count": {
"type": "integer"
},
"approvals": {
"type": "array",
"items": {
"$ref": "deployment_approval.json"
}
},
"additionalProperties": false
}
}
]
}
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ::EE::API::Entities::DeploymentExtended do
subject { ::API::Entities::DeploymentExtended.new(deployment).as_json }
describe '#as_json' do
let(:deployment) { create(:deployment, :blocked) }
before do
stub_licensed_features(protected_environments: true)
create(:protected_environment, project_id: deployment.environment.project_id, name: deployment.environment.name, required_approval_count: 2)
create(:deployment_approval, :approved, deployment: deployment)
end
it 'includes fields from deployment entity' do
is_expected.to include(:id, :iid, :ref, :sha, :created_at, :updated_at, :user, :environment, :deployable, :status)
end
it 'includes pending_approval_count' do
expect(subject[:pending_approval_count]).to eq(1)
end
it 'includes approvals', :aggregate_failures do
expect(subject[:approvals].length).to eq(1)
expect(subject.dig(:approvals, 0, :status)).to eq("approved")
end
end
end
......@@ -28,7 +28,7 @@ RSpec.describe Deployment do
let_it_be(:project) { create(:project, :repository) }
let(:environment) { create(:environment, project: project) }
let(:deployment) { create(:deployment, project: project, environment: environment) }
let(:deployment) { create(:deployment, :blocked, project: project, environment: environment) }
context 'when Protected Environments feature is available' do
before do
......@@ -61,6 +61,14 @@ RSpec.describe Deployment do
expect(deployment.pending_approval_count).to eq(0)
end
end
context 'with a deployment that is not blocked' do
let(:deployment) { create(:deployment, :success, project: project, environment: environment) }
it 'returns zero' do
expect(deployment.pending_approval_count).to eq(0)
end
end
end
context 'when Protected Environments feature is not available' do
......
......@@ -11,7 +11,41 @@ RSpec.describe API::Deployments do
stub_licensed_features(protected_environments: true)
end
describe 'GET /projects/:id/deployments/:id' do
let(:deployment) { create(:deployment, :blocked, project: project) }
before do
create(:deployment_approval, :approved, deployment: deployment)
project.add_developer(user)
end
it 'matches the response schema' do
get api("/projects/#{project.id}/deployments/#{deployment.id}", user)
expect(response).to have_gitlab_http_status(:success)
expect(response).to match_response_schema('public_api/v4/deployment_extended', dir: 'ee')
end
end
describe 'POST /projects/:id/deployments' do
it 'matches the response schema' do
project.add_developer(user)
post(
api("/projects/#{project.id}/deployments", user),
params: {
environment: environment.name,
sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0',
ref: 'master',
tag: false,
status: 'success'
}
)
expect(response).to have_gitlab_http_status(:success)
expect(response).to match_response_schema('public_api/v4/deployment_extended', dir: 'ee')
end
context 'when deploying to a protected environment that requires maintainer access' do
before do
create(
......@@ -114,6 +148,18 @@ RSpec.describe API::Deployments do
)
end
it 'matches the response schema' do
project.add_developer(user)
put(
api("/projects/#{project.id}/deployments/#{deploy.id}", user),
params: { status: 'success' }
)
expect(response).to have_gitlab_http_status(:success)
expect(response).to match_response_schema('public_api/v4/deployment_extended', dir: 'ee')
end
context 'when updating a deployment for a protected environment that requires maintainer access' do
before do
create(
......
......@@ -47,7 +47,7 @@ module API
desc 'Gets a specific deployment' do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::Deployment
success Entities::DeploymentExtended
end
params do
requires :deployment_id, type: Integer, desc: 'The deployment ID'
......@@ -57,12 +57,12 @@ module API
deployment = user_project.deployments.find(params[:deployment_id])
present deployment, with: Entities::Deployment
present deployment, with: Entities::DeploymentExtended
end
desc 'Creates a new deployment' do
detail 'This feature was introduced in GitLab 12.4'
success Entities::Deployment
success Entities::DeploymentExtended
end
params do
requires :environment,
......@@ -106,7 +106,7 @@ module API
deployment = service.execute
if deployment.persisted?
present(deployment, with: Entities::Deployment, current_user: current_user)
present(deployment, with: Entities::DeploymentExtended, current_user: current_user)
else
render_validation_error!(deployment)
end
......@@ -114,7 +114,7 @@ module API
desc 'Updates an existing deployment' do
detail 'This feature was introduced in GitLab 12.4'
success Entities::Deployment
success Entities::DeploymentExtended
end
params do
requires :status,
......@@ -136,7 +136,7 @@ module API
service = ::Deployments::UpdateService.new(deployment, declared_params)
if service.execute
present(deployment, with: Entities::Deployment, current_user: current_user)
present(deployment, with: Entities::DeploymentExtended, current_user: current_user)
else
render_validation_error!(deployment)
end
......
# frozen_string_literal: true
module API
module Entities
class DeploymentExtended < Deployment
end
end
end
API::Entities::DeploymentExtended.prepend_mod
......@@ -8,7 +8,8 @@
"created_at",
"updated_at",
"user",
"deployable"
"deployable",
"status"
],
"properties": {
"id": { "type": "integer" },
......@@ -30,6 +31,5 @@
]
},
"status": { "type": "string" }
},
"additionalProperties": false
}
}
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::Entities::DeploymentExtended do
describe '#as_json' do
subject { described_class.new(deployment).as_json }
let(:deployment) { create(:deployment) }
it 'includes fields from deployment entity' do
is_expected.to include(:id, :iid, :ref, :sha, :created_at, :updated_at, :user, :environment, :deployable, :status)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment