Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
cf7fdfc9
Commit
cf7fdfc9
authored
Mar 16, 2021
by
Tiger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add environment scope to group variables UI
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56812
parent
c36cf6d0
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
192 additions
and
15 deletions
+192
-15
app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
...scripts/ci_variable_list/components/ci_variable_modal.vue
+13
-2
app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue
...scripts/ci_variable_list/components/ci_variable_table.vue
+3
-1
app/controllers/groups/settings/ci_cd_controller.rb
app/controllers/groups/settings/ci_cd_controller.rb
+12
-0
app/controllers/groups/variables_controller.rb
app/controllers/groups/variables_controller.rb
+2
-0
app/models/group.rb
app/models/group.rb
+1
-1
app/serializers/ci/group_variable_entity.rb
app/serializers/ci/group_variable_entity.rb
+1
-0
ee/app/controllers/ee/groups/settings/ci_cd_controller.rb
ee/app/controllers/ee/groups/settings/ci_cd_controller.rb
+16
-0
ee/app/controllers/ee/groups/variables_controller.rb
ee/app/controllers/ee/groups/variables_controller.rb
+18
-0
ee/spec/controllers/ee/groups/variables_controller_spec.rb
ee/spec/controllers/ee/groups/variables_controller_spec.rb
+54
-0
spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
...end/ci_variable_list/components/ci_variable_modal_spec.js
+59
-2
spec/frontend/ci_variable_list/components/ci_variable_table_spec.js
...end/ci_variable_list/components/ci_variable_table_spec.js
+12
-8
spec/serializers/ci/group_variable_entity_spec.rb
spec/serializers/ci/group_variable_entity_spec.rb
+1
-1
No files found.
app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
View file @
cf7fdfc9
...
...
@@ -7,6 +7,7 @@ import {
GlFormCombobox
,
GlFormGroup
,
GlFormSelect
,
GlFormInput
,
GlFormTextarea
,
GlIcon
,
GlLink
,
...
...
@@ -41,6 +42,7 @@ export default {
GlFormCombobox
,
GlFormGroup
,
GlFormSelect
,
GlFormInput
,
GlFormTextarea
,
GlIcon
,
GlLink
,
...
...
@@ -128,6 +130,12 @@ export default {
return
true
;
},
scopedVariablesEnabled
()
{
return
!
this
.
isGroup
||
this
.
glFeatures
.
scopedGroupVariables
;
},
scopedVariablesAvailable
()
{
return
!
this
.
isGroup
||
this
.
glFeatures
.
groupScopedCiVariables
;
},
variableValidationFeedback
()
{
return
`
${
this
.
tokenValidationFeedback
}
${
this
.
maskedFeedback
}
`
;
},
...
...
@@ -226,24 +234,27 @@ export default {
:label=
"__('Type')"
label-for=
"ci-variable-type"
class=
"w-50 gl-mr-5"
:class=
"
{ 'w-100':
isGroup
}"
:class=
"
{ 'w-100':
!scopedVariablesEnabled
}"
>
<gl-form-select
id=
"ci-variable-type"
v-model=
"variable_type"
:options=
"typeOptions"
/>
</gl-form-group>
<gl-form-group
v-if=
"
!isGroup
"
v-if=
"
scopedVariablesEnabled
"
:label=
"__('Environment scope')"
label-for=
"ci-variable-env"
class=
"w-50"
data-testid=
"environment-scope"
>
<ci-environments-dropdown
v-if=
"scopedVariablesAvailable"
class=
"w-100"
:value=
"environment_scope"
@
selectEnvironment=
"setEnvironmentScope"
@
createClicked=
"addWildCardScope"
/>
<gl-form-input
v-else
v-model=
"environment_scope"
class=
"w-100"
readonly
/>
</gl-form-group>
</div>
...
...
app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue
View file @
cf7fdfc9
...
...
@@ -2,6 +2,7 @@
import
{
GlTable
,
GlButton
,
GlModalDirective
,
GlIcon
}
from
'
@gitlab/ui
'
;
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
import
{
s__
,
__
}
from
'
~/locale
'
;
import
glFeatureFlagsMixin
from
'
~/vue_shared/mixins/gl_feature_flags_mixin
'
;
import
{
ADD_CI_VARIABLE_MODAL_ID
}
from
'
../constants
'
;
import
CiVariablePopover
from
'
./ci_variable_popover.vue
'
;
...
...
@@ -59,6 +60,7 @@ export default {
directives
:
{
GlModalDirective
,
},
mixins
:
[
glFeatureFlagsMixin
()],
computed
:
{
...
mapState
([
'
variables
'
,
'
valuesHidden
'
,
'
isGroup
'
,
'
isLoading
'
,
'
isDeleting
'
]),
valuesButtonText
()
{
...
...
@@ -68,7 +70,7 @@ export default {
return
this
.
variables
&&
this
.
variables
.
length
>
0
;
},
fields
()
{
if
(
this
.
isGroup
)
{
if
(
this
.
isGroup
&&
!
this
.
glFeatures
.
scopedGroupVariables
)
{
return
this
.
$options
.
fields
.
filter
((
field
)
=>
field
.
key
!==
'
environment_scope
'
);
}
return
this
.
$options
.
fields
;
...
...
app/controllers/groups/settings/ci_cd_controller.rb
View file @
cf7fdfc9
...
...
@@ -10,6 +10,8 @@ module Groups
before_action
:authorize_admin_group!
before_action
:authorize_update_max_artifacts_size!
,
only:
[
:update
]
before_action
:define_variables
,
only:
[
:show
]
before_action
:push_feature_flags
,
only:
[
:show
]
before_action
:push_licensed_features
,
only:
[
:show
]
feature_category
:continuous_integration
...
...
@@ -91,6 +93,16 @@ module Groups
def
update_group_params
params
.
require
(
:group
).
permit
(
:max_artifacts_size
)
end
def
push_feature_flags
push_frontend_feature_flag
(
:scoped_group_variables
,
group
)
end
# Overridden in EE
def
push_licensed_features
end
end
end
end
Groups
::
Settings
::
CiCdController
.
prepend_if_ee
(
'EE::Groups::Settings::CiCdController'
)
app/controllers/groups/variables_controller.rb
View file @
cf7fdfc9
...
...
@@ -56,3 +56,5 @@ module Groups
end
end
end
Groups
::
VariablesController
.
prepend_if_ee
(
'EE::Groups::VariablesController'
)
app/models/group.rb
View file @
cf7fdfc9
...
...
@@ -86,7 +86,7 @@ class Group < Namespace
validate
:visibility_level_allowed_by_sub_groups
validate
:visibility_level_allowed_by_parent
validate
:two_factor_authentication_allowed
validates
:variables
,
nested_attributes_duplicates:
true
validates
:variables
,
nested_attributes_duplicates:
{
scope: :environment_scope
}
validates
:two_factor_grace_period
,
presence:
true
,
numericality:
{
greater_than_or_equal_to:
0
}
...
...
app/serializers/ci/group_variable_entity.rb
View file @
cf7fdfc9
...
...
@@ -2,5 +2,6 @@
module
Ci
class
GroupVariableEntity
<
Ci
::
BasicVariableEntity
expose
:environment_scope
end
end
ee/app/controllers/ee/groups/settings/ci_cd_controller.rb
0 → 100644
View file @
cf7fdfc9
# frozen_string_literal: true
module
EE
module
Groups
module
Settings
module
CiCdController
extend
::
Gitlab
::
Utils
::
Override
override
:push_licensed_features
def
push_licensed_features
push_licensed_feature
(
:group_scoped_ci_variables
,
group
)
end
end
end
end
end
ee/app/controllers/ee/groups/variables_controller.rb
0 → 100644
View file @
cf7fdfc9
# frozen_string_literal: true
module
EE
module
Groups
module
VariablesController
extend
::
Gitlab
::
Utils
::
Override
override
:variable_params_attributes
def
variable_params_attributes
if
group
.
scoped_variables_available?
super
<<
:environment_scope
else
super
end
end
end
end
end
ee/spec/controllers/ee/groups/variables_controller_spec.rb
0 → 100644
View file @
cf7fdfc9
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Groups
::
VariablesController
do
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:variable
)
{
create
(
:ci_group_variable
,
group:
group
,
environment_scope:
'*'
)
}
before
do
sign_in
(
user
)
group
.
add_user
(
user
,
:owner
)
end
describe
'PATCH #update'
do
let
(
:params
)
do
{
group_id:
group
,
variables_attributes:
[{
id:
variable
.
id
,
environment_scope:
'production'
}]
}
end
before
do
stub_licensed_features
(
group_scoped_ci_variables:
scoped_variables_available
)
end
subject
{
patch
:update
,
params:
params
,
format: :json
}
context
'scoped variables are available'
do
let
(
:scoped_variables_available
)
{
true
}
it
'updates the environment scope'
do
subject
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
variable
.
reload
.
environment_scope
).
to
eq
(
'production'
)
end
end
context
'scoped variables are not available'
do
let
(
:scoped_variables_available
)
{
false
}
it
'does not update the environment scope'
do
subject
expect
(
response
).
to
have_gitlab_http_status
(
:ok
)
expect
(
variable
.
reload
.
environment_scope
).
to
eq
(
'*'
)
end
end
end
end
spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
View file @
cf7fdfc9
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
{
GlButton
,
GlFormInput
}
from
'
@gitlab/ui
'
;
import
{
createLocalVue
,
shallowMount
,
mount
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
CiEnvironmentsDropdown
from
'
~/ci_variable_list/components/ci_environments_dropdown.vue
'
;
import
CiVariableModal
from
'
~/ci_variable_list/components/ci_variable_modal.vue
'
;
import
{
AWS_ACCESS_KEY_ID
}
from
'
~/ci_variable_list/constants
'
;
import
createStore
from
'
~/ci_variable_list/store
'
;
...
...
@@ -15,7 +16,7 @@ describe('Ci variable modal', () => {
let
store
;
const
createComponent
=
(
method
,
options
=
{})
=>
{
store
=
createStore
();
store
=
createStore
(
{
isGroup
:
options
.
isGroup
}
);
wrapper
=
method
(
CiVariableModal
,
{
attachTo
:
document
.
body
,
stubs
:
{
...
...
@@ -27,6 +28,7 @@ describe('Ci variable modal', () => {
});
};
const
findCiEnvironmentsDropdown
=
()
=>
wrapper
.
find
(
CiEnvironmentsDropdown
);
const
findModal
=
()
=>
wrapper
.
find
(
ModalStub
);
const
findAddorUpdateButton
=
()
=>
findModal
()
...
...
@@ -149,6 +151,61 @@ describe('Ci variable modal', () => {
});
});
describe
(
'
Environment scope
'
,
()
=>
{
describe
(
'
group level variables
'
,
()
=>
{
it
(
'
renders the environment dropdown
'
,
()
=>
{
createComponent
(
shallowMount
,
{
isGroup
:
true
,
provide
:
{
glFeatures
:
{
scopedGroupVariables
:
true
,
groupScopedCiVariables
:
true
,
},
},
});
expect
(
findCiEnvironmentsDropdown
().
exists
()).
toBe
(
true
);
expect
(
findCiEnvironmentsDropdown
().
isVisible
()).
toBe
(
true
);
});
describe
(
'
feature flag is disabled
'
,
()
=>
{
it
(
'
hides the dropdown
'
,
()
=>
{
createComponent
(
shallowMount
,
{
isGroup
:
true
,
provide
:
{
glFeatures
:
{
scopedGroupVariables
:
false
,
groupScopedCiVariables
:
true
,
},
},
});
expect
(
findCiEnvironmentsDropdown
().
exists
()).
toBe
(
false
);
});
});
describe
(
'
licensed feature is not available
'
,
()
=>
{
it
(
'
disables the dropdown
'
,
()
=>
{
createComponent
(
mount
,
{
isGroup
:
true
,
provide
:
{
glFeatures
:
{
scopedGroupVariables
:
true
,
groupScopedCiVariables
:
false
,
},
},
});
const
environmentScopeInput
=
wrapper
.
find
(
'
[data-testid="environment-scope"]
'
)
.
find
(
GlFormInput
);
expect
(
findCiEnvironmentsDropdown
().
exists
()).
toBe
(
false
);
expect
(
environmentScopeInput
.
attributes
(
'
readonly
'
)).
toBe
(
'
readonly
'
);
});
});
});
});
describe
(
'
Validations
'
,
()
=>
{
const
maskError
=
'
This variable can not be masked.
'
;
...
...
spec/frontend/ci_variable_list/components/ci_variable_table_spec.js
View file @
cf7fdfc9
import
{
GlTable
}
from
'
@gitlab/ui
'
;
import
{
createLocalVue
,
mount
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
CiVariableTable
from
'
~/ci_variable_list/components/ci_variable_table.vue
'
;
...
...
@@ -12,21 +11,24 @@ describe('Ci variable table', () => {
let
wrapper
;
let
store
;
const
createComponent
=
()
=>
{
store
=
createStore
();
store
.
state
.
isGroup
=
true
;
const
createComponent
=
(
isGroup
=
false
,
scopedGroupVariables
=
false
)
=>
{
store
=
createStore
({
isGroup
});
jest
.
spyOn
(
store
,
'
dispatch
'
).
mockImplementation
();
wrapper
=
mount
(
CiVariableTable
,
{
attachTo
:
document
.
body
,
localVue
,
store
,
provide
:
{
glFeatures
:
{
scopedGroupVariables
,
},
},
});
};
const
findRevealButton
=
()
=>
wrapper
.
find
({
ref
:
'
secret-value-reveal-button
'
});
const
findEditButton
=
()
=>
wrapper
.
find
({
ref
:
'
edit-ci-variable
'
});
const
findEmptyVariablesPlaceholder
=
()
=>
wrapper
.
find
({
ref
:
'
empty-variables
'
});
const
findTable
=
()
=>
wrapper
.
find
(
GlTable
);
beforeEach
(()
=>
{
createComponent
();
...
...
@@ -40,12 +42,14 @@ describe('Ci variable table', () => {
expect
(
store
.
dispatch
).
toHaveBeenCalledWith
(
'
fetchVariables
'
);
});
it
(
'
fields prop does not contain environment_scope if group
'
,
()
=>
{
expect
(
findTable
().
props
(
'
fields
'
)).
not
.
toEqual
(
it
(
'
fields do not contain environment_scope if group level and feature is disabled
'
,
()
=>
{
createComponent
(
true
,
false
);
expect
(
wrapper
.
vm
.
fields
).
not
.
toEqual
(
expect
.
arrayContaining
([
expect
.
objectContaining
({
key
:
'
environment_scope
'
,
label
:
'
Environment
Scope
'
,
label
:
'
Environment
s
'
,
}),
]),
);
...
...
spec/serializers/ci/group_variable_entity_spec.rb
View file @
cf7fdfc9
...
...
@@ -10,7 +10,7 @@ RSpec.describe Ci::GroupVariableEntity do
subject
{
entity
.
as_json
}
it
'contains required fields'
do
expect
(
subject
).
to
include
(
:id
,
:key
,
:value
,
:protected
,
:variable_type
)
expect
(
subject
).
to
include
(
:id
,
:key
,
:value
,
:protected
,
:variable_type
,
:environment_scope
)
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment