diff options
author | Hordur Freyr Yngvason <hfyngvason@gitlab.com> | 2019-08-08 18:51:52 +0000 |
---|---|---|
committer | Robert Speicher <rspeicher@gmail.com> | 2019-08-08 18:51:52 +0000 |
commit | 5f82ff1469510b4e51d531775a44e4bea92254fe (patch) | |
tree | 2762023eb50a91cabb54f8b454db49c147f447d4 /app | |
parent | 455d16d1bfd59000391a64f41ab86d5a847f008a (diff) | |
download | gitlab-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.rb | 2 | ||||
-rw-r--r-- | app/models/ci/variable.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/has_environment_scope.rb | 78 | ||||
-rw-r--r-- | app/models/project.rb | 13 | ||||
-rw-r--r-- | app/serializers/variable_entity.rb | 1 | ||||
-rw-r--r-- | app/views/ci/variables/_environment_scope.html.haml | 21 | ||||
-rw-r--r-- | app/views/ci/variables/_environment_scope_header.html.haml | 2 |
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') |