Commit 7e35adeb authored by Jose Vargas's avatar Jose Vargas

Remove new_ci_variables_list feature flag

This removes the new_ci_variables_list
feature flag while also removing unused
haml code and related specs
parent 524ae855
import initSettingsPanels from '~/settings_panels';
import AjaxVariableList from '~/ci_variable_list/ajax_variable_list';
import initVariableList from '~/ci_variable_list';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import GroupRunnersFilteredSearchTokenKeys from '~/filtered_search/group_runners_filtered_search_token_keys';
......@@ -17,19 +16,6 @@ document.addEventListener('DOMContentLoaded', () => {
useDefaultState: false,
});
if (gon.features.newVariablesUi) {
initVariableList();
} else {
const variableListEl = document.querySelector('.js-ci-variable-list-section');
// eslint-disable-next-line no-new
new AjaxVariableList({
container: variableListEl,
saveButton: variableListEl.querySelector('.js-ci-variables-save-button'),
errorBox: variableListEl.querySelector('.js-ci-variable-error-box'),
saveEndpoint: variableListEl.dataset.saveEndpoint,
maskableRegex: variableListEl.dataset.maskableRegex,
});
}
initSharedRunnersForm();
initVariableList();
});
import initSettingsPanels from '~/settings_panels';
import SecretValues from '~/behaviors/secret_values';
import AjaxVariableList from '~/ci_variable_list/ajax_variable_list';
import registrySettingsApp from '~/registry/settings/registry_settings_bundle';
import initVariableList from '~/ci_variable_list';
import initDeployFreeze from '~/deploy_freeze';
......@@ -18,19 +17,7 @@ document.addEventListener('DOMContentLoaded', () => {
runnerTokenSecretValue.init();
}
if (gon.features.newVariablesUi) {
initVariableList();
} else {
const variableListEl = document.querySelector('.js-ci-variable-list-section');
// eslint-disable-next-line no-new
new AjaxVariableList({
container: variableListEl,
saveButton: variableListEl.querySelector('.js-ci-variables-save-button'),
errorBox: variableListEl.querySelector('.js-ci-variable-error-box'),
saveEndpoint: variableListEl.dataset.saveEndpoint,
maskableRegex: variableListEl.dataset.maskableRegex,
});
}
initVariableList();
// hide extra auto devops settings based checkbox state
const autoDevOpsExtraSettings = document.querySelector('.js-extra-settings');
......
......@@ -8,9 +8,6 @@ module Groups
skip_cross_project_access_check :show
before_action :authorize_admin_group!
before_action :authorize_update_max_artifacts_size!, only: [:update]
before_action do
push_frontend_feature_flag(:new_variables_ui, @group, default_enabled: true)
end
before_action :define_variables, only: [:show]
feature_category :continuous_integration
......
......@@ -8,7 +8,6 @@ module Projects
before_action :authorize_admin_pipeline!
before_action :define_variables
before_action do
push_frontend_feature_flag(:new_variables_ui, @project, default_enabled: true)
push_frontend_feature_flag(:ajax_new_deploy_token, @project)
end
......
......@@ -5,42 +5,20 @@
- link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable') }
= s_('Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
- if Feature.enabled?(:new_variables_ui, @project || @group, default_enabled: true)
- is_group = !@group.nil?
- is_group = !@group.nil?
#js-ci-project-variables{ data: { endpoint: save_endpoint,
project_id: @project&.id || '',
group: is_group.to_s,
maskable_regex: ci_variable_maskable_regex,
protected_by_default: ci_variable_protected_by_default?.to_s,
aws_logo_svg_path: image_path('aws_logo.svg'),
aws_tip_deploy_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'deploy-your-application-to-the-aws-elastic-container-service-ecs'),
aws_tip_commands_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'run-aws-commands-from-gitlab-cicd'),
aws_tip_learn_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'aws'),
protected_environment_variables_link: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable'),
masked_environment_variables_link: help_page_path('ci/variables/README', anchor: 'mask-a-custom-variable'),
} }
- else
.row
.col-lg-12.js-ci-variable-list-section{ data: { save_endpoint: save_endpoint, maskable_regex: ci_variable_maskable_regex } }
.hide.gl-alert.gl-alert-danger.js-ci-variable-error-box
%ul.ci-variable-list
= render 'ci/variables/variable_header'
- @variables.each.each do |variable|
= render 'ci/variables/variable_row', form_field: 'variables', variable: variable
= render 'ci/variables/variable_row', form_field: 'variables'
.prepend-top-20
%button.btn.btn-success.js-ci-variables-save-button{ type: 'button' }
%span.hide.js-ci-variables-save-loading-icon
.spinner.spinner-light.mr-1
= _('Save variables')
%button.btn.btn-info.btn-inverted.gl-ml-3.js-secret-value-reveal-button{ type: 'button', data: { secret_reveal_status: "#{@variables.size == 0}" } }
- if @variables.size == 0
= n_('Hide value', 'Hide values', @variables.size)
- else
= n_('Reveal value', 'Reveal values', @variables.size)
#js-ci-project-variables{ data: { endpoint: save_endpoint,
project_id: @project&.id || '',
group: is_group.to_s,
maskable_regex: ci_variable_maskable_regex,
protected_by_default: ci_variable_protected_by_default?.to_s,
aws_logo_svg_path: image_path('aws_logo.svg'),
aws_tip_deploy_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'deploy-your-application-to-the-aws-elastic-container-service-ecs'),
aws_tip_commands_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'run-aws-commands-from-gitlab-cicd'),
aws_tip_learn_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'aws'),
protected_environment_variables_link: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable'),
masked_environment_variables_link: help_page_path('ci/variables/README', anchor: 'mask-a-custom-variable'),
} }
- if !@group && @project.group
.settings-header.border-top.prepend-top-20
......
---
title: Remove new_ci_variables_list feature flag
merge_request: 41412
author:
type: other
import $ from 'jquery';
import VariableList from '~/ci_variable_list/ci_variable_list';
describe('VariableList (EE features)', () => {
preloadFixtures('projects/ci_cd_settings.html');
let $wrapper;
let variableList;
describe('with all inputs(key, value, protected, environment)', () => {
beforeEach(() => {
loadFixtures('projects/ci_cd_settings.html');
$wrapper = $('.js-ci-variable-list-section');
variableList = new VariableList({
container: $wrapper,
formField: 'variables',
});
variableList.init();
});
describe('environment dropdown', () => {
function addRowByNewEnvironment(newEnv) {
const $row = $wrapper.find('.js-row:last-child');
// Open the dropdown
$row.find('.js-variable-environment-toggle').click();
// Filter for the new item
$row
.find('.js-variable-environment-dropdown-wrapper .dropdown-input-field')
.val(newEnv)
.trigger('input');
// Create the new item
$row.find('.js-variable-environment-dropdown-wrapper .js-dropdown-create-new-item').click();
}
it('should add another row when editing the last rows environment dropdown', () => {
addRowByNewEnvironment('someenv');
jest.runOnlyPendingTimers();
expect($wrapper.find('.js-row')).toHaveLength(2);
// Check for the correct default in the new row
const $environmentInput = $wrapper
.find('.js-row:last-child')
.find('input[name="variables[variables_attributes][][environment_scope]"]');
expect($environmentInput.val()).toBe('*');
});
it('should update dropdown with new environment values and remove values when row is removed', () => {
addRowByNewEnvironment('someenv');
const $row = $wrapper.find('.js-row:last-child');
$row.find('.js-variable-environment-toggle').click();
jest.runOnlyPendingTimers();
const $dropdownItemsBeforeRemove = $row.find(
'.js-variable-environment-dropdown-wrapper .dropdown-content a',
);
expect($dropdownItemsBeforeRemove).toHaveLength(2);
expect($dropdownItemsBeforeRemove[0].textContent.trim()).toBe('someenv');
expect($dropdownItemsBeforeRemove[1].textContent.trim()).toBe('* (All environments)');
$wrapper.find('.js-row-remove-button').trigger('click');
expect($wrapper.find('.js-row')).toHaveLength(0);
jest.runOnlyPendingTimers();
const $dropdownItemsAfterRemove = $row.find(
'.js-variable-environment-dropdown-wrapper .dropdown-content a',
);
expect($dropdownItemsAfterRemove).toHaveLength(1);
expect($dropdownItemsAfterRemove[0].textContent.trim()).toBe('* (All environments)');
});
});
});
});
......@@ -23008,9 +23008,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
msgid "Save variables"
msgstr ""
msgid "Saved scan settings and target site settings which are reusable."
msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Group variables', :js do
let(:user) { create(:user) }
let(:group) { create(:group) }
let!(:variable) { create(:ci_group_variable, key: 'test_key', value: 'test_value', masked: true, group: group) }
let(:page_path) { group_settings_ci_cd_path(group) }
before do
group.add_owner(user)
gitlab_sign_in(user)
stub_feature_flags(new_variables_ui: false)
visit page_path
end
it_behaves_like 'variable list'
end
......@@ -24,7 +24,6 @@ RSpec.describe 'Project group variables', :js do
sign_in(user)
project.add_maintainer(user)
group.add_owner(user)
stub_feature_flags(new_variables_ui: false)
end
it 'project in group shows inherited vars from ancestor group' do
......@@ -50,12 +49,4 @@ RSpec.describe 'Project group variables', :js do
expect(page).to have_content(subgroup.name)
expect(page).to have_content(subgroup_nested.name)
end
it 'project origin keys link to ancestor groups ci_cd settings' do
visit project_path
find('.group-origin-link').click
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq(key1)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Project variables', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:variable) { create(:ci_variable, key: 'test_key', value: 'test_value', masked: true) }
let(:page_path) { project_settings_ci_cd_path(project) }
before do
sign_in(user)
project.add_maintainer(user)
project.variables << variable
stub_feature_flags(new_variables_ui: false)
visit page_path
end
it_behaves_like 'variable list'
it 'adds new variable with a special environment scope' do
page.within('.js-ci-variable-list-section .js-row:last-child') do
find('.js-ci-variable-input-key').set('somekey')
find('.js-ci-variable-input-value').set('somevalue')
find('.js-variable-environment-toggle').click
find('.js-variable-environment-dropdown-wrapper .dropdown-input-field').set('review/*')
find('.js-variable-environment-dropdown-wrapper .js-dropdown-create-new-item').click
expect(find('input[name="variables[variables_attributes][][environment_scope]"]', visible: false).value).to eq('review/*')
end
click_button('Save variables')
wait_for_requests
visit page_path
page.within('.js-ci-variable-list-section .js-row:nth-child(2)') do
expect(find('.js-ci-variable-input-key').value).to eq('somekey')
expect(page).to have_content('review/*')
end
end
end
import $ from 'jquery';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import AjaxFormVariableList from '~/ci_variable_list/ajax_variable_list';
const VARIABLE_PATCH_ENDPOINT = 'http://test.host/frontend-fixtures/builds-project/-/variables';
const HIDE_CLASS = 'hide';
describe('AjaxFormVariableList', () => {
preloadFixtures('projects/ci_cd_settings.html');
preloadFixtures('projects/ci_cd_settings_with_variables.html');
let container;
let saveButton;
let errorBox;
let mock;
let ajaxVariableList;
beforeEach(() => {
loadFixtures('projects/ci_cd_settings.html');
container = document.querySelector('.js-ci-variable-list-section');
mock = new MockAdapter(axios);
const ajaxVariableListEl = document.querySelector('.js-ci-variable-list-section');
saveButton = ajaxVariableListEl.querySelector('.js-ci-variables-save-button');
errorBox = container.querySelector('.js-ci-variable-error-box');
ajaxVariableList = new AjaxFormVariableList({
container,
formField: 'variables',
saveButton,
errorBox,
saveEndpoint: container.dataset.saveEndpoint,
maskableRegex: container.dataset.maskableRegex,
});
jest.spyOn(ajaxVariableList, 'updateRowsWithPersistedVariables');
jest.spyOn(ajaxVariableList.variableList, 'toggleEnableRow');
});
afterEach(() => {
mock.restore();
});
describe('onSaveClicked', () => {
it('shows loading spinner while waiting for the request', () => {
const loadingIcon = saveButton.querySelector('.js-ci-variables-save-loading-icon');
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(() => {
expect(loadingIcon.classList.contains(HIDE_CLASS)).toEqual(false);
return [200, {}];
});
expect(loadingIcon.classList.contains(HIDE_CLASS)).toEqual(true);
return ajaxVariableList.onSaveClicked().then(() => {
expect(loadingIcon.classList.contains(HIDE_CLASS)).toEqual(true);
});
});
it('calls `updateRowsWithPersistedVariables` with the persisted variables', () => {
const variablesResponse = [{ id: 1, key: 'foo', value: 'bar' }];
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(200, {
variables: variablesResponse,
});
return ajaxVariableList.onSaveClicked().then(() => {
expect(ajaxVariableList.updateRowsWithPersistedVariables).toHaveBeenCalledWith(
variablesResponse,
);
});
});
it('hides any previous error box', () => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(200);
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
return ajaxVariableList.onSaveClicked().then(() => {
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
});
});
it('disables remove buttons while waiting for the request', () => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(() => {
expect(ajaxVariableList.variableList.toggleEnableRow).toHaveBeenCalledWith(false);
return [200, {}];
});
return ajaxVariableList.onSaveClicked().then(() => {
expect(ajaxVariableList.variableList.toggleEnableRow).toHaveBeenCalledWith(true);
});
});
it('hides secret values', () => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(200, {});
const row = container.querySelector('.js-row');
const valueInput = row.querySelector('.js-ci-variable-input-value');
const valuePlaceholder = row.querySelector('.js-secret-value-placeholder');
valueInput.value = 'bar';
$(valueInput).trigger('input');
expect(valuePlaceholder.classList.contains(HIDE_CLASS)).toBe(true);
expect(valueInput.classList.contains(HIDE_CLASS)).toBe(false);
return ajaxVariableList.onSaveClicked().then(() => {
expect(valuePlaceholder.classList.contains(HIDE_CLASS)).toBe(false);
expect(valueInput.classList.contains(HIDE_CLASS)).toBe(true);
});
});
it('shows error box with validation errors', () => {
const validationError = 'some validation error';
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(400, [validationError]);
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
return ajaxVariableList.onSaveClicked().then(() => {
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(false);
expect(errorBox.textContent.trim().replace(/\n+\s+/m, ' ')).toEqual(
`Validation failed ${validationError}`,
);
});
});
it('shows flash message when request fails', () => {
mock.onPatch(VARIABLE_PATCH_ENDPOINT).reply(500);
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
return ajaxVariableList.onSaveClicked().then(() => {
expect(errorBox.classList.contains(HIDE_CLASS)).toEqual(true);
});
});
});
describe('updateRowsWithPersistedVariables', () => {
beforeEach(() => {
loadFixtures('projects/ci_cd_settings_with_variables.html');
container = document.querySelector('.js-ci-variable-list-section');
const ajaxVariableListEl = document.querySelector('.js-ci-variable-list-section');
saveButton = ajaxVariableListEl.querySelector('.js-ci-variables-save-button');
errorBox = container.querySelector('.js-ci-variable-error-box');
ajaxVariableList = new AjaxFormVariableList({
container,
formField: 'variables',
saveButton,
errorBox,
saveEndpoint: container.dataset.saveEndpoint,
});
});
it('removes variable that was removed', () => {
expect(container.querySelectorAll('.js-row').length).toBe(3);
container.querySelector('.js-row-remove-button').click();
expect(container.querySelectorAll('.js-row').length).toBe(3);
ajaxVariableList.updateRowsWithPersistedVariables([]);
expect(container.querySelectorAll('.js-row').length).toBe(2);
});
it('updates new variable row with persisted ID', () => {
const row = container.querySelector('.js-row:last-child');
const idInput = row.querySelector('.js-ci-variable-input-id');
const keyInput = row.querySelector('.js-ci-variable-input-key');
const valueInput = row.querySelector('.js-ci-variable-input-value');
keyInput.value = 'foo';
$(keyInput).trigger('input');
valueInput.value = 'bar';
$(valueInput).trigger('input');
expect(idInput.value).toEqual('');
ajaxVariableList.updateRowsWithPersistedVariables([
{
id: 3,
key: 'foo',
value: 'bar',
},
]);
expect(idInput.value).toEqual('3');
expect(row.dataset.isPersisted).toEqual('true');
});
});
describe('maskableRegex', () => {
it('takes in the regex provided by the data attribute', () => {
expect(container.dataset.maskableRegex).toBe('^[a-zA-Z0-9_+=/@:.-]{8,}$');
expect(ajaxVariableList.maskableRegex).toBe(container.dataset.maskableRegex);
});
});
});
import $ from 'jquery';
import waitForPromises from 'helpers/wait_for_promises';
import VariableList from '~/ci_variable_list/ci_variable_list';
const HIDE_CLASS = 'hide';
......@@ -7,7 +6,6 @@ const HIDE_CLASS = 'hide';
describe('VariableList', () => {
preloadFixtures('pipeline_schedules/edit.html');
preloadFixtures('pipeline_schedules/edit_with_variables.html');
preloadFixtures('projects/ci_cd_settings.html');
let $wrapper;
let variableList;
......@@ -113,92 +111,6 @@ describe('VariableList', () => {
});
});
describe('with all inputs(key, value, protected)', () => {
beforeEach(() => {
loadFixtures('projects/ci_cd_settings.html');
$wrapper = $('.js-ci-variable-list-section');
$wrapper.find('.js-ci-variable-input-protected').attr('data-default', 'false');
variableList = new VariableList({
container: $wrapper,
formField: 'variables',
});
variableList.init();
});
it('should not add another row when editing the last rows protected checkbox', () => {
const $row = $wrapper.find('.js-row:last-child');
$row.find('.ci-variable-protected-item .js-project-feature-toggle').click();
return waitForPromises().then(() => {
expect($wrapper.find('.js-row').length).toBe(1);
});
});
it('should not add another row when editing the last rows masked checkbox', () => {
jest.spyOn(variableList, 'checkIfRowTouched');
const $row = $wrapper.find('.js-row:last-child');
$row.find('.ci-variable-masked-item .js-project-feature-toggle').click();
return waitForPromises().then(() => {
// This validates that we are checking after the event listener has run
expect(variableList.checkIfRowTouched).toHaveBeenCalled();
expect($wrapper.find('.js-row').length).toBe(1);
});
});
describe('validateMaskability', () => {
let $row;
const maskingErrorElement = '.js-row:last-child .masking-validation-error';
const clickToggle = () =>
$row.find('.ci-variable-masked-item .js-project-feature-toggle').click();
beforeEach(() => {
$row = $wrapper.find('.js-row:last-child');
});
it('has a regex provided via a data attribute', () => {
clickToggle();
expect($wrapper.attr('data-maskable-regex')).toBe('^[a-zA-Z0-9_+=/@:.-]{8,}$');
});
it('allows values that are 8 characters long', () => {
$row.find('.js-ci-variable-input-value').val('looooong');
clickToggle();
expect($wrapper.find(maskingErrorElement)).toHaveClass('hide');
});
it('rejects values that are shorter than 8 characters', () => {
$row.find('.js-ci-variable-input-value').val('short');
clickToggle();
expect($wrapper.find(maskingErrorElement)).toBeVisible();
});
it('allows values with base 64 characters', () => {
$row.find('.js-ci-variable-input-value').val('abcABC123_+=/-');
clickToggle();
expect($wrapper.find(maskingErrorElement)).toHaveClass('hide');
});
it('rejects values with other special characters', () => {
$row.find('.js-ci-variable-input-value').val('1234567$');
clickToggle();
expect($wrapper.find(maskingErrorElement)).toBeVisible();
});
});
});
describe('toggleEnableRow method', () => {
beforeEach(() => {
loadFixtures('pipeline_schedules/edit_with_variables.html');
......@@ -247,36 +159,4 @@ describe('VariableList', () => {
expect($wrapper.find('.js-ci-variable-input-key:not([disabled])').length).toBe(3);
});
});
describe('hideValues', () => {
beforeEach(() => {
loadFixtures('projects/ci_cd_settings.html');
$wrapper = $('.js-ci-variable-list-section');
variableList = new VariableList({
container: $wrapper,
formField: 'variables',
});
variableList.init();
});
it('should hide value input and show placeholder stars', () => {
const $row = $wrapper.find('.js-row');
const $inputValue = $row.find('.js-ci-variable-input-value');
const $placeholder = $row.find('.js-secret-value-placeholder');
$row
.find('.js-ci-variable-input-value')
.val('foo')
.trigger('input');
expect($placeholder.hasClass(HIDE_CLASS)).toBe(true);
expect($inputValue.hasClass(HIDE_CLASS)).toBe(false);
variableList.hideValues();
expect($placeholder.hasClass(HIDE_CLASS)).toBe(false);
expect($inputValue.hasClass(HIDE_CLASS)).toBe(true);
});
});
});
......@@ -15,7 +15,6 @@ RSpec.describe 'Groups (JavaScript fixtures)', type: :controller do
end
before do
stub_feature_flags(new_variables_ui: false)
group.add_maintainer(admin)
sign_in(admin)
end
......@@ -27,12 +26,4 @@ RSpec.describe 'Groups (JavaScript fixtures)', type: :controller do
expect(response).to be_successful
end
end
describe Groups::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do
it 'groups/ci_cd_settings.html' do
get :show, params: { group_id: group }
expect(response).to be_successful
end
end
end
......@@ -20,7 +20,6 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller do
end
before do
stub_feature_flags(new_variables_ui: false)
project.add_maintainer(admin)
sign_in(admin)
allow(SecureRandom).to receive(:hex).and_return('securerandomhex:thereisnospoon')
......@@ -58,27 +57,4 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller do
expect(response).to be_successful
end
end
describe Projects::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do
it 'projects/ci_cd_settings.html' do
get :show, params: {
namespace_id: project.namespace.to_param,
project_id: project
}
expect(response).to be_successful
end
it 'projects/ci_cd_settings_with_variables.html' do
create(:ci_variable, project: project_variable_populated)
create(:ci_variable, project: project_variable_populated)
get :show, params: {
namespace_id: project_variable_populated.namespace.to_param,
project_id: project_variable_populated
}
expect(response).to be_successful
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