summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMayra Cabrera <mcabrera@gitlab.com>2018-08-03 15:19:11 -0500
committerMayra Cabrera <mcabrera@gitlab.com>2018-08-04 13:02:29 -0500
commitc40451d464f9d8e82e052e42e5b3a80ee3199e51 (patch)
tree3e9770bd9f9a5611a8e541e5219e7b737d2eeb0f
parentc4be8de7ad404f30dd6bfa9c17be4b94ecaf92e6 (diff)
downloadgitlab-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.rb2
-rw-r--r--app/models/ci/build_environment_deployment.rb15
-rw-r--r--app/models/deployment.rb16
-rw-r--r--app/models/environment.rb1
-rw-r--r--app/services/create_deployment_service.rb5
-rw-r--r--changelogs/unreleased/add-ci-build-environment-deployment-relationship.yml5
-rw-r--r--db/migrate/20180803193836_create_ci_build_environment_deployments.rb19
-rw-r--r--db/schema.rb15
-rw-r--r--lib/gitlab/ci/pipeline/chain/create.rb16
-rw-r--r--spec/factories/ci/build_environment_deployments.rb11
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/create_spec.rb19
-rw-r--r--spec/models/ci/build_environment_deployment_spec.rb15
-rw-r--r--spec/models/ci/build_spec.rb2
-rw-r--r--spec/models/deployment_spec.rb26
-rw-r--r--spec/models/environment_spec.rb1
-rw-r--r--spec/services/ci/retry_build_service_spec.rb3
-rw-r--r--spec/services/create_deployment_service_spec.rb10
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