summaryrefslogtreecommitdiff
path: root/app/models/environment.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/environment.rb')
-rw-r--r--app/models/environment.rb74
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