Skip to content
Snippets Groups Projects
Commit f0a9e340 authored by Shinya Maeda's avatar Shinya Maeda
Browse files

Introduce the explicit definition for production environments

This commit introduces the 'tier' column to 'environments' table
in order to explicit define environment tiers.
parent df5fcb4e
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -39,6 +39,7 @@ class Environment < ApplicationRecord
before_validation :generate_slug, if: ->(env) { env.slug.blank? }
 
before_save :set_environment_type
before_save :ensure_environment_tier
after_save :clear_reactive_cache!
 
validates :name,
Loading
Loading
@@ -87,6 +88,7 @@ class Environment < ApplicationRecord
end
 
scope :for_project, -> (project) { where(project_id: project) }
scope :for_tier, -> (tier) { where(tier: tier).where('tier IS NOT NULL') }
scope :with_deployment, -> (sha) { where('EXISTS (?)', Deployment.select(1).where('deployments.environment_id = environments.id').where(sha: sha)) }
scope :unfoldered, -> { where(environment_type: nil) }
scope :with_rank, -> do
Loading
Loading
@@ -94,6 +96,14 @@ class Environment < ApplicationRecord
end
scope :for_id, -> (id) { where(id: id) }
 
enum tier: {
production: 0,
staging: 1,
testing: 2,
development: 3,
other: 4
}
state_machine :state, initial: :available do
event :start do
transition stopped: :available
Loading
Loading
@@ -429,6 +439,24 @@ def has_metrics_and_can_query?
def generate_slug
self.slug = Gitlab::Slug::Environment.new(name).generate
end
def ensure_environment_tier
return unless ::Feature.enabled?(:environment_tier, project, default_enabled: :yaml)
self.tier ||= guess_tier
end
# Guessing the tier of the environment if it's not explicitly specified by users.
# See https://en.wikipedia.org/wiki/Deployment_environment for industry standard deployment environments
def guess_tier
case name
when %r{dev|review|trunk}i then self.class.tiers[:development]
when %r{test|qc}i then self.class.tiers[:testing]
when %r{st(a|)g|mod(e|)l|pre|demo}i then self.class.tiers[:staging]
when %r{pr(o|)d|live}i then self.class.tiers[:production]
else self.class.tiers[:other]
end
end
end
 
Environment.prepend_if_ee('EE::Environment')
---
title: Add tier column to the environments table
merge_request: 55471
author:
type: added
---
name: environment_tier
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55471
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/323166
milestone: '13.10'
type: development
group: group::release
default_enabled: false
# frozen_string_literal: true
class AddTierToEnvironments < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
with_lock_retries do
add_column :environments, :tier, :smallint
end
end
def down
with_lock_retries do
remove_column :environments, :tier
end
end
end
# frozen_string_literal: true
class AddIndexToEnvironmentsTier < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
INDEX_NAME = 'index_environments_on_project_id_and_tier'
DOWNTIME = false
def up
add_concurrent_index :environments, [:project_id, :tier], where: 'tier IS NOT NULL', name: INDEX_NAME
end
def down
remove_concurrent_index :environments, :state, name: INDEX_NAME
end
end
6c52ab55814241b37014949976c4f3a0c63bea0a4f9a301735cc9f4c509f433d
\ No newline at end of file
e1641d84828e3d87aea626dbce6b3b2d231d08fcf1475991fe8d11714cdb0af0
\ No newline at end of file
Loading
Loading
@@ -12144,7 +12144,8 @@ CREATE TABLE environments (
state character varying DEFAULT 'available'::character varying NOT NULL,
slug character varying NOT NULL,
auto_stop_at timestamp with time zone,
auto_delete_at timestamp with time zone
auto_delete_at timestamp with time zone,
tier smallint
);
 
CREATE SEQUENCE environments_id_seq
Loading
Loading
@@ -22179,6 +22180,8 @@ CREATE UNIQUE INDEX index_environments_on_project_id_and_name ON environments US
 
CREATE UNIQUE INDEX index_environments_on_project_id_and_slug ON environments USING btree (project_id, slug);
 
CREATE INDEX index_environments_on_project_id_and_tier ON environments USING btree (project_id, tier) WHERE (tier IS NOT NULL);
CREATE INDEX index_environments_on_project_id_state_environment_type ON environments USING btree (project_id, state, environment_type);
 
CREATE INDEX index_environments_on_state_and_auto_stop_at ON environments USING btree (state, auto_stop_at) WHERE ((auto_stop_at IS NOT NULL) AND ((state)::text = 'available'::text));
Loading
Loading
@@ -15,6 +15,22 @@
state { :stopped }
end
 
trait :production do
tier { :production }
end
trait :staging do
tier { :staging }
end
trait :testing do
tier { :testing }
end
trait :development do
tier { :development }
end
trait :with_review_app do |environment|
transient do
ref { 'master' }
Loading
Loading
Loading
Loading
@@ -34,6 +34,39 @@
 
it { is_expected.to validate_length_of(:external_url).is_at_most(255) }
 
describe '.before_save' do
it 'ensures environment tier when a new object is created' do
environment = build(:environment, name: 'gprd', tier: nil)
expect { environment.save }.to change { environment.tier }.from(nil).to('production')
end
it 'ensures environment tier when an existing object is updated' do
environment = create(:environment, name: 'gprd')
environment.update_column(:tier, nil)
expect { environment.stop! }.to change { environment.reload.tier }.from(nil).to('production')
end
it 'does not overwrite the existing environment tier' do
environment = create(:environment, name: 'gprd', tier: :production)
expect { environment.update!(name: 'gstg') }.not_to change { environment.reload.tier }
end
context 'when environment_tier feature flag is disabled' do
before do
stub_feature_flags(environment_tier: false)
end
it 'does not ensure environment tier' do
environment = build(:environment, name: 'gprd', tier: nil)
expect { environment.save }.not_to change { environment.tier }
end
end
end
describe '.order_by_last_deployed_at' do
let!(:environment1) { create(:environment, project: project) }
let!(:environment2) { create(:environment, project: project) }
Loading
Loading
@@ -195,6 +228,62 @@
end
end
 
describe '.for_tier' do
let_it_be(:environment) { create(:environment, :production) }
it 'returns the production environment when searching for production tier' do
expect(described_class.for_tier(:production)).to eq([environment])
end
it 'returns nothing when searching for staging tier' do
expect(described_class.for_tier(:staging)).to be_empty
end
end
describe '#guess_tier' do
using RSpec::Parameterized::TableSyntax
subject { environment.send(:guess_tier) }
let(:environment) { build(:environment, name: name) }
where(:name, :tier) do
'review/feature' | described_class.tiers[:development]
'review/product' | described_class.tiers[:development]
'DEV' | described_class.tiers[:development]
'development' | described_class.tiers[:development]
'trunk' | described_class.tiers[:development]
'test' | described_class.tiers[:testing]
'TEST' | described_class.tiers[:testing]
'testing' | described_class.tiers[:testing]
'testing-prd' | described_class.tiers[:testing]
'acceptance-testing' | described_class.tiers[:testing]
'QC' | described_class.tiers[:testing]
'gstg' | described_class.tiers[:staging]
'staging' | described_class.tiers[:staging]
'stage' | described_class.tiers[:staging]
'Model' | described_class.tiers[:staging]
'MODL' | described_class.tiers[:staging]
'Pre-production' | described_class.tiers[:staging]
'pre' | described_class.tiers[:staging]
'Demo' | described_class.tiers[:staging]
'gprd' | described_class.tiers[:production]
'gprd-cny' | described_class.tiers[:production]
'production' | described_class.tiers[:production]
'Production' | described_class.tiers[:production]
'prod' | described_class.tiers[:production]
'PROD' | described_class.tiers[:production]
'Live' | described_class.tiers[:production]
'canary' | described_class.tiers[:other]
'other' | described_class.tiers[:other]
'EXP' | described_class.tiers[:other]
end
with_them do
it { is_expected.to eq(tier) }
end
end
describe '#expire_etag_cache' do
let(:store) { Gitlab::EtagCaching::Store.new }
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment