Add deployment information in job API
closes https://gitlab.com/gitlab-org/gitlab-ce/issues/50460
This commit is contained in:
parent
c7d1eef671
commit
3bc5f71133
12 changed files with 245 additions and 47 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Send deployment information in job API
|
||||
merge_request: 21307
|
||||
author:
|
||||
type: other
|
|
@ -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
|
||||
|
|
70
spec/fixtures/api/schemas/deployment.json
vendored
70
spec/fixtures/api/schemas/deployment.json
vendored
|
@ -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
|
||||
}
|
||||
|
|
27
spec/fixtures/api/schemas/entities/commit.json
vendored
Normal file
27
spec/fixtures/api/schemas/entities/commit.json
vendored
Normal 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
|
||||
}
|
||||
]
|
||||
}
|
12
spec/fixtures/api/schemas/entities/user.json
vendored
12
spec/fixtures/api/schemas/entities/user.json
vendored
|
@ -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
|
||||
}
|
||||
|
|
38
spec/fixtures/api/schemas/environment.json
vendored
Normal file
38
spec/fixtures/api/schemas/environment.json
vendored
Normal 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
|
||||
}
|
27
spec/fixtures/api/schemas/job/deployment_status.json
vendored
Normal file
27
spec/fixtures/api/schemas/job/deployment_status.json
vendored
Normal 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
|
||||
}
|
|
@ -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" }
|
||||
}
|
||||
}
|
||||
|
|
6
spec/fixtures/api/schemas/types/nullable_string.json
vendored
Normal file
6
spec/fixtures/api/schemas/types/nullable_string.json
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"oneOf": [
|
||||
{ "type": "null" },
|
||||
{ "type": "string" }
|
||||
]
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue