Commit 2aa758a7 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Rename scope to environment_scope

parent 7afa0877
...@@ -53,6 +53,6 @@ class Projects::VariablesController < Projects::ApplicationController ...@@ -53,6 +53,6 @@ class Projects::VariablesController < Projects::ApplicationController
end end
def variable_params_ee def variable_params_ee
%i[scope] %i[environment_scope]
end end
end end
...@@ -5,7 +5,7 @@ module EE ...@@ -5,7 +5,7 @@ module EE
module VariableClassMethods module VariableClassMethods
def key_uniqueness_scope def key_uniqueness_scope
%i[project_id scope] %i[project_id environment_scope]
end end
end end
...@@ -13,10 +13,10 @@ module EE ...@@ -13,10 +13,10 @@ module EE
singleton_class.prepend(VariableClassMethods) singleton_class.prepend(VariableClassMethods)
validates( validates(
:scope, :environment_scope,
presence: true, presence: true,
format: { with: ::Gitlab::Regex.variable_scope_regex, format: { with: ::Gitlab::Regex.environment_scope_regex,
message: ::Gitlab::Regex.variable_scope_regex_message } message: ::Gitlab::Regex.environment_scope_regex_message }
) )
end end
end end
......
...@@ -78,20 +78,20 @@ module EE ...@@ -78,20 +78,20 @@ module EE
end end
def secret_variables_for(ref:, environment: nil) def secret_variables_for(ref:, environment: nil)
return super.where(scope: '*') unless environment return super.where(environment_scope: '*') unless environment
query = super query = super
where = <<~SQL where = <<~SQL
scope IN (:wildcard, :environment_name) OR environment_scope IN (:wildcard, :environment_name) OR
:environment_name LIKE :environment_name LIKE
REPLACE(REPLACE(scope, :wildcard, :percent), REPLACE(REPLACE(environment_scope, :wildcard, :percent),
:underscore, :underscore,
:escaped_underscore) :escaped_underscore)
SQL SQL
order = <<~SQL order = <<~SQL
CASE scope CASE environment_scope
WHEN %{wildcard} THEN 0 WHEN %{wildcard} THEN 0
WHEN %{environment_name} THEN 2 WHEN %{environment_name} THEN 2
ELSE 1 ELSE 1
......
...@@ -8,12 +8,12 @@ ...@@ -8,12 +8,12 @@
= f.label :value, "Value", class: "label-light" = f.label :value, "Value", class: "label-light"
= f.text_area :value, class: "form-control", placeholder: "PROJECT_VARIABLE" = f.text_area :value, class: "form-control", placeholder: "PROJECT_VARIABLE"
.form-group .form-group
= f.label :scope, "Scope", class: "label-light" = f.label :environment_scope, "Environment scope", class: "label-light"
= f.text_field :scope, class: "form-control", placeholder: "*" = f.text_field :environment_scope, class: "form-control", placeholder: "*"
.help-block .help-block
This variable will be passed only to jobs with a matching environment name. This variable will be passed only to jobs with a matching environment name.
<code>*</code> is a wildcard that matches all environments (existing or not). <code>*</code> is a wildcard that matches all environments (existing or not).
= link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'limiting-scopes-of-secret-variables'), target: '_blank' = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'limiting-environment-scopes-of-secret-variables'), target: '_blank'
.form-group .form-group
.checkbox .checkbox
= f.label :protected do = f.label :protected do
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
%th Key %th Key
%th Value %th Value
%th Protected %th Protected
%th Scope %th Environment scope
%th %th
%tbody %tbody
- @project.variables.order_key_asc.each do |variable| - @project.variables.order_key_asc.each do |variable|
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
%td.variable-key= variable.key %td.variable-key= variable.key
%td.variable-value{ "data-value" => variable.value }****** %td.variable-value{ "data-value" => variable.value }******
%td.variable-protected= Gitlab::Utils.boolean_to_yes_no(variable.protected) %td.variable-protected= Gitlab::Utils.boolean_to_yes_no(variable.protected)
%td.variable-scope= variable.scope %td.variable-environment-scope= variable.environment_scope
%td.variable-menu %td.variable-menu
= link_to namespace_project_variable_path(@project.namespace, @project, variable), class: "btn btn-transparent btn-variable-edit" do = link_to namespace_project_variable_path(@project.namespace, @project, variable), class: "btn btn-transparent btn-variable-edit" do
%span.sr-only %span.sr-only
......
--- ---
title: Add scope to secret variables to specify environments title: Add environment scope to secret variables to specify environments
merge_request: 2112 merge_request: 2112
author: author:
class AddScopeToCiVariables < ActiveRecord::Migration class AddEnvironmentScopeToCiVariables < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
DOWNTIME = false DOWNTIME = false
...@@ -6,10 +6,10 @@ class AddScopeToCiVariables < ActiveRecord::Migration ...@@ -6,10 +6,10 @@ class AddScopeToCiVariables < ActiveRecord::Migration
disable_ddl_transaction! disable_ddl_transaction!
def up def up
add_column_with_default(:ci_variables, :scope, :string, default: '*') add_column_with_default(:ci_variables, :environment_scope, :string, default: '*')
end end
def down def down
remove_column(:ci_variables, :scope) remove_column(:ci_variables, :environment_scope)
end end
end end
...@@ -440,7 +440,7 @@ ActiveRecord::Schema.define(version: 20170612150426) do ...@@ -440,7 +440,7 @@ ActiveRecord::Schema.define(version: 20170612150426) do
t.string "encrypted_value_iv" t.string "encrypted_value_iv"
t.integer "project_id", null: false t.integer "project_id", null: false
t.boolean "protected", default: false, null: false t.boolean "protected", default: false, null: false
t.string "scope", default: "*", null: false t.string "environment_scope", default: "*", null: false
end end
add_index "ci_variables", ["project_id"], name: "index_ci_variables_on_project_id", using: :btree add_index "ci_variables", ["project_id"], name: "index_ci_variables_on_project_id", using: :btree
......
...@@ -67,7 +67,7 @@ POST /projects/:id/variables ...@@ -67,7 +67,7 @@ POST /projects/:id/variables
| `key` | string | yes | The `key` of a variable; must have no more than 255 characters; only `A-Z`, `a-z`, `0-9`, and `_` are allowed | | `key` | string | yes | The `key` of a variable; must have no more than 255 characters; only `A-Z`, `a-z`, `0-9`, and `_` are allowed |
| `value` | string | yes | The `value` of a variable | | `value` | string | yes | The `value` of a variable |
| `protected` | boolean | no | Whether the variable is protected | | `protected` | boolean | no | Whether the variable is protected |
| `scope` | string | no | The `scope` of the variable | | `environment_scope` | string | no | The `environment_scope` of the variable |
``` ```
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value" curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
...@@ -78,7 +78,7 @@ curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitl ...@@ -78,7 +78,7 @@ curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitl
"key": "NEW_VARIABLE", "key": "NEW_VARIABLE",
"value": "new value", "value": "new value",
"protected": false, "protected": false,
"scope": "*" "environment_scope": "*"
} }
``` ```
...@@ -96,7 +96,7 @@ PUT /projects/:id/variables/:key ...@@ -96,7 +96,7 @@ PUT /projects/:id/variables/:key
| `key` | string | yes | The `key` of a variable | | `key` | string | yes | The `key` of a variable |
| `value` | string | yes | The `value` of a variable | | `value` | string | yes | The `value` of a variable |
| `protected` | boolean | no | Whether the variable is protected | | `protected` | boolean | no | Whether the variable is protected |
| `scope` | string | no | The `scope` of the variable | | `environment_scope` | string | no | The `environment_scope` of the variable |
``` ```
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value" curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value"
...@@ -107,7 +107,7 @@ curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitla ...@@ -107,7 +107,7 @@ curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitla
"key": "NEW_VARIABLE", "key": "NEW_VARIABLE",
"value": "updated value", "value": "updated value",
"protected": true, "protected": true,
"scope": "*" "environment_scope": "*"
} }
``` ```
......
...@@ -176,22 +176,23 @@ Protected variables can be added by going to your project's ...@@ -176,22 +176,23 @@ Protected variables can be added by going to your project's
Once you set them, they will be available for all subsequent pipelines. Once you set them, they will be available for all subsequent pipelines.
### Limiting scopes of secret variables ### Limiting environment scopes of secret variables
>**Notes:** >**Notes:**
[Introduced][ee-2112] in [GitLab Enterprise Edition Premium][eep] 9.4. [Introduced][ee-2112] in [GitLab Enterprise Edition Premium][eep] 9.4.
You can limit the scope of a secret variable by [defining which environments][envs] You can limit the environment scope of a secret variable by
it can be available for. [defining which environments][envs] it can be available for.
Wildcards can be used, and the default scope is `*` which means any jobs will Wildcards can be used, and the default environment scope is `*` which means
have this variable, not matter if an environment is defined or not. any jobs will have this variable, not matter if an environment is defined or
not.
For example, if the scope is `production`, then only the jobs having the For example, if the environment scope is `production`, then only the jobs
environment `production` defined would have this specific variable. Wildcards (`*`) having the environment `production` defined would have this specific variable.
can be used along with the environment name, therefore if the scope is `review/*` Wildcards (`*`) can be used along with the environment name, therefore if the
then any jobs with environment names starting with `review/` would have environment scope is `review/*` then any jobs with environment names starting
that particular variable. with `review/` would have that particular variable.
## Deployment variables ## Deployment variables
......
...@@ -753,7 +753,7 @@ module API ...@@ -753,7 +753,7 @@ module API
expose :protected?, as: :protected expose :protected?, as: :protected
# EE # EE
expose :scope expose :environment_scope
end end
class Pipeline < PipelineBasic class Pipeline < PipelineBasic
......
...@@ -45,7 +45,7 @@ module API ...@@ -45,7 +45,7 @@ module API
optional :protected, type: String, desc: 'Whether the variable is protected' optional :protected, type: String, desc: 'Whether the variable is protected'
# EE # EE
optional :scope, type: String, desc: 'The scope of the variable' optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
end end
post ':id/variables' do post ':id/variables' do
variable = user_project.variables.create(declared_params(include_missing: false)) variable = user_project.variables.create(declared_params(include_missing: false))
...@@ -66,7 +66,7 @@ module API ...@@ -66,7 +66,7 @@ module API
optional :protected, type: String, desc: 'Whether the variable is protected' optional :protected, type: String, desc: 'Whether the variable is protected'
# EE # EE
optional :scope, type: String, desc: 'The scope of the variable' optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
end end
put ':id/variables/:key' do put ':id/variables/:key' do
variable = user_project.variables.find_by(key: params[:key]) variable = user_project.variables.find_by(key: params[:key])
......
module EE module EE
module Gitlab module Gitlab
module Regex module Regex
def variable_scope_regex_chars def environment_scope_regex_chars
"#{environment_name_regex_chars}\\*" "#{environment_name_regex_chars}\\*"
end end
def variable_scope_regex def environment_scope_regex
@variable_scope_regex ||= /\A[#{variable_scope_regex_chars}]+\z/.freeze @environment_scope_regex ||= /\A[#{environment_scope_regex_chars}]+\z/.freeze
end end
def variable_scope_regex_message def environment_scope_regex_message
"can contain only letters, digits, '-', '_', '/', '$', '{', '}', '.', '*' and spaces" "can contain only letters, digits, '-', '_', '/', '$', '{', '}', '.', '*' and spaces"
end end
end end
......
...@@ -56,10 +56,10 @@ describe 'Project variables', js: true do ...@@ -56,10 +56,10 @@ describe 'Project variables', js: true do
end end
# EE # EE
it 'adds new variable with a special scope' do it 'adds new variable with a special environment scope' do
fill_in('variable_key', with: 'key') fill_in('variable_key', with: 'key')
fill_in('variable_value', with: 'value') fill_in('variable_value', with: 'value')
fill_in('variable_scope', with: 'review/*') fill_in('variable_environment_scope', with: 'review/*')
click_button('Add new variable') click_button('Add new variable')
expect(page).to have_content('Variables were successfully updated.') expect(page).to have_content('Variables were successfully updated.')
...@@ -158,16 +158,16 @@ describe 'Project variables', js: true do ...@@ -158,16 +158,16 @@ describe 'Project variables', js: true do
end end
# EE # EE
it 'edits variable to be another scope' do it 'edits variable to be another environment scope' do
page.within('.variables-table') do page.within('.variables-table') do
find('.btn-variable-edit').click find('.btn-variable-edit').click
end end
expect(page).to have_content('Update variable') expect(page).to have_content('Update variable')
fill_in('variable_scope', with: 'review/*') fill_in('variable_environment_scope', with: 'review/*')
click_button('Save variable') click_button('Save variable')
expect(page).to have_content('Variable was successfully updated.') expect(page).to have_content('Variable was successfully updated.')
expect(project.variables(true).first.scope).to eq('review/*') expect(project.variables(true).first.environment_scope).to eq('review/*')
end end
end end
...@@ -1417,7 +1417,7 @@ describe Ci::Build, :models do ...@@ -1417,7 +1417,7 @@ describe Ci::Build, :models do
create(:ci_variable, create(:ci_variable,
environment_varialbe.slice(:key, :value) environment_varialbe.slice(:key, :value)
.merge(project: project, scope: 'stag*')) .merge(project: project, environment_scope: 'stag*'))
end end
it { is_expected.to include(environment_varialbe) } it { is_expected.to include(environment_varialbe) }
......
...@@ -12,11 +12,11 @@ describe Ci::Variable, models: true do ...@@ -12,11 +12,11 @@ describe Ci::Variable, models: true do
it { is_expected.not_to allow_value('foo/bar').for(:key) } it { is_expected.not_to allow_value('foo/bar').for(:key) }
# EE # EE
it { is_expected.to allow_value('review/*').for(:scope) } it { is_expected.to allow_value('review/*').for(:environment_scope) }
it { is_expected.not_to allow_value('').for(:scope) } it { is_expected.not_to allow_value('').for(:environment_scope) }
let(:key_scope) do let(:key_scope) do
[:project_id, :scope] # EE [:project_id, :environment_scope] # EE
end end
it { is_expected.to validate_uniqueness_of(:key).scoped_to(key_scope) } it { is_expected.to validate_uniqueness_of(:key).scoped_to(key_scope) }
......
...@@ -2293,9 +2293,9 @@ describe Project, models: true do ...@@ -2293,9 +2293,9 @@ describe Project, models: true do
project.secret_variables_for(ref: 'ref', environment: environment) project.secret_variables_for(ref: 'ref', environment: environment)
end end
context 'when scope is exactly matched' do context 'when environment scope is exactly matched' do
before do before do
secret_variable.update(scope: 'review/name') secret_variable.update(environment_scope: 'review/name')
end end
it 'contains the secret variable' do it 'contains the secret variable' do
...@@ -2303,9 +2303,9 @@ describe Project, models: true do ...@@ -2303,9 +2303,9 @@ describe Project, models: true do
end end
end end
context 'when scope is matched by wildcard' do context 'when environment scope is matched by wildcard' do
before do before do
secret_variable.update(scope: 'review/*') secret_variable.update(environment_scope: 'review/*')
end end
it 'contains the secret variable' do it 'contains the secret variable' do
...@@ -2313,9 +2313,9 @@ describe Project, models: true do ...@@ -2313,9 +2313,9 @@ describe Project, models: true do
end end
end end
context 'when scope does not match' do context 'when environment scope does not match' do
before do before do
secret_variable.update(scope: 'review/*/special') secret_variable.update(environment_scope: 'review/*/special')
end end
it 'does not contain the secret variable' do it 'does not contain the secret variable' do
...@@ -2323,27 +2323,27 @@ describe Project, models: true do ...@@ -2323,27 +2323,27 @@ describe Project, models: true do
end end
end end
context 'when scope has _' do context 'when environment scope has _' do
it 'does not treat it as wildcard' do it 'does not treat it as wildcard' do
secret_variable.update(scope: '*_*') secret_variable.update(environment_scope: '*_*')
is_expected.not_to contain_exactly(secret_variable) is_expected.not_to contain_exactly(secret_variable)
end end
it 'matches literally for _' do it 'matches literally for _' do
secret_variable.update(scope: 'foo_bar/*') secret_variable.update(environment_scope: 'foo_bar/*')
environment.update(name: 'foo_bar/test') environment.update(name: 'foo_bar/test')
is_expected.to contain_exactly(secret_variable) is_expected.to contain_exactly(secret_variable)
end end
end end
context 'when variables with the same name have different scopes' do context 'when variables with the same name have different environment scopes' do
let!(:partially_matched_variable) do let!(:partially_matched_variable) do
create(:ci_variable, create(:ci_variable,
key: secret_variable.key, key: secret_variable.key,
value: 'partial', value: 'partial',
scope: 'review/*', environment_scope: 'review/*',
project: project) project: project)
end end
...@@ -2351,11 +2351,11 @@ describe Project, models: true do ...@@ -2351,11 +2351,11 @@ describe Project, models: true do
create(:ci_variable, create(:ci_variable,
key: secret_variable.key, key: secret_variable.key,
value: 'prefect', value: 'prefect',
scope: 'review/name', environment_scope: 'review/name',
project: project) project: project)
end end
it 'puts variables matching scope more in the end' do it 'puts variables matching environment scope more in the end' do
is_expected.to eq( is_expected.to eq(
[secret_variable, [secret_variable,
partially_matched_variable, partially_matched_variable,
......
...@@ -91,27 +91,27 @@ describe API::Variables do ...@@ -91,27 +91,27 @@ describe API::Variables do
end end
# EE # EE
it 'creates variable with a specific scope' do it 'creates variable with a specific environment scope' do
expect do expect do
post api("/projects/#{project.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2', scope: 'review/*' post api("/projects/#{project.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2', environment_scope: 'review/*'
end.to change{project.variables.count}.by(1) end.to change{project.variables.count}.by(1)
expect(response).to have_http_status(201) expect(response).to have_http_status(201)
expect(json_response['key']).to eq('TEST_VARIABLE_2') expect(json_response['key']).to eq('TEST_VARIABLE_2')
expect(json_response['value']).to eq('VALUE_2') expect(json_response['value']).to eq('VALUE_2')
expect(json_response['scope']).to eq('review/*') expect(json_response['environment_scope']).to eq('review/*')
end end
# EE # EE
it 'allows duplicated variable key given different scopes' do it 'allows duplicated variable key given different environment scopes' do
expect do expect do
post api("/projects/#{project.id}/variables", user), key: variable.key, value: 'VALUE_2', scope: 'review/*' post api("/projects/#{project.id}/variables", user), key: variable.key, value: 'VALUE_2', environment_scope: 'review/*'
end.to change{project.variables.count}.by(1) end.to change{project.variables.count}.by(1)
expect(response).to have_http_status(201) expect(response).to have_http_status(201)
expect(json_response['key']).to eq(variable.key) expect(json_response['key']).to eq(variable.key)
expect(json_response['value']).to eq('VALUE_2') expect(json_response['value']).to eq('VALUE_2')
expect(json_response['scope']).to eq('review/*') expect(json_response['environment_scope']).to eq('review/*')
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment