Add deployment information in job API

closes https://gitlab.com/gitlab-org/gitlab-ce/issues/50460
This commit is contained in:
Steve Azzopardi 2018-08-20 15:15:53 +02:00
parent c7d1eef671
commit 3bc5f71133
No known key found for this signature in database
GPG key ID: 605BD4706E7DB47D
12 changed files with 245 additions and 47 deletions

View file

@ -654,8 +654,31 @@ module Ci
end
end
# Virtual deployment status depending on the environment status.
def deployment_status
return nil unless starts_environment?
if success?
return successful_deployment_status
elsif complete? && !success?
return :failed
end
:creating
end
private
def successful_deployment_status
if success? && last_deployment&.last?
return :last
elsif success? && last_deployment.present?
return :out_of_date
end
:creating
end
def each_test_report
Ci::JobArtifact::TEST_REPORT_FILE_TYPES.each do |file_type|
public_send("job_artifacts_#{file_type}").each_blob do |blob| # rubocop:disable GitlabSecurity/PublicSend

View file

@ -1,12 +1,26 @@
# frozen_string_literal: true
class BuildDetailsEntity < JobEntity
include EnvironmentHelper
include RequestAwareEntity
include CiStatusHelper
expose :coverage, :erased_at, :duration
expose :tag_list, as: :tags
expose :user, using: UserEntity
expose :runner, using: RunnerEntity
expose :pipeline, using: PipelineEntity
expose :deployment_status, if: -> (*) { build.has_environment? } do
expose :deployment_status, as: :status
expose :icon do |build|
ci_label_for_status(build.status)
end
expose :persisted_environment, as: :environment, with: EnvironmentEntity
end
expose :metadata, using: BuildMetadataEntity
expose :artifact, if: -> (*) { can?(current_user, :read_build, build) } do

View file

@ -0,0 +1,5 @@
---
title: Send deployment information in job API
merge_request: 21307
author:
type: other

View file

@ -86,7 +86,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
def create_job(name, status)
pipeline = create(:ci_pipeline, project: project)
create(:ci_build, :tags, :triggered, :artifacts,
pipeline: pipeline, name: name, status: status)
pipeline: pipeline, name: name, status: status)
end
end
@ -206,6 +206,29 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(json_response['status']['illustration']).to have_key('title')
end
end
context 'with no deployment' do
let(:job) { create(:ci_build, :success, pipeline: pipeline) }
it 'does not exposes the deployment information' do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['deployment_status']).to be_nil
end
end
context 'with deployment' do
let(:merge_request) { create(:merge_request, source_project: project) }
let(:environment) { create(:environment, project: project, name: 'staging', state: :available) }
let(:job) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) }
it 'exposes the deployment information' do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to match_schema('job/job_details')
expect(json_response['deployment_status']["status"]).to eq 'creating'
expect(json_response['deployment_status']["icon"]).to eq 'passed'
expect(json_response['deployment_status']["environment"]).not_to be_nil
end
end
end
context 'when requesting JSON job is triggered' do

View file

@ -1,45 +1,31 @@
{
"additionalProperties": false,
"properties": {
"created_at": {
"type": "string"
},
"id": {
"type": "integer"
},
"iid": {
"type": "integer"
},
"last?": {
"type": "boolean"
},
"ref": {
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"sha": {
"type": "string"
},
"tag": {
"type": "boolean"
}
"type": "object",
"required": [
"sha",
"created_at",
"iid",
"tag",
"last?",
"ref",
"id"
],
"properties": {
"created_at": { "type": "string" },
"id": { "type": "integer" },
"iid": { "type": "integer" },
"last?": { "type": "boolean" },
"ref": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": { "type": "string" }
},
"additionalProperties": false
},
"required": [
"sha",
"created_at",
"iid",
"tag",
"last?",
"ref",
"id"
],
"type": "object"
"sha": { "type": "string" },
"tag": { "type": "boolean" }
},
"additionalProperties": false
}

View file

@ -0,0 +1,27 @@
{
"type": "object",
"allOf": [
{ "$ref": "../public_api/v4/commit/basic.json" },
{
"type": "object",
"required": [
"author_gravatar_url",
"commit_url",
"commit_path",
"author"
],
"properties": {
"author_gravatar_url": { "type": "string" },
"commit_url": { "type": "string" },
"commit_path": { "type": "string" },
"author": {
"oneOf": [
{ "type": "null" },
{ "type": "user.json" }
]
}
},
"additionalProperties": false
}
]
}

View file

@ -5,13 +5,19 @@
"state",
"avatar_url",
"web_url",
"path"
"path",
"name",
"username"
],
"properties": {
"id": { "type": "integer" },
"state": { "type": "string" },
"avatar_url": { "type": "string" },
"web_url": { "type": "string" },
"path": { "type": "string" }
}
"path": { "type": "string" },
"name": { "type": "string" },
"username": { "type": "string" },
"status_tooltip_html": { "$ref": "../types/nullable_string.json" }
},
"additionalProperties": false
}

View file

@ -0,0 +1,38 @@
{
"type": "object",
"required": [
"id",
"name",
"state",
"external_url",
"environment_type",
"has_stop_action",
"environment_path",
"stop_path",
"folder_path",
"created_at",
"updated_at",
"can_stop"
],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"state": { "type": "string" },
"external_url": { "$ref": "types/nullable_string.json" },
"environment_type": { "$ref": "types/nullable_string.json" },
"has_stop_action": { "type": "boolean" },
"environment_path": { "type": "string" },
"stop_path": { "type": "string" },
"folder_path": { "type": "string" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" },
"can_stop": { "type": "boolean" },
"last_deployment": {
"oneOf": [
{ "type": "null" },
{ "$ref": "deployment.json" }
]
}
},
"additionalProperties": false
}

View file

@ -0,0 +1,27 @@
{
"type": "object",
"required": [
"status",
"icon",
"environment"
],
"properties": {
"status": {
"oneOf": [
{
"type": "string",
"enum": [
"last",
"creating",
"failed",
"out_of_date"
]
},
{ "type": "null" }
]
},
"icon": { "type": "string" },
"environment": { "$ref": "../environment.json" }
},
"additionalProperties": false
}

View file

@ -6,6 +6,7 @@
"properties": {
"artifact": { "$ref": "artifact.json" },
"terminal_path": { "type": "string" },
"trigger": { "$ref": "trigger.json" }
"trigger": { "$ref": "trigger.json" },
"deployment_status": { "$ref": "deployment_status.json" }
}
}

View file

@ -0,0 +1,6 @@
{
"oneOf": [
{ "type": "null" },
{ "type": "string" }
]
}

View file

@ -2981,4 +2981,46 @@ describe Ci::Build do
end
end
end
describe '#deployment_status' do
context 'when build is a last deployment' do
let(:build) { create(:ci_build, :success, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) }
it { expect(build.deployment_status).to eq(:last) }
end
context 'when there is a newer build with deployment' do
let(:build) { create(:ci_build, :success, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) }
let!(:last_deployment) { create(:deployment, environment: environment, project: environment.project) }
it { expect(build.deployment_status).to eq(:out_of_date) }
end
context 'when build with deployment has failed' do
let(:build) { create(:ci_build, :failed, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) }
it { expect(build.deployment_status).to eq(:failed) }
end
context 'when build with deployment is running' do
let(:build) { create(:ci_build, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) }
it { expect(build.deployment_status).to eq(:creating) }
end
context 'when build is successful but deployment is not ready yet' do
let(:build) { create(:ci_build, :success, environment: 'production') }
let(:environment) { create(:environment, name: 'production', project: build.project) }
it { expect(build.deployment_status).to eq(:creating) }
end
end
end