diff options
Diffstat (limited to 'app/models/environment.rb')
-rw-r--r-- | app/models/environment.rb | 74 |
1 files changed, 72 insertions, 2 deletions
diff --git a/app/models/environment.rb b/app/models/environment.rb index 73f415c0ef0..8ef1c841ea3 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -1,25 +1,38 @@ class Environment < ActiveRecord::Base + # Used to generate random suffixes for the slug + NUMBERS = '0'..'9' + SUFFIX_CHARS = ('a'..'z').to_a + NUMBERS.to_a + belongs_to :project, required: true, validate: true has_many :deployments before_validation :nullify_external_url + before_validation :generate_slug, if: ->(env) { env.slug.blank? } + before_save :set_environment_type validates :name, presence: true, uniqueness: { scope: :project_id }, - length: { within: 0..255 }, + length: { maximum: 255 }, format: { with: Gitlab::Regex.environment_name_regex, message: Gitlab::Regex.environment_name_regex_message } + validates :slug, + presence: true, + uniqueness: { scope: :project_id }, + length: { maximum: 24 }, + format: { with: Gitlab::Regex.environment_slug_regex, + message: Gitlab::Regex.environment_slug_regex_message } + validates :external_url, uniqueness: { scope: :project_id }, length: { maximum: 255 }, allow_nil: true, addressable_url: true - delegate :stop_action, to: :last_deployment, allow_nil: true + delegate :stop_action, :manual_actions, to: :last_deployment, allow_nil: true scope :available, -> { with_state(:available) } scope :stopped, -> { with_state(:stopped) } @@ -37,6 +50,17 @@ class Environment < ActiveRecord::Base state :stopped end + def predefined_variables + [ + { key: 'CI_ENVIRONMENT_NAME', value: name, public: true }, + { key: 'CI_ENVIRONMENT_SLUG', value: slug, public: true }, + ] + end + + def recently_updated_on_branch?(ref) + ref.to_s == last_deployment.try(:ref) + end + def last_deployment deployments.last end @@ -92,6 +116,52 @@ class Environment < ActiveRecord::Base def stop!(current_user) return unless stoppable? + stop stop_action.play(current_user) end + + def actions_for(environment) + return [] unless manual_actions + + manual_actions.select do |action| + action.expanded_environment_name == environment + end + end + + # An environment name is not necessarily suitable for use in URLs, DNS + # or other third-party contexts, so provide a slugified version. A slug has + # the following properties: + # * contains only lowercase letters (a-z), numbers (0-9), and '-' + # * begins with a letter + # * has a maximum length of 24 bytes (OpenShift limitation) + # * cannot end with `-` + def generate_slug + # Lowercase letters and numbers only + slugified = name.to_s.downcase.gsub(/[^a-z0-9]/, '-') + + # Must start with a letter + slugified = "env-" + slugified if NUMBERS.cover?(slugified[0]) + + # Maximum length: 24 characters (OpenShift limitation) + slugified = slugified[0..23] + + # Cannot end with a "-" character (Kubernetes label limitation) + slugified = slugified[0..-2] if slugified[-1] == "-" + + # Add a random suffix, shortening the current string if necessary, if it + # has been slugified. This ensures uniqueness. + slugified = slugified[0..16] + "-" + random_suffix if slugified != name + + self.slug = slugified + end + + private + + # Slugifying a name may remove the uniqueness guarantee afforded by it being + # based on name (which must be unique). To compensate, we add a random + # 6-byte suffix in those circumstances. This is not *guaranteed* uniqueness, + # but the chance of collisions is vanishingly small + def random_suffix + (0..5).map { SUFFIX_CHARS.sample }.join + end end |