From 3bc5f7113350096263d615de07afe143f602659d Mon Sep 17 00:00:00 2001 From: Steve Azzopardi Date: Mon, 20 Aug 2018 15:15:53 +0200 Subject: [PATCH] Add deployment information in job API closes https://gitlab.com/gitlab-org/gitlab-ce/issues/50460 --- app/models/ci/build.rb | 23 ++++++ app/serializers/build_details_entity.rb | 14 ++++ ...send-deployment-information-in-job-api.yml | 5 ++ .../projects/jobs_controller_spec.rb | 25 ++++++- spec/fixtures/api/schemas/deployment.json | 70 ++++++++----------- .../fixtures/api/schemas/entities/commit.json | 27 +++++++ spec/fixtures/api/schemas/entities/user.json | 12 +++- spec/fixtures/api/schemas/environment.json | 38 ++++++++++ .../api/schemas/job/deployment_status.json | 27 +++++++ .../fixtures/api/schemas/job/job_details.json | 3 +- .../api/schemas/types/nullable_string.json | 6 ++ spec/models/ci/build_spec.rb | 42 +++++++++++ 12 files changed, 245 insertions(+), 47 deletions(-) create mode 100644 changelogs/unreleased/21307-send-deployment-information-in-job-api.yml create mode 100644 spec/fixtures/api/schemas/entities/commit.json create mode 100644 spec/fixtures/api/schemas/environment.json create mode 100644 spec/fixtures/api/schemas/job/deployment_status.json create mode 100644 spec/fixtures/api/schemas/types/nullable_string.json diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index ab738c2fad8..63aaa0f7bcc 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -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 diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb index 6f8194d9856..ab9861c58c4 100644 --- a/app/serializers/build_details_entity.rb +++ b/app/serializers/build_details_entity.rb @@ -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 diff --git a/changelogs/unreleased/21307-send-deployment-information-in-job-api.yml b/changelogs/unreleased/21307-send-deployment-information-in-job-api.yml new file mode 100644 index 00000000000..8f9e24428be --- /dev/null +++ b/changelogs/unreleased/21307-send-deployment-information-in-job-api.yml @@ -0,0 +1,5 @@ +--- +title: Send deployment information in job API +merge_request: 21307 +author: +type: other diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index b42f6419922..706f801a285 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -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 diff --git a/spec/fixtures/api/schemas/deployment.json b/spec/fixtures/api/schemas/deployment.json index 536e6475c23..8c8cdf8bcb2 100644 --- a/spec/fixtures/api/schemas/deployment.json +++ b/spec/fixtures/api/schemas/deployment.json @@ -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 } diff --git a/spec/fixtures/api/schemas/entities/commit.json b/spec/fixtures/api/schemas/entities/commit.json new file mode 100644 index 00000000000..686d29c97d2 --- /dev/null +++ b/spec/fixtures/api/schemas/entities/commit.json @@ -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 + } + ] +} diff --git a/spec/fixtures/api/schemas/entities/user.json b/spec/fixtures/api/schemas/entities/user.json index 6482e0eedd2..82d80b75cef 100644 --- a/spec/fixtures/api/schemas/entities/user.json +++ b/spec/fixtures/api/schemas/entities/user.json @@ -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 } diff --git a/spec/fixtures/api/schemas/environment.json b/spec/fixtures/api/schemas/environment.json new file mode 100644 index 00000000000..f1d33e3ce7b --- /dev/null +++ b/spec/fixtures/api/schemas/environment.json @@ -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 +} diff --git a/spec/fixtures/api/schemas/job/deployment_status.json b/spec/fixtures/api/schemas/job/deployment_status.json new file mode 100644 index 00000000000..a90b8b35654 --- /dev/null +++ b/spec/fixtures/api/schemas/job/deployment_status.json @@ -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 +} diff --git a/spec/fixtures/api/schemas/job/job_details.json b/spec/fixtures/api/schemas/job/job_details.json index b82f7413b50..ab0ade55bbe 100644 --- a/spec/fixtures/api/schemas/job/job_details.json +++ b/spec/fixtures/api/schemas/job/job_details.json @@ -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" } } } diff --git a/spec/fixtures/api/schemas/types/nullable_string.json b/spec/fixtures/api/schemas/types/nullable_string.json new file mode 100644 index 00000000000..e3b0baef849 --- /dev/null +++ b/spec/fixtures/api/schemas/types/nullable_string.json @@ -0,0 +1,6 @@ +{ + "oneOf": [ + { "type": "null" }, + { "type": "string" } + ] +} diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 42b627b6823..dbebda20ce0 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -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