Commit 724f19ba authored by Krasimir Angelov's avatar Krasimir Angelov Committed by Kamil Trzciński

Add new API endpoint to expose single environment

This is resolving https://gitlab.com/gitlab-org/gitlab-ce/issues/30157.

Implement new API endpoint `/projects/:id/environments/:environment_id`
to expose single environment. Include information for environment's last
deployment if there is one.
parent e70fae8d
---
title: 'Add new API endpoint to expose a single environment.'
merge_request: 26887
author:
type: added
......@@ -29,6 +29,111 @@ Example response:
]
```
## Get a specific environment
```
GET /projects/:id/environments/:environment_id
```
| Attribute | Type | Required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `environment_id` | integer | yes | The ID of the environment |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/environments/1"
```
Example of response
```json
{
"id": 1,
"name": "review/fix-foo",
"slug": "review-fix-foo-dfjre3",
"external_url": "https://review-fix-foo-dfjre3.example.gitlab.com"
"last_deployment": {
"id": 100,
"iid": 34,
"ref": "fdroid",
"sha": "416d8ea11849050d3d1f5104cf8cf51053e790ab",
"created_at": "2019-03-25T18:55:13.252Z",
"user": {
"id": 1,
"name": "Administrator",
"state": "active",
"username": "root",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://localhost:3000/root"
}
"deployable": {
"id": 710,
"status": "success",
"stage": "deploy",
"name": "staging",
"ref": "fdroid",
"tag": false,
"coverage": null,
"created_at": "2019-03-25T18:55:13.215Z",
"started_at": "2019-03-25T12:54:50.082Z",
"finished_at": "2019-03-25T18:55:13.216Z",
"duration": 21623.13423,
"user": {
"id": 1,
"name": "Administrator",
"username": "root",
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.dev/root",
"created_at": "2015-12-21T13:14:24.077Z",
"bio": null,
"location": null,
"public_email": "",
"skype": "",
"linkedin": "",
"twitter": "",
"website_url": "",
"organization": null
}
"commit": {
"id": "416d8ea11849050d3d1f5104cf8cf51053e790ab",
"short_id": "416d8ea1",
"created_at": "2016-01-02T15:39:18.000Z",
"parent_ids": [
"e9a4449c95c64358840902508fc827f1a2eab7df"
],
"title": "Removed fabric to fix #40",
"message": "Removed fabric to fix #40\n",
"author_name": "Administrator",
"author_email": "admin@example.com",
"authored_date": "2016-01-02T15:39:18.000Z",
"committer_name": "Administrator",
"committer_email": "admin@example.com",
"committed_date": "2016-01-02T15:39:18.000Z"
},
"pipeline": {
"id": 34,
"sha": "416d8ea11849050d3d1f5104cf8cf51053e790ab",
"ref": "fdroid",
"status": "success",
"web_url": "http://localhost:3000/Commit451/lab-coat/pipelines/34"
},
"web_url": "http://localhost:3000/Commit451/lab-coat/-/jobs/710",
"artifacts": [
{
"file_type": "trace",
"size": 1305,
"filename": "job.log",
"file_format": null
}
],
"runner": null,
"artifacts_expire_at": null
}
}
}
```
## Create a new environment
Creates a new environment with the given name and external_url.
......
......@@ -1294,10 +1294,6 @@ module API
expose :id, :name, :slug, :external_url
end
class Environment < EnvironmentBasic
expose :project, using: Entities::BasicProjectDetails
end
class Deployment < Grape::Entity
expose :id, :iid, :ref, :sha, :created_at
expose :user, using: Entities::UserBasic
......@@ -1305,6 +1301,11 @@ module API
expose :deployable, using: Entities::Job
end
class Environment < EnvironmentBasic
expose :project, using: Entities::BasicProjectDetails
expose :last_deployment, using: Entities::Deployment, if: { last_deployment: true }
end
class LicenseBasic < Grape::Entity
expose :key, :name, :nickname
expose :url, as: :html_url
......
......@@ -101,6 +101,21 @@ module API
status 200
present environment, with: Entities::Environment, current_user: current_user
end
desc 'Get a single environment' do
success Entities::Environment
end
params do
requires :environment_id, type: Integer, desc: 'The environment ID'
end
get ':id/environments/:environment_id' do
authorize! :read_environment, user_project
environment = user_project.environments.find(params[:environment_id])
present environment, with: Entities::Environment, current_user: current_user,
except: [:project, { last_deployment: [:environment] }],
last_deployment: true
end
end
end
end
{
"type": "object",
"required": [
"file_type",
"size",
"filename",
"file_format"
],
"properties": {
"file_type": { "type": "string"},
"size": { "type": "integer"},
"filename": { "type": "string"},
"file_format": { "type": "string"}
},
"additionalProperties": false
}
{
"type": "object",
"required": [
"filename",
"size"
],
"properties": {
"filename": { "type": "string"},
"size": { "type": "integer"}
},
"additionalProperties": false
}
{
"type": "object",
"required": [
"id",
"iid",
"ref",
"sha",
"created_at",
"user",
"deployable"
],
"properties": {
"id": { "type": "integer" },
"iid": { "type": "integer" },
"ref": { "type": "string" },
"sha": { "type": "string" },
"created_at": { "type": "string" },
"user": {
"oneOf": [
{ "type": "null" },
{ "$ref": "user/basic.json" }
]
},
"deployable": {
"oneOf": [
{ "type": "null" },
{ "$ref": "job.json" }
]
}
},
"additionalProperties": false
}
{
"type": "object",
"required": [
"id",
"name",
"slug",
"external_url",
"last_deployment"
],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"slug": { "type": "string" },
"external_url": { "$ref": "../../types/nullable_string.json" },
"last_deployment": {
"oneOf": [
{ "type": "null" },
{ "$ref": "deployment.json" }
]
}
},
"additionalProperties": false
}
{
"type": "object",
"required": [
"id",
"status",
"stage",
"name",
"ref",
"tag",
"coverage",
"created_at",
"started_at",
"finished_at",
"duration",
"user",
"commit",
"pipeline",
"web_url",
"artifacts",
"artifacts_expire_at",
"runner"
],
"properties": {
"id": { "type": "integer" },
"status": { "type": "string" },
"stage": { "type": "string" },
"name": { "type": "string" },
"ref": { "type": "string" },
"tag": { "type": "boolean" },
"coverage": { "type": ["number", "null"] },
"created_at": { "type": "string" },
"started_at": { "type": ["null", "string"] },
"finished_at": { "type": ["null", "string"] },
"duration": { "type": ["null", "number"] },
"user": { "$ref": "user/basic.json" },
"commit": {
"oneOf": [
{ "type": "null" },
{ "$ref": "commit/basic.json" }
]
},
"pipeline": { "$ref": "pipeline/basic.json" },
"web_url": { "type": "string" },
"artifacts": {
"type": "array",
"items": { "$ref": "artifact.json" }
},
"artifacts_file": {
"oneOf": [
{ "type": "null" },
{ "$ref": "artifact_file.json" }
]
},
"artifacts_expire_at": { "type": ["null", "string"] },
"runner": {
"oneOf": [
{ "type": "null" },
{ "$ref": "runner.json" }
]
}
},
"additionalProperties":false
}
{
"type": "object",
"required": [
"id",
"description",
"ip_address",
"active",
"is_shared",
"name",
"online",
"status"
],
"properties": {
"id": { "type": "integer" },
"description": { "type": "string" },
"ip_address": { "type": "string" },
"active": { "type": "boolean" },
"is_shared": { "type": "boolean" },
"name": { "type": ["null", "string"] },
"online": { "type": "boolean" },
"status": { "type": "string" }
},
"additionalProperties": false
}
......@@ -32,6 +32,7 @@ describe API::Environments do
expect(json_response.first['name']).to eq(environment.name)
expect(json_response.first['external_url']).to eq(environment.external_url)
expect(json_response.first['project'].keys).to contain_exactly(*project_data_keys)
expect(json_response.first).not_to have_key("last_deployment")
end
end
......@@ -188,4 +189,25 @@ describe API::Environments do
end
end
end
describe 'GET /projects/:id/environments/:environment_id' do
context 'as member of the project' do
it 'returns project environments' do
create(:deployment, :success, project: project, environment: environment)
get api("/projects/#{project.id}/environments/#{environment.id}", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('public_api/v4/environment')
end
end
context 'as non member' do
it 'returns a 404 status code' do
get api("/projects/#{project.id}/environments/#{environment.id}", non_member)
expect(response).to have_gitlab_http_status(404)
end
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