2020-04-08 14:13:33 +05:30
|
|
|
<script>
|
|
|
|
import {
|
2020-06-23 00:09:42 +05:30
|
|
|
GlAlert,
|
|
|
|
GlButton,
|
|
|
|
GlCollapse,
|
2020-04-22 19:07:51 +05:30
|
|
|
GlDeprecatedButton,
|
2020-06-23 00:09:42 +05:30
|
|
|
GlFormCheckbox,
|
2020-04-08 14:13:33 +05:30
|
|
|
GlFormGroup,
|
|
|
|
GlFormInput,
|
2020-06-23 00:09:42 +05:30
|
|
|
GlFormSelect,
|
2020-04-08 14:13:33 +05:30
|
|
|
GlFormTextarea,
|
|
|
|
GlIcon,
|
2020-06-23 00:09:42 +05:30
|
|
|
GlLink,
|
|
|
|
GlModal,
|
|
|
|
GlSprintf,
|
2020-04-08 14:13:33 +05:30
|
|
|
} from '@gitlab/ui';
|
2020-06-23 00:09:42 +05:30
|
|
|
import Cookies from 'js-cookie';
|
2020-04-22 19:07:51 +05:30
|
|
|
import { mapActions, mapState } from 'vuex';
|
|
|
|
import { __ } from '~/locale';
|
|
|
|
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
|
2020-06-23 00:09:42 +05:30
|
|
|
import {
|
|
|
|
AWS_TOKEN_CONSTANTS,
|
|
|
|
ADD_CI_VARIABLE_MODAL_ID,
|
|
|
|
AWS_TIP_DISMISSED_COOKIE_NAME,
|
|
|
|
AWS_TIP_MESSAGE,
|
|
|
|
} from '../constants';
|
2020-04-22 19:07:51 +05:30
|
|
|
import { awsTokens, awsTokenList } from './ci_variable_autocomplete_tokens';
|
|
|
|
import CiKeyField from './ci_key_field.vue';
|
|
|
|
import CiEnvironmentsDropdown from './ci_environments_dropdown.vue';
|
2020-04-08 14:13:33 +05:30
|
|
|
|
|
|
|
export default {
|
|
|
|
modalId: ADD_CI_VARIABLE_MODAL_ID,
|
|
|
|
components: {
|
2020-04-22 19:07:51 +05:30
|
|
|
CiEnvironmentsDropdown,
|
|
|
|
CiKeyField,
|
2020-06-23 00:09:42 +05:30
|
|
|
GlAlert,
|
|
|
|
GlButton,
|
|
|
|
GlCollapse,
|
2020-04-22 19:07:51 +05:30
|
|
|
GlDeprecatedButton,
|
2020-06-23 00:09:42 +05:30
|
|
|
GlFormCheckbox,
|
2020-04-08 14:13:33 +05:30
|
|
|
GlFormGroup,
|
|
|
|
GlFormInput,
|
2020-06-23 00:09:42 +05:30
|
|
|
GlFormSelect,
|
2020-04-08 14:13:33 +05:30
|
|
|
GlFormTextarea,
|
|
|
|
GlIcon,
|
2020-06-23 00:09:42 +05:30
|
|
|
GlLink,
|
|
|
|
GlModal,
|
|
|
|
GlSprintf,
|
2020-04-08 14:13:33 +05:30
|
|
|
},
|
2020-04-22 19:07:51 +05:30
|
|
|
mixins: [glFeatureFlagsMixin()],
|
|
|
|
tokens: awsTokens,
|
|
|
|
tokenList: awsTokenList,
|
2020-06-23 00:09:42 +05:30
|
|
|
awsTipMessage: AWS_TIP_MESSAGE,
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
isTipDismissed: Cookies.get(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true',
|
|
|
|
};
|
|
|
|
},
|
2020-04-08 14:13:33 +05:30
|
|
|
computed: {
|
|
|
|
...mapState([
|
|
|
|
'projectId',
|
|
|
|
'environments',
|
|
|
|
'typeOptions',
|
|
|
|
'variable',
|
|
|
|
'variableBeingEdited',
|
|
|
|
'isGroup',
|
|
|
|
'maskableRegex',
|
2020-04-22 19:07:51 +05:30
|
|
|
'selectedEnvironment',
|
2020-05-24 23:13:21 +05:30
|
|
|
'isProtectedByDefault',
|
2020-06-23 00:09:42 +05:30
|
|
|
'awsLogoSvgPath',
|
|
|
|
'awsTipDeployLink',
|
|
|
|
'awsTipCommandsLink',
|
|
|
|
'awsTipLearnLink',
|
|
|
|
'protectedEnvironmentVariablesLink',
|
|
|
|
'maskedEnvironmentVariablesLink',
|
2020-04-08 14:13:33 +05:30
|
|
|
]),
|
2020-06-23 00:09:42 +05:30
|
|
|
isTipVisible() {
|
|
|
|
return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variableData.key);
|
|
|
|
},
|
2020-04-08 14:13:33 +05:30
|
|
|
canSubmit() {
|
2020-04-22 19:07:51 +05:30
|
|
|
return (
|
|
|
|
this.variableValidationState &&
|
|
|
|
this.variableData.key !== '' &&
|
|
|
|
this.variableData.secret_value !== ''
|
|
|
|
);
|
2020-04-08 14:13:33 +05:30
|
|
|
},
|
|
|
|
canMask() {
|
|
|
|
const regex = RegExp(this.maskableRegex);
|
|
|
|
return regex.test(this.variableData.secret_value);
|
|
|
|
},
|
|
|
|
displayMaskedError() {
|
2020-04-22 19:07:51 +05:30
|
|
|
return !this.canMask && this.variableData.masked;
|
2020-04-08 14:13:33 +05:30
|
|
|
},
|
|
|
|
maskedState() {
|
|
|
|
if (this.displayMaskedError) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-04-22 19:07:51 +05:30
|
|
|
return true;
|
2020-04-08 14:13:33 +05:30
|
|
|
},
|
|
|
|
variableData() {
|
|
|
|
return this.variableBeingEdited || this.variable;
|
|
|
|
},
|
|
|
|
modalActionText() {
|
|
|
|
return this.variableBeingEdited ? __('Update variable') : __('Add variable');
|
|
|
|
},
|
|
|
|
maskedFeedback() {
|
2020-04-22 19:07:51 +05:30
|
|
|
return this.displayMaskedError ? __('This variable can not be masked.') : '';
|
|
|
|
},
|
|
|
|
tokenValidationFeedback() {
|
|
|
|
const tokenSpecificFeedback = this.$options.tokens?.[this.variableData.key]?.invalidMessage;
|
|
|
|
if (!this.tokenValidationState && tokenSpecificFeedback) {
|
|
|
|
return tokenSpecificFeedback;
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
},
|
|
|
|
tokenValidationState() {
|
|
|
|
// If the feature flag is off, do not validate. Remove when flag is removed.
|
|
|
|
if (!this.glFeatures.ciKeyAutocomplete) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const validator = this.$options.tokens?.[this.variableData.key]?.validation;
|
|
|
|
|
|
|
|
if (validator) {
|
|
|
|
return validator(this.variableData.secret_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
variableValidationFeedback() {
|
|
|
|
return `${this.tokenValidationFeedback} ${this.maskedFeedback}`;
|
|
|
|
},
|
|
|
|
variableValidationState() {
|
|
|
|
if (
|
|
|
|
this.variableData.secret_value === '' ||
|
|
|
|
(this.tokenValidationState && this.maskedState)
|
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2020-04-08 14:13:33 +05:30
|
|
|
},
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
...mapActions([
|
|
|
|
'addVariable',
|
|
|
|
'updateVariable',
|
|
|
|
'resetEditing',
|
|
|
|
'displayInputValue',
|
|
|
|
'clearModal',
|
|
|
|
'deleteVariable',
|
2020-04-22 19:07:51 +05:30
|
|
|
'setEnvironmentScope',
|
|
|
|
'addWildCardScope',
|
|
|
|
'resetSelectedEnvironment',
|
|
|
|
'setSelectedEnvironment',
|
2020-05-24 23:13:21 +05:30
|
|
|
'setVariableProtected',
|
2020-04-08 14:13:33 +05:30
|
|
|
]),
|
2020-06-23 00:09:42 +05:30
|
|
|
dismissTip() {
|
|
|
|
Cookies.set(AWS_TIP_DISMISSED_COOKIE_NAME, 'true', { expires: 90 });
|
|
|
|
this.isTipDismissed = true;
|
|
|
|
},
|
2020-04-22 19:07:51 +05:30
|
|
|
deleteVarAndClose() {
|
|
|
|
this.deleteVariable(this.variableBeingEdited);
|
2020-04-08 14:13:33 +05:30
|
|
|
this.hideModal();
|
|
|
|
},
|
2020-04-22 19:07:51 +05:30
|
|
|
hideModal() {
|
|
|
|
this.$refs.modal.hide();
|
|
|
|
},
|
2020-04-08 14:13:33 +05:30
|
|
|
resetModalHandler() {
|
|
|
|
if (this.variableBeingEdited) {
|
|
|
|
this.resetEditing();
|
|
|
|
} else {
|
|
|
|
this.clearModal();
|
|
|
|
}
|
2020-04-22 19:07:51 +05:30
|
|
|
this.resetSelectedEnvironment();
|
2020-04-08 14:13:33 +05:30
|
|
|
},
|
2020-04-22 19:07:51 +05:30
|
|
|
updateOrAddVariable() {
|
|
|
|
if (this.variableBeingEdited) {
|
|
|
|
this.updateVariable(this.variableBeingEdited);
|
|
|
|
} else {
|
|
|
|
this.addVariable();
|
|
|
|
}
|
2020-04-08 14:13:33 +05:30
|
|
|
this.hideModal();
|
|
|
|
},
|
2020-05-24 23:13:21 +05:30
|
|
|
setVariableProtectedByDefault() {
|
|
|
|
if (this.isProtectedByDefault && !this.variableBeingEdited) {
|
|
|
|
this.setVariableProtected();
|
|
|
|
}
|
|
|
|
},
|
2020-04-08 14:13:33 +05:30
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<gl-modal
|
|
|
|
ref="modal"
|
|
|
|
:modal-id="$options.modalId"
|
|
|
|
:title="modalActionText"
|
2020-04-22 19:07:51 +05:30
|
|
|
static
|
|
|
|
lazy
|
2020-04-08 14:13:33 +05:30
|
|
|
@hidden="resetModalHandler"
|
2020-05-24 23:13:21 +05:30
|
|
|
@shown="setVariableProtectedByDefault"
|
2020-04-08 14:13:33 +05:30
|
|
|
>
|
|
|
|
<form>
|
2020-04-22 19:07:51 +05:30
|
|
|
<ci-key-field
|
|
|
|
v-if="glFeatures.ciKeyAutocomplete"
|
|
|
|
v-model="variableData.key"
|
|
|
|
:token-list="$options.tokenList"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<gl-form-group v-else :label="__('Key')" label-for="ci-variable-key">
|
2020-04-08 14:13:33 +05:30
|
|
|
<gl-form-input
|
|
|
|
id="ci-variable-key"
|
|
|
|
v-model="variableData.key"
|
2020-04-22 19:07:51 +05:30
|
|
|
data-qa-selector="ci_variable_key_field"
|
2020-04-08 14:13:33 +05:30
|
|
|
/>
|
|
|
|
</gl-form-group>
|
|
|
|
|
|
|
|
<gl-form-group
|
|
|
|
:label="__('Value')"
|
|
|
|
label-for="ci-variable-value"
|
2020-04-22 19:07:51 +05:30
|
|
|
:state="variableValidationState"
|
|
|
|
:invalid-feedback="variableValidationFeedback"
|
2020-04-08 14:13:33 +05:30
|
|
|
>
|
|
|
|
<gl-form-textarea
|
|
|
|
id="ci-variable-value"
|
2020-04-22 19:07:51 +05:30
|
|
|
ref="valueField"
|
2020-04-08 14:13:33 +05:30
|
|
|
v-model="variableData.secret_value"
|
2020-04-22 19:07:51 +05:30
|
|
|
:state="variableValidationState"
|
2020-04-08 14:13:33 +05:30
|
|
|
rows="3"
|
|
|
|
max-rows="6"
|
2020-04-22 19:07:51 +05:30
|
|
|
data-qa-selector="ci_variable_value_field"
|
2020-04-08 14:13:33 +05:30
|
|
|
/>
|
|
|
|
</gl-form-group>
|
|
|
|
|
|
|
|
<div class="d-flex">
|
|
|
|
<gl-form-group
|
|
|
|
:label="__('Type')"
|
|
|
|
label-for="ci-variable-type"
|
|
|
|
class="w-50 append-right-15"
|
|
|
|
:class="{ 'w-100': isGroup }"
|
|
|
|
>
|
|
|
|
<gl-form-select
|
|
|
|
id="ci-variable-type"
|
|
|
|
v-model="variableData.variable_type"
|
|
|
|
:options="typeOptions"
|
|
|
|
/>
|
|
|
|
</gl-form-group>
|
|
|
|
|
|
|
|
<gl-form-group
|
|
|
|
v-if="!isGroup"
|
|
|
|
:label="__('Environment scope')"
|
|
|
|
label-for="ci-variable-env"
|
|
|
|
class="w-50"
|
|
|
|
>
|
2020-04-22 19:07:51 +05:30
|
|
|
<ci-environments-dropdown
|
|
|
|
class="w-100"
|
|
|
|
:value="variableData.environment_scope"
|
|
|
|
@selectEnvironment="setEnvironmentScope"
|
|
|
|
@createClicked="addWildCardScope"
|
2020-04-08 14:13:33 +05:30
|
|
|
/>
|
|
|
|
</gl-form-group>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<gl-form-group :label="__('Flags')" label-for="ci-variable-flags">
|
|
|
|
<gl-form-checkbox v-model="variableData.protected" class="mb-0">
|
|
|
|
{{ __('Protect variable') }}
|
2020-06-23 00:09:42 +05:30
|
|
|
<gl-link target="_blank" :href="protectedEnvironmentVariablesLink">
|
2020-04-08 14:13:33 +05:30
|
|
|
<gl-icon name="question" :size="12" />
|
|
|
|
</gl-link>
|
2020-06-23 00:09:42 +05:30
|
|
|
<p class="gl-mt-2 text-secondary">
|
2020-04-08 14:13:33 +05:30
|
|
|
{{ __('Export variable to pipelines running on protected branches and tags only.') }}
|
|
|
|
</p>
|
|
|
|
</gl-form-checkbox>
|
|
|
|
|
|
|
|
<gl-form-checkbox
|
|
|
|
ref="masked-ci-variable"
|
|
|
|
v-model="variableData.masked"
|
2020-04-22 19:07:51 +05:30
|
|
|
data-qa-selector="ci_variable_masked_checkbox"
|
2020-04-08 14:13:33 +05:30
|
|
|
>
|
|
|
|
{{ __('Mask variable') }}
|
2020-06-23 00:09:42 +05:30
|
|
|
<gl-link target="_blank" :href="maskedEnvironmentVariablesLink">
|
2020-04-08 14:13:33 +05:30
|
|
|
<gl-icon name="question" :size="12" />
|
|
|
|
</gl-link>
|
2020-06-23 00:09:42 +05:30
|
|
|
<p class="gl-mt-2 gl-mb-0 text-secondary">
|
2020-04-08 14:13:33 +05:30
|
|
|
{{ __('Variable will be masked in job logs.') }}
|
|
|
|
<span
|
|
|
|
:class="{
|
|
|
|
'bold text-plain': displayMaskedError,
|
|
|
|
}"
|
|
|
|
>
|
|
|
|
{{ __('Requires values to meet regular expression requirements.') }}</span
|
|
|
|
>
|
2020-06-23 00:09:42 +05:30
|
|
|
<gl-link target="_blank" :href="maskedEnvironmentVariablesLink">{{
|
2020-04-08 14:13:33 +05:30
|
|
|
__('More information')
|
|
|
|
}}</gl-link>
|
|
|
|
</p>
|
|
|
|
</gl-form-checkbox>
|
|
|
|
</gl-form-group>
|
|
|
|
</form>
|
2020-06-23 00:09:42 +05:30
|
|
|
<gl-collapse :visible="isTipVisible">
|
|
|
|
<gl-alert
|
|
|
|
:title="__('Deploying to AWS is easy with GitLab')"
|
|
|
|
variant="tip"
|
|
|
|
data-testid="aws-guidance-tip"
|
|
|
|
@dismiss="dismissTip"
|
|
|
|
>
|
|
|
|
<div class="gl-display-flex gl-flex-direction-row">
|
|
|
|
<div>
|
|
|
|
<p>
|
|
|
|
<gl-sprintf :message="$options.awsTipMessage">
|
|
|
|
<template #deployLink="{ content }">
|
|
|
|
<gl-link :href="awsTipDeployLink" target="_blank">{{ content }}</gl-link>
|
|
|
|
</template>
|
|
|
|
<template #commandsLink="{ content }">
|
|
|
|
<gl-link :href="awsTipCommandsLink" target="_blank">{{ content }}</gl-link>
|
|
|
|
</template>
|
|
|
|
</gl-sprintf>
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
<gl-button
|
|
|
|
:href="awsTipLearnLink"
|
|
|
|
target="_blank"
|
|
|
|
category="secondary"
|
|
|
|
variant="info"
|
|
|
|
class="gl-overflow-wrap-break"
|
|
|
|
>{{ __('Learn more about deploying to AWS') }}</gl-button
|
|
|
|
>
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<img
|
|
|
|
class="gl-mt-3"
|
|
|
|
:alt="__('Amazon Web Services Logo')"
|
|
|
|
:src="awsLogoSvgPath"
|
|
|
|
height="32"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</gl-alert>
|
|
|
|
</gl-collapse>
|
2020-04-08 14:13:33 +05:30
|
|
|
<template #modal-footer>
|
2020-04-22 19:07:51 +05:30
|
|
|
<gl-deprecated-button @click="hideModal">{{ __('Cancel') }}</gl-deprecated-button>
|
|
|
|
<gl-deprecated-button
|
2020-04-08 14:13:33 +05:30
|
|
|
v-if="variableBeingEdited"
|
|
|
|
ref="deleteCiVariable"
|
|
|
|
category="secondary"
|
|
|
|
variant="danger"
|
2020-04-22 19:07:51 +05:30
|
|
|
data-qa-selector="ci_variable_delete_button"
|
2020-04-08 14:13:33 +05:30
|
|
|
@click="deleteVarAndClose"
|
2020-04-22 19:07:51 +05:30
|
|
|
>{{ __('Delete variable') }}</gl-deprecated-button
|
2020-04-08 14:13:33 +05:30
|
|
|
>
|
2020-04-22 19:07:51 +05:30
|
|
|
<gl-deprecated-button
|
2020-04-08 14:13:33 +05:30
|
|
|
ref="updateOrAddVariable"
|
|
|
|
:disabled="!canSubmit"
|
|
|
|
variant="success"
|
2020-04-22 19:07:51 +05:30
|
|
|
data-qa-selector="ci_variable_save_button"
|
2020-04-08 14:13:33 +05:30
|
|
|
@click="updateOrAddVariable"
|
|
|
|
>{{ modalActionText }}
|
2020-04-22 19:07:51 +05:30
|
|
|
</gl-deprecated-button>
|
2020-04-08 14:13:33 +05:30
|
|
|
</template>
|
|
|
|
</gl-modal>
|
|
|
|
</template>
|