summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorHordur Freyr Yngvason <hfyngvason@gitlab.com>2019-08-08 18:51:52 +0000
committerRobert Speicher <rspeicher@gmail.com>2019-08-08 18:51:52 +0000
commit5f82ff1469510b4e51d531775a44e4bea92254fe (patch)
tree2762023eb50a91cabb54f8b454db49c147f447d4 /app
parent455d16d1bfd59000391a64f41ab86d5a847f008a (diff)
downloadgitlab-ce-5f82ff1469510b4e51d531775a44e4bea92254fe.tar.gz
Bring scoped environment variables to core
As decided in https://gitlab.com/gitlab-org/gitlab-ce/issues/53593
Diffstat (limited to 'app')
-rw-r--r--app/controllers/projects/variables_controller.rb2
-rw-r--r--app/models/ci/variable.rb1
-rw-r--r--app/models/concerns/has_environment_scope.rb78
-rw-r--r--app/models/project.rb13
-rw-r--r--app/serializers/variable_entity.rb1
-rw-r--r--app/views/ci/variables/_environment_scope.html.haml21
-rw-r--r--app/views/ci/variables/_environment_scope_header.html.haml2
7 files changed, 113 insertions, 5 deletions
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index 646728e8167..1dffc57fcf0 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -38,6 +38,6 @@ class Projects::VariablesController < Projects::ApplicationController
end
def variable_params_attributes
- %i[id variable_type key secret_value protected masked _destroy]
+ %i[id variable_type key secret_value protected masked environment_scope _destroy]
end
end
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index a77bbef0fca..760872d3e6b 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -6,6 +6,7 @@ module Ci
include HasVariable
include Presentable
include Maskable
+ prepend HasEnvironmentScope
belongs_to :project
diff --git a/app/models/concerns/has_environment_scope.rb b/app/models/concerns/has_environment_scope.rb
new file mode 100644
index 00000000000..9553abe4dd3
--- /dev/null
+++ b/app/models/concerns/has_environment_scope.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+module HasEnvironmentScope
+ extend ActiveSupport::Concern
+
+ prepended do
+ validates(
+ :environment_scope,
+ presence: true,
+ format: { with: ::Gitlab::Regex.environment_scope_regex,
+ message: ::Gitlab::Regex.environment_scope_regex_message }
+ )
+
+ ##
+ # Select rows which have a scope that matches the given environment name.
+ # Rows are ordered by relevance, by default. The most relevant row is
+ # placed at the end of a list.
+ #
+ # options:
+ # - relevant_only: (boolean)
+ # You can get the most relevant row only. Other rows are not be
+ # selected even if its scope matches the environment name.
+ # This is equivalent to using `#last` from SQL standpoint.
+ #
+ scope :on_environment, -> (environment_name, relevant_only: false) do
+ order_direction = relevant_only ? 'DESC' : 'ASC'
+
+ where = <<~SQL
+ environment_scope IN (:wildcard, :environment_name) OR
+ :environment_name LIKE
+ #{::Gitlab::SQL::Glob.to_like('environment_scope')}
+ SQL
+
+ order = <<~SQL
+ CASE environment_scope
+ WHEN :wildcard THEN 0
+ WHEN :environment_name THEN 2
+ ELSE 1
+ END #{order_direction}
+ SQL
+
+ values = {
+ wildcard: '*',
+ environment_name: environment_name
+ }
+
+ sanitized_order_sql = sanitize_sql_array([order, values])
+
+ # The query is trying to find variables with scopes matching the
+ # current environment name. Suppose the environment name is
+ # 'review/app', and we have variables with environment scopes like:
+ # * variable A: review
+ # * variable B: review/app
+ # * variable C: review/*
+ # * variable D: *
+ # And the query should find variable B, C, and D, because it would
+ # try to convert the scope into a LIKE pattern for each variable:
+ # * A: review
+ # * B: review/app
+ # * C: review/%
+ # * D: %
+ # Note that we'll match % and _ literally therefore we'll escape them.
+ # In this case, B, C, and D would match. We also want to prioritize
+ # the exact matched name, and put * last, and everything else in the
+ # middle. So the order should be: D < C < B
+ relation = where(where, values)
+ .order(Arel.sql(sanitized_order_sql)) # `order` cannot escape for us!
+
+ relation = relation.limit(1) if relevant_only
+
+ relation
+ end
+ end
+
+ def environment_scope=(new_environment_scope)
+ super(new_environment_scope.to_s.strip)
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 960795b73cb..7a5e980b783 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1828,11 +1828,16 @@ class Project < ApplicationRecord
end
def ci_variables_for(ref:, environment: nil)
- # EE would use the environment
- if protected_for?(ref)
- variables
+ result = if protected_for?(ref)
+ variables
+ else
+ variables.unprotected
+ end
+
+ if environment
+ result.on_environment(environment)
else
- variables.unprotected
+ result.where(environment_scope: '*')
end
end
diff --git a/app/serializers/variable_entity.rb b/app/serializers/variable_entity.rb
index 4d48e13cfca..8b19925f153 100644
--- a/app/serializers/variable_entity.rb
+++ b/app/serializers/variable_entity.rb
@@ -7,4 +7,5 @@ class VariableEntity < Grape::Entity
expose :protected?, as: :protected
expose :masked?, as: :masked
+ expose :environment_scope
end
diff --git a/app/views/ci/variables/_environment_scope.html.haml b/app/views/ci/variables/_environment_scope.html.haml
new file mode 100644
index 00000000000..15e61d85881
--- /dev/null
+++ b/app/views/ci/variables/_environment_scope.html.haml
@@ -0,0 +1,21 @@
+- form_field = local_assigns.fetch(:form_field, nil)
+- variable = local_assigns.fetch(:variable, nil)
+
+- if @project
+ - environment_scope = variable&.environment_scope || '*'
+ - environment_scope_label = environment_scope == '*' ? s_('CiVariable|All environments') : environment_scope
+
+ %input{ type: "hidden", name: "#{form_field}[variables_attributes][][environment_scope]", value: environment_scope }
+ = dropdown_tag(environment_scope_label,
+ options: { wrapper_class: 'ci-variable-body-item js-variable-environment-dropdown-wrapper',
+ toggle_class: 'js-variable-environment-toggle wide',
+ filter: true,
+ dropdown_class: "dropdown-menu-selectable",
+ placeholder: s_('CiVariable|Search environments'),
+ footer_content: true,
+ data: { selected: environment_scope } }) do
+ %ul.dropdown-footer-list
+ %li
+ %button{ class: "dropdown-create-new-item-button js-dropdown-create-new-item", title: s_('CiVariable|New environment') }
+ = s_('CiVariable|Create wildcard')
+ %code
diff --git a/app/views/ci/variables/_environment_scope_header.html.haml b/app/views/ci/variables/_environment_scope_header.html.haml
new file mode 100644
index 00000000000..4ba4ceec16c
--- /dev/null
+++ b/app/views/ci/variables/_environment_scope_header.html.haml
@@ -0,0 +1,2 @@
+.bold.table-section.section-15.append-right-10
+ = s_('CiVariables|Scope')