Commit 3a19c93d authored by Stan Hu's avatar Stan Hu

Merge branch 'deployment-validate-sha' into 'master'

Validate deployment SHAs and refs

Closes #36967

See merge request gitlab-org/gitlab!20849
parents 41a9166d 14420903
...@@ -23,6 +23,8 @@ class Deployment < ApplicationRecord ...@@ -23,6 +23,8 @@ class Deployment < ApplicationRecord
validates :sha, presence: true validates :sha, presence: true
validates :ref, presence: true validates :ref, presence: true
validate :valid_sha, on: :create
validate :valid_ref, on: :create
delegate :name, to: :environment, prefix: true delegate :name, to: :environment, prefix: true
...@@ -234,6 +236,18 @@ class Deployment < ApplicationRecord ...@@ -234,6 +236,18 @@ class Deployment < ApplicationRecord
end end
end end
def valid_sha
return if project&.commit(sha)
errors.add(:sha, _('The commit does not exist'))
end
def valid_ref
return if project&.commit(ref)
errors.add(:ref, _('The branch or tag does not exist'))
end
private private
def ref_path def ref_path
......
---
title: Validate deployment SHAs and refs
merge_request:
author:
type: fixed
...@@ -105,7 +105,7 @@ describe OperationsController do ...@@ -105,7 +105,7 @@ describe OperationsController do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:commit) { project.commit } let(:commit) { project.commit }
let!(:environment) { create(:environment, name: 'production', project: project) } let!(:environment) { create(:environment, name: 'production', project: project) }
let!(:deployment) { create(:deployment, :success, environment: environment, sha: commit.id, created_at: now) } let!(:deployment) { create(:deployment, :success, environment: environment, sha: commit.id, created_at: now, project: project) }
it_behaves_like 'unlicensed', :get, :list it_behaves_like 'unlicensed', :get, :list
...@@ -276,7 +276,7 @@ describe OperationsController do ...@@ -276,7 +276,7 @@ describe OperationsController do
end end
context 'with a project in the dashboard' do context 'with a project in the dashboard' do
let(:project) { create(:project, :with_avatar) } let(:project) { create(:project, :with_avatar, :repository) }
before do before do
project.add_developer(user) project.add_developer(user)
......
...@@ -5,7 +5,7 @@ require 'spec_helper' ...@@ -5,7 +5,7 @@ require 'spec_helper'
describe Environment, :use_clean_rails_memory_store_caching do describe Environment, :use_clean_rails_memory_store_caching do
include ReactiveCachingHelpers include ReactiveCachingHelpers
let(:project) { create(:project, :stubbed_repository) } let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, project: project) } let(:environment) { create(:environment, project: project) }
describe '.deployed_to_cluster' do describe '.deployed_to_cluster' do
...@@ -211,10 +211,9 @@ describe Environment, :use_clean_rails_memory_store_caching do ...@@ -211,10 +211,9 @@ describe Environment, :use_clean_rails_memory_store_caching do
end end
describe '#rollout_status' do describe '#rollout_status' do
let(:cluster) { create(:cluster, :project, :provided_by_user) } let!(:cluster) { create(:cluster, :project, :provided_by_user, projects: [project]) }
let(:project) { cluster.project } let!(:environment) { create(:environment, project: project) }
let(:environment) { create(:environment, project: project) } let!(:deployment) { create(:deployment, :success, environment: environment, project: project) }
let!(:deployment) { create(:deployment, :success, environment: environment) }
subject { environment.rollout_status } subject { environment.rollout_status }
......
...@@ -6,7 +6,7 @@ describe Ci::BuildPolicy do ...@@ -6,7 +6,7 @@ describe Ci::BuildPolicy do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0') }
describe '#update_build?' do describe '#update_build?' do
let(:environment) { create(:environment, project: project, name: 'production') } let(:environment) { create(:environment, project: project, name: 'production') }
......
...@@ -104,7 +104,6 @@ describe API::Deployments do ...@@ -104,7 +104,6 @@ describe API::Deployments do
end end
describe 'PUT /projects/:id/deployments/:deployment_id' do describe 'PUT /projects/:id/deployments/:deployment_id' do
let(:project) { create(:project) }
let(:deploy) do let(:deploy) do
create( create(
:deployment, :deployment,
......
...@@ -6,7 +6,7 @@ describe Dashboard::Environments::ListService do ...@@ -6,7 +6,7 @@ describe Dashboard::Environments::ListService do
describe '#execute' do describe '#execute' do
def setup def setup
user = create(:user) user = create(:user)
project = create(:project) project = create(:project, :repository)
project.add_developer(user) project.add_developer(user)
user.update!(ops_dashboard_projects: [project]) user.update!(ops_dashboard_projects: [project])
......
...@@ -14,7 +14,7 @@ RSpec.shared_examples 'additional custom metrics query' do ...@@ -14,7 +14,7 @@ RSpec.shared_examples 'additional custom metrics query' do
let(:client) { double('prometheus_client') } let(:client) { double('prometheus_client') }
let(:query_result) { described_class.new(client).query(*query_params) } let(:query_result) { described_class.new(client).query(*query_params) }
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, slug: 'environment-slug', project: project) } let(:environment) { create(:environment, slug: 'environment-slug', project: project) }
before do before do
......
...@@ -17849,6 +17849,9 @@ msgstr "" ...@@ -17849,6 +17849,9 @@ msgstr ""
msgid "The branch for this project has no active pipeline configuration." msgid "The branch for this project has no active pipeline configuration."
msgstr "" msgstr ""
msgid "The branch or tag does not exist"
msgstr ""
msgid "The character highlighter helps you keep the subject line to %{titleLength} characters and wrap the body at %{bodyLength} so they are readable in git." msgid "The character highlighter helps you keep the subject line to %{titleLength} characters and wrap the body at %{bodyLength} so they are readable in git."
msgstr "" msgstr ""
...@@ -17858,6 +17861,9 @@ msgstr "" ...@@ -17858,6 +17861,9 @@ msgstr ""
msgid "The collection of events added to the data gathered for that stage." msgid "The collection of events added to the data gathered for that stage."
msgstr "" msgstr ""
msgid "The commit does not exist"
msgstr ""
msgid "The configuration status of the table below only applies to the default branch and is based on the %{linkStart}latest pipeline%{linkEnd}. Once you've configured a scan for the default branch, any subsequent feature branch you create will include the scan." msgid "The configuration status of the table below only applies to the default branch and is based on the %{linkStart}latest pipeline%{linkEnd}. Once you've configured a scan for the default branch, any subsequent feature branch you create will include the scan."
msgstr "" msgstr ""
......
...@@ -6,7 +6,7 @@ describe Projects::DeploymentsController do ...@@ -6,7 +6,7 @@ describe Projects::DeploymentsController do
include ApiHelpers include ApiHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, name: 'production', project: project) } let(:environment) { create(:environment, name: 'production', project: project) }
before do before do
......
...@@ -7,9 +7,9 @@ describe Projects::Serverless::FunctionsController do ...@@ -7,9 +7,9 @@ describe Projects::Serverless::FunctionsController do
include ReactiveCachingHelpers include ReactiveCachingHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:project) { create(:project, :repository) }
let(:cluster) { create(:cluster, :project, :provided_by_gcp, projects: [project]) }
let(:service) { cluster.platform_kubernetes } let(:service) { cluster.platform_kubernetes }
let(:project) { cluster.project }
let(:environment) { create(:environment, project: project) } let(:environment) { create(:environment, project: project) }
let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) } let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) }
let(:knative_services_finder) { environment.knative_services_finder } let(:knative_services_finder) { environment.knative_services_finder }
......
...@@ -33,10 +33,10 @@ describe 'Merge request > User sees deployment widget', :js do ...@@ -33,10 +33,10 @@ describe 'Merge request > User sees deployment widget', :js do
end end
context 'when a user created a new merge request with the same SHA' do context 'when a user created a new merge request with the same SHA' do
let(:pipeline2) { create(:ci_pipeline, sha: sha, project: project, ref: 'new-patch-1') } let(:pipeline2) { create(:ci_pipeline, sha: sha, project: project, ref: 'video') }
let(:build2) { create(:ci_build, :success, pipeline: pipeline2) } let(:build2) { create(:ci_build, :success, pipeline: pipeline2) }
let(:environment2) { create(:environment, project: project) } let(:environment2) { create(:environment, project: project) }
let!(:deployment2) { create(:deployment, environment: environment2, sha: sha, ref: 'new-patch-1', deployable: build2) } let!(:deployment2) { create(:deployment, environment: environment2, sha: sha, ref: 'video', deployable: build2) }
it 'displays one environment which is related to the pipeline' do it 'displays one environment which is related to the pipeline' do
visit project_merge_request_path(project, merge_request) visit project_merge_request_path(project, merge_request)
......
...@@ -6,7 +6,7 @@ describe 'Environment > Metrics' do ...@@ -6,7 +6,7 @@ describe 'Environment > Metrics' do
include PrometheusHelpers include PrometheusHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:prometheus_project) } let(:project) { create(:prometheus_project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project) } let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
let(:environment) { create(:environment, project: project) } let(:environment) { create(:environment, project: project) }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
require 'spec_helper' require 'spec_helper'
describe 'Environment' do describe 'Environment' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:role) { :developer } let(:role) { :developer }
...@@ -17,6 +17,7 @@ describe 'Environment' do ...@@ -17,6 +17,7 @@ describe 'Environment' do
let!(:permissions) { } let!(:permissions) { }
let!(:deployment) { } let!(:deployment) { }
let!(:action) { } let!(:action) { }
let!(:cluster) { }
before do before do
visit_environment(environment) visit_environment(environment)
...@@ -94,19 +95,10 @@ describe 'Environment' do ...@@ -94,19 +95,10 @@ describe 'Environment' do
it 'does show build name' do it 'does show build name' do
expect(page).to have_link("#{build.name} (##{build.id})") expect(page).to have_link("#{build.name} (##{build.id})")
expect(page).not_to have_link('Re-deploy')
expect(page).not_to have_terminal_button
end end
context 'when user has ability to re-deploy' do it 'shows the re-deploy button' do
let(:permissions) do expect(page).to have_button('Re-deploy to environment')
create(:protected_branch, :developers_can_merge,
name: build.ref, project: project)
end
it 'does show re-deploy' do
expect(page).to have_link('Re-deploy')
end
end end
context 'with manual action' do context 'with manual action' do
...@@ -141,6 +133,11 @@ describe 'Environment' do ...@@ -141,6 +133,11 @@ describe 'Environment' do
end end
context 'when user has no ability to trigger a deployment' do context 'when user has no ability to trigger a deployment' do
let(:permissions) do
create(:protected_branch, :no_one_can_merge,
name: action.ref, project: project)
end
it 'does not show a play button' do it 'does not show a play button' do
expect(page).not_to have_link(action.name) expect(page).not_to have_link(action.name)
end end
...@@ -158,8 +155,9 @@ describe 'Environment' do ...@@ -158,8 +155,9 @@ describe 'Environment' do
context 'with terminal' do context 'with terminal' do
context 'when user configured kubernetes from CI/CD > Clusters' do context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) } let!(:cluster) do
let(:project) { cluster.project } create(:cluster, :project, :provided_by_gcp, projects: [project])
end
context 'for project maintainer' do context 'for project maintainer' do
let(:role) { :maintainer } let(:role) { :maintainer }
...@@ -228,6 +226,11 @@ describe 'Environment' do ...@@ -228,6 +226,11 @@ describe 'Environment' do
end end
context 'when user has no ability to stop environment' do context 'when user has no ability to stop environment' do
let(:permissions) do
create(:protected_branch, :no_one_can_merge,
name: action.ref, project: project)
end
it 'does not allow to stop environment' do it 'does not allow to stop environment' do
expect(page).not_to have_button('Stop') expect(page).not_to have_button('Stop')
end end
......
...@@ -6,7 +6,7 @@ describe 'Functions', :js do ...@@ -6,7 +6,7 @@ describe 'Functions', :js do
include KubernetesHelpers include KubernetesHelpers
include ReactiveCachingHelpers include ReactiveCachingHelpers
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:user) { create(:user) } let(:user) { create(:user) }
before do before do
...@@ -36,9 +36,8 @@ describe 'Functions', :js do ...@@ -36,9 +36,8 @@ describe 'Functions', :js do
end end
context 'when the user has a cluster and knative installed and visits the serverless page' do context 'when the user has a cluster and knative installed and visits the serverless page' do
let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:cluster) { create(:cluster, :project, :provided_by_gcp, projects: [project]) }
let(:service) { cluster.platform_kubernetes } let(:service) { cluster.platform_kubernetes }
let(:project) { cluster.project }
let(:environment) { create(:environment, project: project) } let(:environment) { create(:environment, project: project) }
let!(:deployment) { create(:deployment, :success, cluster: cluster, environment: environment) } let!(:deployment) { create(:deployment, :success, cluster: cluster, environment: environment) }
let(:knative_services_finder) { environment.knative_services_finder } let(:knative_services_finder) { environment.knative_services_finder }
......
...@@ -6,9 +6,9 @@ describe Clusters::KnativeServicesFinder do ...@@ -6,9 +6,9 @@ describe Clusters::KnativeServicesFinder do
include KubernetesHelpers include KubernetesHelpers
include ReactiveCachingHelpers include ReactiveCachingHelpers
let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:project) { create(:project, :repository) }
let(:cluster) { create(:cluster, :project, :provided_by_gcp, projects: [project]) }
let(:service) { environment.deployment_platform } let(:service) { environment.deployment_platform }
let(:project) { cluster.cluster_project.project }
let(:environment) { create(:environment, project: project) } let(:environment) { create(:environment, project: project) }
let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) } let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) }
let(:namespace) do let(:namespace) do
......
...@@ -5,7 +5,7 @@ require 'spec_helper' ...@@ -5,7 +5,7 @@ require 'spec_helper'
describe DeploymentsFinder do describe DeploymentsFinder do
subject { described_class.new(project, params).execute } subject { described_class.new(project, params).execute }
let(:project) { create(:project, :public, :repository) } let(:project) { create(:project, :public, :test_repo) }
let(:params) { {} } let(:params) { {} }
describe "#execute" do describe "#execute" do
...@@ -34,7 +34,7 @@ describe DeploymentsFinder do ...@@ -34,7 +34,7 @@ describe DeploymentsFinder do
let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: 2.days.ago, updated_at: Time.now) } let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: 2.days.ago, updated_at: Time.now) }
let!(:deployment_2) { create(:deployment, :success, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago, updated_at: 2.hours.ago) } let!(:deployment_2) { create(:deployment, :success, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago, updated_at: 2.hours.ago) }
let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'patch', created_at: Time.now, updated_at: 1.hour.ago) } let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'video', created_at: Time.now, updated_at: 1.hour.ago) }
where(:order_by, :sort, :ordered_deployments) do where(:order_by, :sort, :ordered_deployments) do
'created_at' | 'asc' | [:deployment_1, :deployment_2, :deployment_3] 'created_at' | 'asc' | [:deployment_1, :deployment_2, :deployment_3]
......
...@@ -8,9 +8,9 @@ describe Projects::Serverless::FunctionsFinder do ...@@ -8,9 +8,9 @@ describe Projects::Serverless::FunctionsFinder do
include ReactiveCachingHelpers include ReactiveCachingHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:project) { create(:project, :repository) }
let(:cluster) { create(:cluster, :project, :provided_by_gcp, projects: [project]) }
let(:service) { cluster.platform_kubernetes } let(:service) { cluster.platform_kubernetes }
let(:project) { cluster.project }
let(:environment) { create(:environment, project: project) } let(:environment) { create(:environment, project: project) }
let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) } let!(:deployment) { create(:deployment, :success, environment: environment, cluster: cluster) }
let(:knative_services_finder) { environment.knative_services_finder } let(:knative_services_finder) { environment.knative_services_finder }
......
...@@ -3,8 +3,13 @@ ...@@ -3,8 +3,13 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Pipeline::Seed::Deployment do describe Gitlab::Ci::Pipeline::Seed::Deployment do
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project, :repository) }
let(:job) { build(:ci_build, project: project) } let(:pipeline) do
create(:ci_pipeline, project: project,
sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0')
end
let(:job) { build(:ci_build, project: project, pipeline: pipeline) }
let(:seed) { described_class.new(job) } let(:seed) { described_class.new(job) }
let(:attributes) { {} } let(:attributes) { {} }
......
...@@ -8,7 +8,8 @@ describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery do ...@@ -8,7 +8,8 @@ describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery do
end end
include_examples 'additional metrics query' do include_examples 'additional metrics query' do
let(:deployment) { create(:deployment, environment: environment) } let(:project) { create(:project, :repository) }
let(:deployment) { create(:deployment, environment: environment, project: project) }
let(:query_params) { [deployment.id] } let(:query_params) { [deployment.id] }
it 'queries using specific time' do it 'queries using specific time' do
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::SlashCommands::Command do describe Gitlab::SlashCommands::Command do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:chat_name) { double(:chat_name, user: user) } let(:chat_name) { double(:chat_name, user: user) }
......
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
describe Gitlab::SlashCommands::Deploy do describe Gitlab::SlashCommands::Deploy do
describe '#execute' do describe '#execute' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:chat_name) { double(:chat_name, user: user) } let(:chat_name) { double(:chat_name, user: user) }
let(:regex_match) { described_class.match('deploy staging to production') } let(:regex_match) { described_class.match('deploy staging to production') }
......
...@@ -1054,7 +1054,7 @@ describe Ci::Build do ...@@ -1054,7 +1054,7 @@ describe Ci::Build do
end end
describe 'state transition as a deployable' do describe 'state transition as a deployable' do
let!(:build) { create(:ci_build, :with_deployment, :start_review_app) } let!(:build) { create(:ci_build, :with_deployment, :start_review_app, project: project, pipeline: pipeline) }
let(:deployment) { build.deployment } let(:deployment) { build.deployment }
let(:environment) { deployment.environment } let(:environment) { deployment.environment }
...@@ -3907,7 +3907,7 @@ describe Ci::Build do ...@@ -3907,7 +3907,7 @@ describe Ci::Build do
end end
context 'when build is a last deployment' do context 'when build is a last deployment' do
let(:build) { create(:ci_build, :success, environment: 'production') } let(:build) { create(:ci_build, :success, environment: 'production', pipeline: pipeline, project: project) }
let(:environment) { create(:environment, name: 'production', project: build.project) } let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
...@@ -3915,7 +3915,7 @@ describe Ci::Build do ...@@ -3915,7 +3915,7 @@ describe Ci::Build do
end end
context 'when there is a newer build with deployment' do context 'when there is a newer build with deployment' do
let(:build) { create(:ci_build, :success, environment: 'production') } let(:build) { create(:ci_build, :success, environment: 'production', pipeline: pipeline, project: project) }
let(:environment) { create(:environment, name: 'production', project: build.project) } let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
let!(:last_deployment) { create(:deployment, :success, environment: environment, project: environment.project) } let!(:last_deployment) { create(:deployment, :success, environment: environment, project: environment.project) }
...@@ -3924,7 +3924,7 @@ describe Ci::Build do ...@@ -3924,7 +3924,7 @@ describe Ci::Build do
end end
context 'when build with deployment has failed' do context 'when build with deployment has failed' do
let(:build) { create(:ci_build, :failed, environment: 'production') } let(:build) { create(:ci_build, :failed, environment: 'production', pipeline: pipeline, project: project) }
let(:environment) { create(:environment, name: 'production', project: build.project) } let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
...@@ -3932,7 +3932,7 @@ describe Ci::Build do ...@@ -3932,7 +3932,7 @@ describe Ci::Build do
end end
context 'when build with deployment is running' do context 'when build with deployment is running' do
let(:build) { create(:ci_build, environment: 'production') } let(:build) { create(:ci_build, environment: 'production', pipeline: pipeline, project: project) }
let(:environment) { create(:environment, name: 'production', project: build.project) } let(:environment) { create(:environment, name: 'production', project: build.project) }
let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) } let!(:deployment) { create(:deployment, :success, environment: environment, project: environment.project, deployable: build) }
......
...@@ -403,40 +403,37 @@ describe Deployment do ...@@ -403,40 +403,37 @@ describe Deployment do
describe '#previous_environment_deployment' do describe '#previous_environment_deployment' do
it 'returns the previous deployment of the same environment' do it 'returns the previous deployment of the same environment' do
deploy1 = create(:deployment, :success, ref: 'v1.0.0') deploy1 = create(:deployment, :success)
deploy2 = create( deploy2 = create(
:deployment, :deployment,
:success, :success,
project: deploy1.project, project: deploy1.project,
environment: deploy1.environment, environment: deploy1.environment
ref: 'v1.0.1'
) )
expect(deploy2.previous_environment_deployment).to eq(deploy1) expect(deploy2.previous_environment_deployment).to eq(deploy1)
end end
it 'ignores deployments that were not successful' do it 'ignores deployments that were not successful' do
deploy1 = create(:deployment, :failed, ref: 'v1.0.0') deploy1 = create(:deployment, :failed)
deploy2 = create( deploy2 = create(
:deployment, :deployment,
:success, :success,
project: deploy1.project, project: deploy1.project,
environment: deploy1.environment, environment: deploy1.environment
ref: 'v1.0.1'
) )
expect(deploy2.previous_environment_deployment).to be_nil expect(deploy2.previous_environment_deployment).to be_nil
end end
it 'ignores deployments for different environments' do it 'ignores deployments for different environments' do
deploy1 = create(:deployment, :success, ref: 'v1.0.0') deploy1 = create(:deployment, :success)
preprod = create(:environment, project: deploy1.project, name: 'preprod') preprod = create(:environment, project: deploy1.project, name: 'preprod')
deploy2 = create( deploy2 = create(
:deployment, :deployment,
:success, :success,
project: deploy1.project, project: deploy1.project,
environment: preprod, environment: preprod
ref: 'v1.0.1'
) )
expect(deploy2.previous_environment_deployment).to be_nil expect(deploy2.previous_environment_deployment).to be_nil
...@@ -499,4 +496,36 @@ describe Deployment do ...@@ -499,4 +496,36 @@ describe Deployment do
end end
end end
end end
describe '#valid_sha' do
it 'does not add errors for a valid SHA' do
project = create(:project, :repository)
deploy = build(:deployment, project: project)
expect(deploy).to be_valid
end
it 'adds an error for an invalid SHA' do
deploy = build(:deployment, sha: 'foo')
expect(deploy).not_to be_valid
expect(deploy.errors[:sha]).not_to be_empty
end
end
describe '#valid_ref' do
it 'does not add errors for a valid ref' do
project = create(:project, :repository)
deploy = build(:deployment, project: project)
expect(deploy).to be_valid
end
it 'adds an error for an invalid ref' do
deploy = build(:deployment, ref: 'does-not-exist')
expect(deploy).not_to be_valid
expect(deploy.errors[:ref]).not_to be_empty
end
end
end end
...@@ -7,7 +7,7 @@ describe Environment, :use_clean_rails_memory_store_caching do ...@@ -7,7 +7,7 @@ describe Environment, :use_clean_rails_memory_store_caching do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
include RepoHelpers include RepoHelpers
let(:project) { create(:project, :stubbed_repository) } let(:project) { create(:project, :repository) }
subject(:environment) { create(:environment, project: project) } subject(:environment) { create(:environment, project: project) }
...@@ -29,7 +29,6 @@ describe Environment, :use_clean_rails_memory_store_caching do ...@@ -29,7 +29,6 @@ describe Environment, :use_clean_rails_memory_store_caching do
it { is_expected.to validate_length_of(:external_url).is_at_most(255) } it { is_expected.to validate_length_of(:external_url).is_at_most(255) }
describe '.order_by_last_deployed_at' do describe '.order_by_last_deployed_at' do
let(:project) { create(:project, :repository) }
let!(:environment1) { create(:environment, project: project) } let!(:environment1) { create(:environment, project: project) }
let!(:environment2) { create(:environment, project: project) } let!(:environment2) { create(:environment, project: project) }
let!(:environment3) { create(:environment, project: project) } let!(:environment3) { create(:environment, project: project) }
...@@ -139,8 +138,8 @@ describe Environment, :use_clean_rails_memory_store_caching do ...@@ -139,8 +138,8 @@ describe Environment, :use_clean_rails_memory_store_caching do
describe '.with_deployment' do describe '.with_deployment' do
subject { described_class.with_deployment(sha) } subject { described_class.with_deployment(sha) }
let(:environment) { create(:environment) } let(:environment) { create(:environment, project: project) }
let(:sha) { RepoHelpers.sample_commit.id } let(:sha) { 'b83d6e391c22777fca1ed3012fce84f633d7fed0' }
context 'when deployment has the specified sha' do context 'when deployment has the specified sha' do
let!(:deployment) { create(:deployment, environment: environment, sha: sha) } let!(:deployment) { create(:deployment, environment: environment, sha: sha) }
...@@ -149,7 +148,7 @@ describe Environment, :use_clean_rails_memory_store_caching do ...@@ -149,7 +148,7 @@ describe Environment, :use_clean_rails_memory_store_caching do
end end
context 'when deployment does not have the specified sha' do context 'when deployment does not have the specified sha' do
let!(:deployment) { create(:deployment, environment: environment, sha: 'abc') } let!(:deployment) { create(:deployment, environment: environment, sha: 'ddd0f15ae83993f5cb66a927a28673882e99100b') }
it { is_expected.to be_empty } it { is_expected.to be_empty }
end end
...@@ -158,7 +157,7 @@ describe Environment, :use_clean_rails_memory_store_caching do ...@@ -158,7 +157,7 @@ describe Environment, :use_clean_rails_memory_store_caching do
describe '#folder_name' do describe '#folder_name' do
context 'when it is inside a folder' do context 'when it is inside a folder' do
subject(:environment) do subject(:environment) do
create(:environment, name: 'staging/review-1') create(:environment, name: 'staging/review-1', project: project)
end end
it 'returns a top-level folder name' do it 'returns a top-level folder name' do
...@@ -672,8 +671,7 @@ describe Environment, :use_clean_rails_memory_store_caching do ...@@ -672,8 +671,7 @@ describe Environment, :use_clean_rails_memory_store_caching do
context 'when the environment is available' do context 'when the environment is available' do
context 'with a deployment service' do context 'with a deployment service' do
context 'when user configured kubernetes from CI/CD > Clusters' do context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) } let!(:cluster) { create(:cluster, :project, :provided_by_gcp, projects: [project]) }
let(:project) { cluster.project }
context 'with deployment' do context 'with deployment' do
let!(:deployment) { create(:deployment, :success, environment: environment) } let!(:deployment) { create(:deployment, :success, environment: environment) }
...@@ -794,10 +792,9 @@ describe Environment, :use_clean_rails_memory_store_caching do ...@@ -794,10 +792,9 @@ describe Environment, :use_clean_rails_memory_store_caching do
end end
describe '#calculate_reactive_cache' do describe '#calculate_reactive_cache' do
let(:cluster) { create(:cluster, :project, :provided_by_user) } let!(:cluster) { create(:cluster, :project, :provided_by_user, projects: [project]) }
let(:project) { cluster.project } let!(:environment) { create(:environment, project: project) }
let(:environment) { create(:environment, project: project) } let!(:deployment) { create(:deployment, :success, environment: environment, project: project) }
let!(:deployment) { create(:deployment, :success, environment: environment) }
subject { environment.calculate_reactive_cache } subject { environment.calculate_reactive_cache }
...@@ -830,7 +827,7 @@ describe Environment, :use_clean_rails_memory_store_caching do ...@@ -830,7 +827,7 @@ describe Environment, :use_clean_rails_memory_store_caching do
context 'when the environment is available' do context 'when the environment is available' do
context 'with a deployment service' do context 'with a deployment service' do
let(:project) { create(:prometheus_project) } let(:project) { create(:prometheus_project, :repository) }
context 'and a deployment' do context 'and a deployment' do
let!(:deployment) { create(:deployment, environment: environment) } let!(:deployment) { create(:deployment, environment: environment) }
......
...@@ -5107,7 +5107,7 @@ describe Project do ...@@ -5107,7 +5107,7 @@ describe Project do
describe '.deployments' do describe '.deployments' do
subject { project.deployments } subject { project.deployments }
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
before do before do
allow_any_instance_of(Deployment).to receive(:create_ref) allow_any_instance_of(Deployment).to receive(:create_ref)
......
...@@ -11,10 +11,10 @@ describe API::Deployments do ...@@ -11,10 +11,10 @@ describe API::Deployments do
end end
describe 'GET /projects/:id/deployments' do describe 'GET /projects/:id/deployments' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: Time.now, updated_at: Time.now) } let!(:deployment_1) { create(:deployment, :success, project: project, iid: 11, ref: 'master', created_at: Time.now, updated_at: Time.now) }
let!(:deployment_2) { create(:deployment, :success, project: project, iid: 12, ref: 'feature', created_at: 1.day.ago, updated_at: 2.hours.ago) } let!(:deployment_2) { create(:deployment, :success, project: project, iid: 12, ref: 'master', created_at: 1.day.ago, updated_at: 2.hours.ago) }
let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'patch', created_at: 2.days.ago, updated_at: 1.hour.ago) } let!(:deployment_3) { create(:deployment, :success, project: project, iid: 8, ref: 'master', created_at: 2.days.ago, updated_at: 1.hour.ago) }
context 'as member of the project' do context 'as member of the project' do
it 'returns projects deployments sorted by id asc' do it 'returns projects deployments sorted by id asc' do
...@@ -345,7 +345,7 @@ describe API::Deployments do ...@@ -345,7 +345,7 @@ describe API::Deployments do
context 'prevent N + 1 queries' do context 'prevent N + 1 queries' do
context 'when the endpoint returns multiple records' do context 'when the endpoint returns multiple records' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
def create_record def create_record
create(:deployment, :success, project: project) create(:deployment, :success, project: project)
...@@ -372,9 +372,11 @@ describe API::Deployments do ...@@ -372,9 +372,11 @@ describe API::Deployments do
end end
it 'does not increase the query count' do it 'does not increase the query count' do
expect { create_record }.not_to change { request_with_query_count } 10.times { create_record }
expect { trigger_request }.not_to be_n_plus_1_query
expect(json_response.size).to eq(2) expect(json_response.size).to eq(11)
end end
end end
end end
......
...@@ -5,7 +5,7 @@ require 'spec_helper' ...@@ -5,7 +5,7 @@ require 'spec_helper'
describe API::Environments do describe API::Environments do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:non_member) { create(:user) } let(:non_member) { create(:user) }
let(:project) { create(:project, :private, namespace: user.namespace) } let(:project) { create(:project, :private, :repository, namespace: user.namespace) }
let!(:environment) { create(:environment, project: project) } let!(:environment) { create(:environment, project: project) }
before do before do
......
...@@ -6,7 +6,7 @@ describe DeploymentEntity do ...@@ -6,7 +6,7 @@ describe DeploymentEntity do
let(:user) { developer } let(:user) { developer }
let(:developer) { create(:user) } let(:developer) { create(:user) }
let(:reporter) { create(:user) } let(:reporter) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:request) { double('request') } let(:request) { double('request') }
let(:deployment) { create(:deployment, deployable: build, project: project) } let(:deployment) { create(:deployment, deployable: build, project: project) }
let(:build) { create(:ci_build, :manual, pipeline: pipeline) } let(:build) { create(:ci_build, :manual, pipeline: pipeline) }
......
...@@ -4,8 +4,11 @@ require 'spec_helper' ...@@ -4,8 +4,11 @@ require 'spec_helper'
describe Ci::RetryBuildService do describe Ci::RetryBuildService do
set(:user) { create(:user) } set(:user) { create(:user) }
set(:project) { create(:project) } set(:project) { create(:project, :repository) }
set(:pipeline) { create(:ci_pipeline, project: project) } set(:pipeline) do
create(:ci_pipeline, project: project,
sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0')
end
let(:stage) do let(:stage) do
create(:ci_stage_entity, project: project, create(:ci_stage_entity, project: project,
...@@ -207,7 +210,8 @@ describe Ci::RetryBuildService do ...@@ -207,7 +210,8 @@ describe Ci::RetryBuildService do
context 'when build with deployment is retried' do context 'when build with deployment is retried' do
let!(:build) do let!(:build) do
create(:ci_build, :with_deployment, :deploy_to_production, pipeline: pipeline, stage_id: stage.id) create(:ci_build, :with_deployment, :deploy_to_production,
pipeline: pipeline, stage_id: stage.id, project: project)
end end
it 'creates a new deployment' do it 'creates a new deployment' do
......
...@@ -6,10 +6,18 @@ describe Deployments::AfterCreateService do ...@@ -6,10 +6,18 @@ describe Deployments::AfterCreateService do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:options) { { name: 'production' } } let(:options) { { name: 'production' } }
let(:pipeline) do
create(
:ci_pipeline,
sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0',
project: project
)
end
let(:job) do let(:job) do
create(:ci_build, create(:ci_build,
:with_deployment, :with_deployment,
pipeline: pipeline,
ref: 'master', ref: 'master',
tag: false, tag: false,
environment: 'production', environment: 'production',
...@@ -139,6 +147,7 @@ describe Deployments::AfterCreateService do ...@@ -139,6 +147,7 @@ describe Deployments::AfterCreateService do
let(:job) do let(:job) do
create(:ci_build, create(:ci_build,
:with_deployment, :with_deployment,
pipeline: pipeline,
ref: 'master', ref: 'master',
environment: 'production', environment: 'production',
project: project, project: project,
...@@ -152,6 +161,7 @@ describe Deployments::AfterCreateService do ...@@ -152,6 +161,7 @@ describe Deployments::AfterCreateService do
let(:job) do let(:job) do
create(:ci_build, create(:ci_build,
:with_deployment, :with_deployment,
pipeline: pipeline,
ref: 'master', ref: 'master',
environment: 'prod-slug', environment: 'prod-slug',
project: project, project: project,
...@@ -165,6 +175,7 @@ describe Deployments::AfterCreateService do ...@@ -165,6 +175,7 @@ describe Deployments::AfterCreateService do
let(:job) do let(:job) do
create(:ci_build, create(:ci_build,
:with_deployment, :with_deployment,
pipeline: pipeline,
yaml_variables: [{ key: :APP_HOST, value: 'host' }], yaml_variables: [{ key: :APP_HOST, value: 'host' }],
environment: 'production', environment: 'production',
project: project, project: project,
...@@ -175,7 +186,7 @@ describe Deployments::AfterCreateService do ...@@ -175,7 +186,7 @@ describe Deployments::AfterCreateService do
end end
context 'when yaml environment does not have url' do context 'when yaml environment does not have url' do
let(:job) { create(:ci_build, :with_deployment, environment: 'staging', project: project) } let(:job) { create(:ci_build, :with_deployment, pipeline: pipeline, environment: 'staging', project: project) }
it 'returns the external_url from persisted environment' do it 'returns the external_url from persisted environment' do
is_expected.to be_nil is_expected.to be_nil
...@@ -202,6 +213,7 @@ describe Deployments::AfterCreateService do ...@@ -202,6 +213,7 @@ describe Deployments::AfterCreateService do
let(:job) do let(:job) do
create(:ci_build, create(:ci_build,
:with_deployment, :with_deployment,
pipeline: pipeline,
ref: 'master', ref: 'master',
tag: false, tag: false,
environment: 'staging', environment: 'staging',
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
require 'spec_helper' require 'spec_helper'
describe Deployments::LinkMergeRequestsService do describe Deployments::LinkMergeRequestsService do
let(:project) { create(:project, :repository) }
describe '#execute' do describe '#execute' do
context 'when the deployment did not succeed' do context 'when the deployment did not succeed' do
it 'does nothing' do it 'does nothing' do
...@@ -16,20 +18,29 @@ describe Deployments::LinkMergeRequestsService do ...@@ -16,20 +18,29 @@ describe Deployments::LinkMergeRequestsService do
context 'when there is a previous deployment' do context 'when there is a previous deployment' do
it 'links all merge requests merged since the previous deployment' do it 'links all merge requests merged since the previous deployment' do
deploy1 = create(:deployment, :success, sha: 'foo') deploy1 = create(
:deployment,
:success,
project: project,
sha: '7975be0116940bf2ad4321f79d02a55c5f7779aa'
)
deploy2 = create( deploy2 = create(
:deployment, :deployment,
:success, :success,
sha: 'bar',
project: deploy1.project, project: deploy1.project,
environment: deploy1.environment environment: deploy1.environment,
sha: 'ddd0f15ae83993f5cb66a927a28673882e99100b'
) )
service = described_class.new(deploy2) service = described_class.new(deploy2)
expect(service) expect(service)
.to receive(:link_merge_requests_for_range) .to receive(:link_merge_requests_for_range)
.with('foo', 'bar') .with(
'7975be0116940bf2ad4321f79d02a55c5f7779aa',
'ddd0f15ae83993f5cb66a927a28673882e99100b'
)
service.execute service.execute
end end
...@@ -37,7 +48,7 @@ describe Deployments::LinkMergeRequestsService do ...@@ -37,7 +48,7 @@ describe Deployments::LinkMergeRequestsService do
context 'when there are no previous deployments' do context 'when there are no previous deployments' do
it 'links all merged merge requests' do it 'links all merged merge requests' do
deploy = create(:deployment, :success) deploy = create(:deployment, :success, project: project)
service = described_class.new(deploy) service = described_class.new(deploy)
expect(service).to receive(:link_all_merged_merge_requests) expect(service).to receive(:link_all_merged_merge_requests)
...@@ -49,7 +60,6 @@ describe Deployments::LinkMergeRequestsService do ...@@ -49,7 +60,6 @@ describe Deployments::LinkMergeRequestsService do
describe '#link_merge_requests_for_range' do describe '#link_merge_requests_for_range' do
it 'links merge requests' do it 'links merge requests' do
project = create(:project, :repository)
environment = create(:environment, project: project) environment = create(:environment, project: project)
deploy = deploy =
create(:deployment, :success, project: project, environment: environment) create(:deployment, :success, project: project, environment: environment)
...@@ -81,7 +91,6 @@ describe Deployments::LinkMergeRequestsService do ...@@ -81,7 +91,6 @@ describe Deployments::LinkMergeRequestsService do
describe '#link_all_merged_merge_requests' do describe '#link_all_merged_merge_requests' do
it 'links all merged merge requests targeting the deployed branch' do it 'links all merged merge requests targeting the deployed branch' do
project = create(:project, :repository)
environment = create(:environment, project: project) environment = create(:environment, project: project)
deploy = deploy =
create(:deployment, :success, project: project, environment: environment) create(:deployment, :success, project: project, environment: environment)
......
...@@ -14,7 +14,7 @@ RSpec.shared_examples 'additional metrics query' do ...@@ -14,7 +14,7 @@ RSpec.shared_examples 'additional metrics query' do
let(:client) { double('prometheus_client') } let(:client) { double('prometheus_client') }
let(:query_result) { described_class.new(client).query(*query_params) } let(:query_result) { described_class.new(client).query(*query_params) }
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, slug: 'environment-slug', project: project) } let(:environment) { create(:environment, slug: 'environment-slug', project: project) }
before do before do
...@@ -47,8 +47,7 @@ RSpec.shared_examples 'additional metrics query' do ...@@ -47,8 +47,7 @@ RSpec.shared_examples 'additional metrics query' do
describe 'project has Kubernetes service' do describe 'project has Kubernetes service' do
context 'when user configured kubernetes from CI/CD > Clusters' do context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) } let!(:cluster) { create(:cluster, :project, :provided_by_gcp, projects: [project]) }
let(:project) { cluster.project }
let(:environment) { create(:environment, slug: 'environment-slug', project: project) } let(:environment) { create(:environment, slug: 'environment-slug', project: project) }
let(:kube_namespace) { environment.deployment_namespace } let(:kube_namespace) { environment.deployment_namespace }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment