diff options
author | Mayra Cabrera <mcabrera@gitlab.com> | 2018-08-03 15:19:11 -0500 |
---|---|---|
committer | Mayra Cabrera <mcabrera@gitlab.com> | 2018-08-04 13:02:29 -0500 |
commit | c40451d464f9d8e82e052e42e5b3a80ee3199e51 (patch) | |
tree | 3e9770bd9f9a5611a8e541e5219e7b737d2eeb0f | |
parent | c4be8de7ad404f30dd6bfa9c17be4b94ecaf92e6 (diff) | |
download | gitlab-ce-add-ci-build-environment-deployment-relationship.tar.gz |
Introduce Ci::BuildEnvironmentDeployment relationshipadd-ci-build-environment-deployment-relationship
- This one is created in Pipeline::Chain::Create class, and then updated
on CreateDeploymentService
- The whole purpose of this class is to improve the performance when
fetching Ci::Build, Environments and Deployments information
Closes #49954
-rw-r--r-- | app/models/ci/build.rb | 2 | ||||
-rw-r--r-- | app/models/ci/build_environment_deployment.rb | 15 | ||||
-rw-r--r-- | app/models/deployment.rb | 16 | ||||
-rw-r--r-- | app/models/environment.rb | 1 | ||||
-rw-r--r-- | app/services/create_deployment_service.rb | 5 | ||||
-rw-r--r-- | changelogs/unreleased/add-ci-build-environment-deployment-relationship.yml | 5 | ||||
-rw-r--r-- | db/migrate/20180803193836_create_ci_build_environment_deployments.rb | 19 | ||||
-rw-r--r-- | db/schema.rb | 15 | ||||
-rw-r--r-- | lib/gitlab/ci/pipeline/chain/create.rb | 16 | ||||
-rw-r--r-- | spec/factories/ci/build_environment_deployments.rb | 11 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/chain/create_spec.rb | 19 | ||||
-rw-r--r-- | spec/models/ci/build_environment_deployment_spec.rb | 15 | ||||
-rw-r--r-- | spec/models/ci/build_spec.rb | 2 | ||||
-rw-r--r-- | spec/models/deployment_spec.rb | 26 | ||||
-rw-r--r-- | spec/models/environment_spec.rb | 1 | ||||
-rw-r--r-- | spec/services/ci/retry_build_service_spec.rb | 3 | ||||
-rw-r--r-- | spec/services/create_deployment_service_spec.rb | 10 |
17 files changed, 173 insertions, 8 deletions
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 9292929be98..9798b58b2c5 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -33,6 +33,8 @@ module Ci has_one :metadata, class_name: 'Ci::BuildMetadata' has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, inverse_of: :build + has_one :build_environment_deployment + has_one :related_environment, through: :build_environment_deployment, source: :environment accepts_nested_attributes_for :runner_session diff --git a/app/models/ci/build_environment_deployment.rb b/app/models/ci/build_environment_deployment.rb new file mode 100644 index 00000000000..e8dcd5171aa --- /dev/null +++ b/app/models/ci/build_environment_deployment.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +module Ci + class BuildEnvironmentDeployment < ActiveRecord::Base + extend Gitlab::Ci::Model + + belongs_to :build, class_name: 'Ci::Build', foreign_key: :build_id + belongs_to :environment + belongs_to :deployment + + validates :environment_id, uniqueness: { scope: :build_id } + validates :build, :environment, presence: true + + delegate :project, to: :build + end +end diff --git a/app/models/deployment.rb b/app/models/deployment.rb index 6962b54441b..ac8c7622ee0 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -8,6 +8,7 @@ class Deployment < ActiveRecord::Base belongs_to :environment, required: true belongs_to :user belongs_to :deployable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations + has_one :build_environment_deployment, class_name: 'Ci::BuildEnvironmentDeployment' has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.deployments&.maximum(:iid) } @@ -116,6 +117,14 @@ class Deployment < ActiveRecord::Base metrics&.merge(deployment_time: created_at.to_i) || {} end + def update_build_environment_relationship(build_id) + build_environment_deployment = find_build_environment_relationship(build_id) + + return unless build_environment_deployment + + build_environment_deployment.update_attribute(:deployment, self) + end + private def prometheus_adapter @@ -125,4 +134,11 @@ class Deployment < ActiveRecord::Base def ref_path File.join(environment.ref_path, 'deployments', iid.to_s) end + + def find_build_environment_relationship(build_id) + Ci::BuildEnvironmentDeployment.find_by( + environment_id: environment_id, + build_id: build_id + ) + end end diff --git a/app/models/environment.rb b/app/models/environment.rb index c8d1d378ae0..97f8e91a6e3 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -11,6 +11,7 @@ class Environment < ActiveRecord::Base has_many :deployments, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_one :last_deployment, -> { order('deployments.id DESC') }, class_name: 'Deployment' + has_one :build_environment_deployment, class_name: 'Ci::BuildEnvironmentDeployment' before_validation :nullify_external_url before_validation :generate_slug, if: ->(env) { env.slug.blank? } diff --git a/app/services/create_deployment_service.rb b/app/services/create_deployment_service.rb index bb3f605da28..3e9730ddca1 100644 --- a/app/services/create_deployment_service.rb +++ b/app/services/create_deployment_service.rb @@ -35,7 +35,7 @@ class CreateDeploymentService end def deploy - project.deployments.create( + deployment = project.deployments.create( environment: environment, ref: job.ref, tag: job.tag, @@ -43,6 +43,9 @@ class CreateDeploymentService user: job.user, deployable: job, on_stop: on_stop) + + deployment.update_build_environment_relationship(job.id) + deployment end def environment diff --git a/changelogs/unreleased/add-ci-build-environment-deployment-relationship.yml b/changelogs/unreleased/add-ci-build-environment-deployment-relationship.yml new file mode 100644 index 00000000000..f027df9ec11 --- /dev/null +++ b/changelogs/unreleased/add-ci-build-environment-deployment-relationship.yml @@ -0,0 +1,5 @@ +--- +title: Add relationship between builds, environments and deployments +merge_request: 21025 +author: +type: performance diff --git a/db/migrate/20180803193836_create_ci_build_environment_deployments.rb b/db/migrate/20180803193836_create_ci_build_environment_deployments.rb new file mode 100644 index 00000000000..0fc081155d7 --- /dev/null +++ b/db/migrate/20180803193836_create_ci_build_environment_deployments.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true +class CreateCiBuildEnvironmentDeployments < ActiveRecord::Migration + DOWNTIME = false + + def change + create_table :ci_build_environment_deployments do |t| + t.integer :build_id, null: false + t.integer :environment_id, null: false + t.integer :deployment_id + t.timestamps_with_timezone null: false + + t.foreign_key :ci_builds, column: :build_id, on_delete: :cascade + t.foreign_key :environments, column: :environment_id, on_delete: :cascade + t.foreign_key :deployments, column: :deployment_id, on_delete: :cascade + + t.index [:build_id, :environment_id], unique: true, name: 'index_ci_build_id_and_environment_id' + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 2bef2971f29..1938f1492ee 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180726172057) do +ActiveRecord::Schema.define(version: 20180803193836) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -257,6 +257,16 @@ ActiveRecord::Schema.define(version: 20180726172057) do add_index "chat_teams", ["namespace_id"], name: "index_chat_teams_on_namespace_id", unique: true, using: :btree + create_table "ci_build_environment_deployments", force: :cascade do |t| + t.integer "build_id", null: false + t.integer "environment_id", null: false + t.integer "deployment_id" + t.datetime_with_timezone "created_at", null: false + t.datetime_with_timezone "updated_at", null: false + end + + add_index "ci_build_environment_deployments", ["build_id", "environment_id"], name: "index_ci_build_id_and_environment_id", unique: true, using: :btree + create_table "ci_build_trace_chunks", id: :bigserial, force: :cascade do |t| t.integer "build_id", null: false t.integer "chunk_index", null: false @@ -2244,6 +2254,9 @@ ActiveRecord::Schema.define(version: 20180726172057) do add_foreign_key "boards", "namespaces", column: "group_id", on_delete: :cascade add_foreign_key "boards", "projects", name: "fk_f15266b5f9", on_delete: :cascade add_foreign_key "chat_teams", "namespaces", on_delete: :cascade + add_foreign_key "ci_build_environment_deployments", "ci_builds", column: "build_id", on_delete: :cascade + add_foreign_key "ci_build_environment_deployments", "deployments", on_delete: :cascade + add_foreign_key "ci_build_environment_deployments", "environments", on_delete: :cascade add_foreign_key "ci_build_trace_chunks", "ci_builds", column: "build_id", on_delete: :cascade add_foreign_key "ci_build_trace_section_names", "projects", on_delete: :cascade add_foreign_key "ci_build_trace_sections", "ci_build_trace_section_names", column: "section_name_id", name: "fk_264e112c66", on_delete: :cascade diff --git a/lib/gitlab/ci/pipeline/chain/create.rb b/lib/gitlab/ci/pipeline/chain/create.rb index f4c8d5342c1..41d1174267c 100644 --- a/lib/gitlab/ci/pipeline/chain/create.rb +++ b/lib/gitlab/ci/pipeline/chain/create.rb @@ -13,11 +13,7 @@ module Gitlab # Create environments before the pipeline starts. # pipeline.builds.each do |build| - if build.has_environment? - project.environments.find_or_create_by( - name: build.expanded_environment_name - ) - end + create_environment_objects(build) if build.has_environment? end end rescue ActiveRecord::RecordInvalid => e @@ -27,6 +23,16 @@ module Gitlab def break? !pipeline.persisted? end + + private + + def create_environment_objects(build) + environment = project.environments.find_or_create_by( + name: build.expanded_environment_name + ) + + build.create_build_environment_deployment(environment: environment) + end end end end diff --git a/spec/factories/ci/build_environment_deployments.rb b/spec/factories/ci/build_environment_deployments.rb new file mode 100644 index 00000000000..b6267d1d5d4 --- /dev/null +++ b/spec/factories/ci/build_environment_deployments.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true +FactoryBot.define do + factory :build_environment_deployment, class: Ci::BuildEnvironmentDeployment do + build factory: :ci_build + environment + + trait :with_deployment do + deployment + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb index 0edc3f315bb..3d20e321c79 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb @@ -54,4 +54,23 @@ describe Gitlab::Ci::Pipeline::Chain::Create do .to include /Failed to persist the pipeline/ end end + + context 'when build is related to environment' do + before do + pipeline.stages.build(name: 'test', position: 0, project: project) + pipeline.builds << build(:ci_build, environment: 'production') + end + + it 'creates an environment' do + expect do + step.perform! + end.to change { Environment.count }.from(0).to(1) + end + + it 'creates a build-environment-deployment relationship' do + expect do + step.perform! + end.to change { Ci::BuildEnvironmentDeployment.count }.from(0).to(1) + end + end end diff --git a/spec/models/ci/build_environment_deployment_spec.rb b/spec/models/ci/build_environment_deployment_spec.rb new file mode 100644 index 00000000000..4ff40270562 --- /dev/null +++ b/spec/models/ci/build_environment_deployment_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Ci::BuildEnvironmentDeployment, type: :model do + describe 'associations' do + it { is_expected.to belong_to(:build) } + it { is_expected.to belong_to(:environment) } + it { is_expected.to belong_to(:deployment) } + end + + describe 'validations' do + it { is_expected.to validate_presence_of(:build) } + it { is_expected.to validate_presence_of(:environment) } + end +end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 32b8755ee9a..20fa2a11320 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -23,6 +23,8 @@ describe Ci::Build do it { is_expected.to validate_presence_of(:ref) } it { is_expected.to respond_to(:has_trace?) } it { is_expected.to respond_to(:trace) } + it { is_expected.to have_one(:build_environment_deployment) } + it { is_expected.to have_one(:related_environment).through(:build_environment_deployment) } it { is_expected.to be_a(ArtifactMigratable) } diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index b335e0fbeb3..d533e5a8fa7 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -7,6 +7,7 @@ describe Deployment do it { is_expected.to belong_to(:environment) } it { is_expected.to belong_to(:user) } it { is_expected.to belong_to(:deployable) } + it { is_expected.to have_one(:build_environment_deployment) } it { is_expected.to delegate_method(:name).to(:environment).with_prefix } it { is_expected.to delegate_method(:commit).to(:project) } @@ -157,4 +158,29 @@ describe Deployment do end end end + + describe '#update_build_environment_relationship' do + let(:deployment) { create(:deployment) } + let(:build) { create(:ci_build) } + + subject { deployment.build_environment_deployment } + + context 'when the relationship exists' do + before do + create(:build_environment_deployment, build: build, environment: deployment.environment) + + deployment.update_build_environment_relationship(build.id) + end + + it { is_expected.to be_present } + end + + context 'when the relationship does not exist' do + before do + deployment.update_build_environment_relationship(build.id) + end + + it { is_expected.to be_nil } + end + end end diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index c65e0b81451..023307cd032 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -6,6 +6,7 @@ describe Environment do it { is_expected.to belong_to(:project) } it { is_expected.to have_many(:deployments) } + it { is_expected.to have_one(:build_environment_deployment) } it { is_expected.to delegate_method(:stop_action).to(:last_deployment) } it { is_expected.to delegate_method(:manual_actions).to(:last_deployment) } diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 18d52082399..272a404a674 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -32,7 +32,8 @@ describe Ci::RetryBuildService do runner_id tag_taggings taggings tags trigger_request_id user_id auto_canceled_by_id retried failure_reason artifacts_file_store artifacts_metadata_store - metadata runner_session trace_chunks].freeze + metadata runner_session trace_chunks build_environment_deployment + related_environment].freeze shared_examples 'build duplication' do let(:another_pipeline) { create(:ci_empty_pipeline, project: project) } diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb index b9bfbb11511..1ac6e4e05ee 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/create_deployment_service_spec.rb @@ -124,6 +124,16 @@ describe CreateDeploymentService do expect(Deployment.count).to be_zero end end + + context 'when build-environment relationship exists' do + before do + create(:build_environment_deployment, build: job, environment: environment) + end + + it 'updates the relationship' do + expect(subject).to eq(job.build_environment_deployment.deployment) + end + end end describe '#expanded_environment_url' do |