Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
0a850868df
commit
cc6b394a06
|
@ -1 +1 @@
|
||||||
1.66.0
|
1.67.0
|
||||||
|
|
|
@ -3,6 +3,8 @@ import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_searc
|
||||||
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
|
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
|
||||||
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
|
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
|
||||||
|
|
||||||
|
const findItem = (items, valueProp, value) => items.find(item => item[valueProp] === value);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DropdownButton,
|
DropdownButton,
|
||||||
|
@ -26,7 +28,7 @@ export default {
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
type: Object,
|
type: [Object, String],
|
||||||
required: false,
|
required: false,
|
||||||
default: () => null,
|
default: () => null,
|
||||||
},
|
},
|
||||||
|
@ -93,8 +95,8 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
selectedItem: findItem(this.items, this.value),
|
||||||
searchQuery: '',
|
searchQuery: '',
|
||||||
selectedItem: null,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -127,10 +129,15 @@ export default {
|
||||||
return (this.selectedItem && this.selectedItem[this.valueProperty]) || '';
|
return (this.selectedItem && this.selectedItem[this.valueProperty]) || '';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
value(value) {
|
||||||
|
this.selectedItem = findItem(this.items, this.valueProperty, value);
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
select(item) {
|
select(item) {
|
||||||
this.selectedItem = item;
|
this.selectedItem = item;
|
||||||
this.$emit('input', item);
|
this.$emit('input', item[this.valueProperty]);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,12 +3,15 @@ import { createNamespacedHelpers, mapState, mapActions } from 'vuex';
|
||||||
import { sprintf, s__ } from '~/locale';
|
import { sprintf, s__ } from '~/locale';
|
||||||
import ClusterFormDropdown from './cluster_form_dropdown.vue';
|
import ClusterFormDropdown from './cluster_form_dropdown.vue';
|
||||||
import RegionDropdown from './region_dropdown.vue';
|
import RegionDropdown from './region_dropdown.vue';
|
||||||
import RoleNameDropdown from './role_name_dropdown.vue';
|
|
||||||
import SecurityGroupDropdown from './security_group_dropdown.vue';
|
import SecurityGroupDropdown from './security_group_dropdown.vue';
|
||||||
|
|
||||||
|
const { mapState: mapRolesState, mapActions: mapRolesActions } = createNamespacedHelpers('roles');
|
||||||
const { mapState: mapRegionsState, mapActions: mapRegionsActions } = createNamespacedHelpers(
|
const { mapState: mapRegionsState, mapActions: mapRegionsActions } = createNamespacedHelpers(
|
||||||
'regions',
|
'regions',
|
||||||
);
|
);
|
||||||
|
const { mapState: mapKeyPairsState, mapActions: mapKeyPairsActions } = createNamespacedHelpers(
|
||||||
|
'keyPairs',
|
||||||
|
);
|
||||||
const { mapState: mapVpcsState, mapActions: mapVpcActions } = createNamespacedHelpers('vpcs');
|
const { mapState: mapVpcsState, mapActions: mapVpcActions } = createNamespacedHelpers('vpcs');
|
||||||
const { mapState: mapSubnetsState, mapActions: mapSubnetActions } = createNamespacedHelpers(
|
const { mapState: mapSubnetsState, mapActions: mapSubnetActions } = createNamespacedHelpers(
|
||||||
'subnets',
|
'subnets',
|
||||||
|
@ -18,16 +21,31 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
ClusterFormDropdown,
|
ClusterFormDropdown,
|
||||||
RegionDropdown,
|
RegionDropdown,
|
||||||
RoleNameDropdown,
|
|
||||||
SecurityGroupDropdown,
|
SecurityGroupDropdown,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['selectedRegion', 'selectedVpc', 'selectedSubnet']),
|
...mapState([
|
||||||
|
'selectedRegion',
|
||||||
|
'selectedKeyPair',
|
||||||
|
'selectedVpc',
|
||||||
|
'selectedSubnet',
|
||||||
|
'selectedRole',
|
||||||
|
]),
|
||||||
|
...mapRolesState({
|
||||||
|
roles: 'items',
|
||||||
|
isLoadingRoles: 'isLoadingItems',
|
||||||
|
loadingRolesError: 'loadingItemsError',
|
||||||
|
}),
|
||||||
...mapRegionsState({
|
...mapRegionsState({
|
||||||
regions: 'items',
|
regions: 'items',
|
||||||
isLoadingRegions: 'isLoadingItems',
|
isLoadingRegions: 'isLoadingItems',
|
||||||
loadingRegionsError: 'loadingItemsError',
|
loadingRegionsError: 'loadingItemsError',
|
||||||
}),
|
}),
|
||||||
|
...mapKeyPairsState({
|
||||||
|
keyPairs: 'items',
|
||||||
|
isLoadingKeyPairs: 'isLoadingItems',
|
||||||
|
loadingKeyPairsError: 'loadingItemsError',
|
||||||
|
}),
|
||||||
...mapVpcsState({
|
...mapVpcsState({
|
||||||
vpcs: 'items',
|
vpcs: 'items',
|
||||||
isLoadingVpcs: 'isLoadingItems',
|
isLoadingVpcs: 'isLoadingItems',
|
||||||
|
@ -41,9 +59,38 @@ export default {
|
||||||
vpcDropdownDisabled() {
|
vpcDropdownDisabled() {
|
||||||
return !this.selectedRegion;
|
return !this.selectedRegion;
|
||||||
},
|
},
|
||||||
|
keyPairDropdownDisabled() {
|
||||||
|
return !this.selectedRegion;
|
||||||
|
},
|
||||||
subnetDropdownDisabled() {
|
subnetDropdownDisabled() {
|
||||||
return !this.selectedVpc;
|
return !this.selectedVpc;
|
||||||
},
|
},
|
||||||
|
roleDropdownHelpText() {
|
||||||
|
return sprintf(
|
||||||
|
s__(
|
||||||
|
'ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, first create one on %{startLink}Amazon Web Services%{endLink}.',
|
||||||
|
),
|
||||||
|
{
|
||||||
|
startLink:
|
||||||
|
'<a href="https://console.aws.amazon.com/iam/home?#roles" target="_blank" rel="noopener noreferrer">',
|
||||||
|
endLink: '</a>',
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
keyPairDropdownHelpText() {
|
||||||
|
return sprintf(
|
||||||
|
s__(
|
||||||
|
'ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services%{endLink}.',
|
||||||
|
),
|
||||||
|
{
|
||||||
|
startLink:
|
||||||
|
'<a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#having-ec2-create-your-key-pair" target="_blank" rel="noopener noreferrer">',
|
||||||
|
endLink: '</a>',
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
},
|
||||||
vpcDropdownHelpText() {
|
vpcDropdownHelpText() {
|
||||||
return sprintf(
|
return sprintf(
|
||||||
s__(
|
s__(
|
||||||
|
@ -73,15 +120,19 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchRegions();
|
this.fetchRegions();
|
||||||
|
this.fetchRoles();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['setRegion', 'setVpc', 'setSubnet']),
|
...mapActions(['setRegion', 'setVpc', 'setSubnet', 'setRole', 'setKeyPair']),
|
||||||
...mapRegionsActions({ fetchRegions: 'fetchItems' }),
|
...mapRegionsActions({ fetchRegions: 'fetchItems' }),
|
||||||
...mapVpcActions({ fetchVpcs: 'fetchItems' }),
|
...mapVpcActions({ fetchVpcs: 'fetchItems' }),
|
||||||
...mapSubnetActions({ fetchSubnets: 'fetchItems' }),
|
...mapSubnetActions({ fetchSubnets: 'fetchItems' }),
|
||||||
setRegionAndFetchVpcs(region) {
|
...mapRolesActions({ fetchRoles: 'fetchItems' }),
|
||||||
|
...mapKeyPairsActions({ fetchKeyPairs: 'fetchItems' }),
|
||||||
|
setRegionAndFetchVpcsAndKeyPairs(region) {
|
||||||
this.setRegion({ region });
|
this.setRegion({ region });
|
||||||
this.fetchVpcs({ region });
|
this.fetchVpcs({ region });
|
||||||
|
this.fetchKeyPairs({ region });
|
||||||
},
|
},
|
||||||
setVpcAndFetchSubnets(vpc) {
|
setVpcAndFetchSubnets(vpc) {
|
||||||
this.setVpc({ vpc });
|
this.setVpc({ vpc });
|
||||||
|
@ -93,27 +144,57 @@ export default {
|
||||||
<template>
|
<template>
|
||||||
<form name="eks-cluster-configuration-form">
|
<form name="eks-cluster-configuration-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="label-bold" name="role" for="eks-role">{{
|
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Role name') }}</label>
|
||||||
s__('ClusterIntegration|Role name')
|
<cluster-form-dropdown
|
||||||
}}</label>
|
field-id="eks-role"
|
||||||
<role-name-dropdown />
|
field-name="eks-role"
|
||||||
|
:input="selectedRole"
|
||||||
|
:items="roles"
|
||||||
|
:loading="isLoadingRoles"
|
||||||
|
:loading-text="s__('ClusterIntegration|Loading IAM Roles')"
|
||||||
|
:placeholder="s__('ClusterIntergation|Select role name')"
|
||||||
|
:search-field-placeholder="s__('ClusterIntegration|Search IAM Roles')"
|
||||||
|
:empty-text="s__('ClusterIntegration|No IAM Roles found')"
|
||||||
|
:has-errors="Boolean(loadingRolesError)"
|
||||||
|
:error-message="s__('ClusterIntegration|Could not load IAM roles')"
|
||||||
|
@input="setRole({ role: $event })"
|
||||||
|
/>
|
||||||
|
<p class="form-text text-muted" v-html="roleDropdownHelpText"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="label-bold" name="role" for="eks-role">{{
|
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Region') }}</label>
|
||||||
s__('ClusterIntegration|Region')
|
|
||||||
}}</label>
|
|
||||||
<region-dropdown
|
<region-dropdown
|
||||||
:value="selectedRegion"
|
:value="selectedRegion"
|
||||||
:regions="regions"
|
:regions="regions"
|
||||||
:error="loadingRegionsError"
|
:error="loadingRegionsError"
|
||||||
:loading="isLoadingRegions"
|
:loading="isLoadingRegions"
|
||||||
@input="setRegionAndFetchVpcs($event)"
|
@input="setRegionAndFetchVpcsAndKeyPairs($event)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="label-bold" name="eks-vpc" for="eks-vpc">{{
|
<label class="label-bold" for="eks-key-pair">{{
|
||||||
s__('ClusterIntegration|VPC')
|
s__('ClusterIntegration|Key pair name')
|
||||||
}}</label>
|
}}</label>
|
||||||
|
<cluster-form-dropdown
|
||||||
|
field-id="eks-key-pair"
|
||||||
|
field-name="eks-key-pair"
|
||||||
|
:input="selectedKeyPair"
|
||||||
|
:items="keyPairs"
|
||||||
|
:disabled="keyPairDropdownDisabled"
|
||||||
|
:disabled-text="s__('ClusterIntegration|Select a region to choose a Key Pair')"
|
||||||
|
:loading="isLoadingKeyPairs"
|
||||||
|
:loading-text="s__('ClusterIntegration|Loading Key Pairs')"
|
||||||
|
:placeholder="s__('ClusterIntergation|Select key pair')"
|
||||||
|
:search-field-placeholder="s__('ClusterIntegration|Search Key Pairs')"
|
||||||
|
:empty-text="s__('ClusterIntegration|No Key Pairs found')"
|
||||||
|
:has-errors="Boolean(loadingKeyPairsError)"
|
||||||
|
:error-message="s__('ClusterIntegration|Could not load Key Pairs')"
|
||||||
|
@input="setKeyPair({ keyPair: $event })"
|
||||||
|
/>
|
||||||
|
<p class="form-text text-muted" v-html="keyPairDropdownHelpText"></p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="label-bold" for="eks-vpc">{{ s__('ClusterIntegration|VPC') }}</label>
|
||||||
<cluster-form-dropdown
|
<cluster-form-dropdown
|
||||||
field-id="eks-vpc"
|
field-id="eks-vpc"
|
||||||
field-name="eks-vpc"
|
field-name="eks-vpc"
|
||||||
|
@ -126,16 +207,14 @@ export default {
|
||||||
:placeholder="s__('ClusterIntergation|Select a VPC')"
|
:placeholder="s__('ClusterIntergation|Select a VPC')"
|
||||||
:search-field-placeholder="s__('ClusterIntegration|Search VPCs')"
|
:search-field-placeholder="s__('ClusterIntegration|Search VPCs')"
|
||||||
:empty-text="s__('ClusterIntegration|No VPCs found')"
|
:empty-text="s__('ClusterIntegration|No VPCs found')"
|
||||||
:has-errors="loadingVpcsError"
|
:has-errors="Boolean(loadingVpcsError)"
|
||||||
:error-message="s__('ClusterIntegration|Could not load VPCs for the selected region')"
|
:error-message="s__('ClusterIntegration|Could not load VPCs for the selected region')"
|
||||||
@input="setVpcAndFetchSubnets($event)"
|
@input="setVpcAndFetchSubnets($event)"
|
||||||
/>
|
/>
|
||||||
<p class="form-text text-muted" v-html="vpcDropdownHelpText"></p>
|
<p class="form-text text-muted" v-html="vpcDropdownHelpText"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="label-bold" name="eks-subnet" for="eks-subnet">{{
|
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Subnet') }}</label>
|
||||||
s__('ClusterIntegration|Subnet')
|
|
||||||
}}</label>
|
|
||||||
<cluster-form-dropdown
|
<cluster-form-dropdown
|
||||||
field-id="eks-subnet"
|
field-id="eks-subnet"
|
||||||
field-name="eks-subnet"
|
field-name="eks-subnet"
|
||||||
|
@ -148,7 +227,7 @@ export default {
|
||||||
:placeholder="s__('ClusterIntergation|Select a subnet')"
|
:placeholder="s__('ClusterIntergation|Select a subnet')"
|
||||||
:search-field-placeholder="s__('ClusterIntegration|Search subnets')"
|
:search-field-placeholder="s__('ClusterIntegration|Search subnets')"
|
||||||
:empty-text="s__('ClusterIntegration|No subnet found')"
|
:empty-text="s__('ClusterIntegration|No subnet found')"
|
||||||
:has-errors="loadingSubnetsError"
|
:has-errors="Boolean(loadingSubnetsError)"
|
||||||
:error-message="s__('ClusterIntegration|Could not load subnets for the selected VPC')"
|
:error-message="s__('ClusterIntegration|Could not load subnets for the selected VPC')"
|
||||||
@input="setSubnet({ subnet: $event })"
|
@input="setSubnet({ subnet: $event })"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
<script>
|
|
||||||
import { sprintf, s__ } from '~/locale';
|
|
||||||
|
|
||||||
import ClusterFormDropdown from './cluster_form_dropdown.vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
ClusterFormDropdown,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
roles: {
|
|
||||||
type: Array,
|
|
||||||
required: false,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
loading: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
helpText() {
|
|
||||||
return sprintf(
|
|
||||||
s__(
|
|
||||||
'ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, first create one on %{startLink}Amazon Web Services%{endLink}.',
|
|
||||||
),
|
|
||||||
{
|
|
||||||
startLink:
|
|
||||||
'<a href="https://console.aws.amazon.com/iam/home?#roles" target="_blank" rel="noopener noreferrer">',
|
|
||||||
endLink: '</a>',
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<cluster-form-dropdown
|
|
||||||
field-id="eks-role-name"
|
|
||||||
field-name="eks-role-name"
|
|
||||||
:items="roles"
|
|
||||||
:loading="loading"
|
|
||||||
:loading-text="s__('ClusterIntegration|Loading IAM Roles')"
|
|
||||||
:placeholder="s__('ClusterIntergation|Select role name')"
|
|
||||||
:search-field-placeholder="s__('ClusterIntegration|Search IAM Roles')"
|
|
||||||
:empty-text="s__('ClusterIntegration|No IAM Roles found')"
|
|
||||||
/>
|
|
||||||
<p class="form-text text-muted" v-html="helpText"></p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
|
@ -1,4 +1,39 @@
|
||||||
import EC2 from 'aws-sdk/clients/ec2';
|
import EC2 from 'aws-sdk/clients/ec2';
|
||||||
|
import IAM from 'aws-sdk/clients/iam';
|
||||||
|
|
||||||
|
export const fetchRoles = () =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const iam = new IAM();
|
||||||
|
|
||||||
|
iam
|
||||||
|
.listRoles()
|
||||||
|
.on('success', ({ data: { Roles: roles } }) => {
|
||||||
|
const transformedRoles = roles.map(({ RoleName: name }) => ({ name }));
|
||||||
|
|
||||||
|
resolve(transformedRoles);
|
||||||
|
})
|
||||||
|
.on('error', error => {
|
||||||
|
reject(error);
|
||||||
|
})
|
||||||
|
.send();
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchKeyPairs = () =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const ec2 = new EC2();
|
||||||
|
|
||||||
|
ec2
|
||||||
|
.describeKeyPairs()
|
||||||
|
.on('success', ({ data: { KeyPairs: keyPairs } }) => {
|
||||||
|
const transformedKeyPairs = keyPairs.map(({ RegionName: name }) => ({ name }));
|
||||||
|
|
||||||
|
resolve(transformedKeyPairs);
|
||||||
|
})
|
||||||
|
.on('error', error => {
|
||||||
|
reject(error);
|
||||||
|
})
|
||||||
|
.send();
|
||||||
|
});
|
||||||
|
|
||||||
export const fetchRegions = () =>
|
export const fetchRegions = () =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
|
|
|
@ -4,6 +4,10 @@ export const setRegion = ({ commit }, payload) => {
|
||||||
commit(types.SET_REGION, payload);
|
commit(types.SET_REGION, payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setKeyPair = ({ commit }, payload) => {
|
||||||
|
commit(types.SET_KEY_PAIR, payload);
|
||||||
|
};
|
||||||
|
|
||||||
export const setVpc = ({ commit }, payload) => {
|
export const setVpc = ({ commit }, payload) => {
|
||||||
commit(types.SET_VPC, payload);
|
commit(types.SET_VPC, payload);
|
||||||
};
|
};
|
||||||
|
@ -12,4 +16,8 @@ export const setSubnet = ({ commit }, payload) => {
|
||||||
commit(types.SET_SUBNET, payload);
|
commit(types.SET_SUBNET, payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setRole = ({ commit }, payload) => {
|
||||||
|
commit(types.SET_ROLE, payload);
|
||||||
|
};
|
||||||
|
|
||||||
export default () => {};
|
export default () => {};
|
||||||
|
|
|
@ -15,10 +15,18 @@ const createStore = () =>
|
||||||
mutations,
|
mutations,
|
||||||
state: state(),
|
state: state(),
|
||||||
modules: {
|
modules: {
|
||||||
|
roles: {
|
||||||
|
namespaced: true,
|
||||||
|
...clusterDropdownStore(awsServices.fetchRoles),
|
||||||
|
},
|
||||||
regions: {
|
regions: {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
...clusterDropdownStore(awsServices.fetchRegions),
|
...clusterDropdownStore(awsServices.fetchRegions),
|
||||||
},
|
},
|
||||||
|
keyPairs: {
|
||||||
|
namespaced: true,
|
||||||
|
...clusterDropdownStore(awsServices.fetchKeyPairs),
|
||||||
|
},
|
||||||
vpcs: {
|
vpcs: {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
...clusterDropdownStore(awsServices.fetchVpcs),
|
...clusterDropdownStore(awsServices.fetchVpcs),
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
export const SET_REGION = 'SET_REGION';
|
export const SET_REGION = 'SET_REGION';
|
||||||
export const SET_VPC = 'SET_VPC';
|
export const SET_VPC = 'SET_VPC';
|
||||||
|
export const SET_KEY_PAIR = 'SET_KEY_PAIR';
|
||||||
export const SET_SUBNET = 'SET_SUBNET';
|
export const SET_SUBNET = 'SET_SUBNET';
|
||||||
|
export const SET_ROLE = 'SET_ROLE';
|
||||||
|
|
|
@ -4,10 +4,16 @@ export default {
|
||||||
[types.SET_REGION](state, { region }) {
|
[types.SET_REGION](state, { region }) {
|
||||||
state.selectedRegion = region;
|
state.selectedRegion = region;
|
||||||
},
|
},
|
||||||
|
[types.SET_KEY_PAIR](state, { keyPair }) {
|
||||||
|
state.selectedKeyPair = keyPair;
|
||||||
|
},
|
||||||
[types.SET_VPC](state, { vpc }) {
|
[types.SET_VPC](state, { vpc }) {
|
||||||
state.selectedVpc = vpc;
|
state.selectedVpc = vpc;
|
||||||
},
|
},
|
||||||
[types.SET_SUBNET](state, { subnet }) {
|
[types.SET_SUBNET](state, { subnet }) {
|
||||||
state.selectedSubnet = subnet;
|
state.selectedSubnet = subnet;
|
||||||
},
|
},
|
||||||
|
[types.SET_ROLE](state, { role }) {
|
||||||
|
state.selectedRole = role;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ export default () => ({
|
||||||
|
|
||||||
selectedRegion: '',
|
selectedRegion: '',
|
||||||
selectedRole: '',
|
selectedRole: '',
|
||||||
|
selectedKeyPair: '',
|
||||||
selectedVpc: '',
|
selectedVpc: '',
|
||||||
selectedSubnet: '',
|
selectedSubnet: '',
|
||||||
selectedSecurityGroup: '',
|
selectedSecurityGroup: '',
|
||||||
|
|
|
@ -19,18 +19,13 @@ export default {
|
||||||
updated() {
|
updated() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.handleScrollDown();
|
this.handleScrollDown();
|
||||||
this.handleCollapsibleRows();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.handleScrollDown();
|
this.handleScrollDown();
|
||||||
this.handleCollapsibleRows();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
destroyed() {
|
|
||||||
this.removeEventListener();
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['scrollBottom']),
|
...mapActions(['scrollBottom']),
|
||||||
/**
|
/**
|
||||||
|
@ -47,53 +42,6 @@ export default {
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeEventListener() {
|
|
||||||
this.$el.querySelectorAll('.js-section-start').forEach(el => {
|
|
||||||
const titleSection = el.nextSibling;
|
|
||||||
titleSection.removeEventListener(
|
|
||||||
'click',
|
|
||||||
this.handleHeaderClick.bind(this, el, el.dataset.section),
|
|
||||||
);
|
|
||||||
el.removeEventListener('click', this.handleSectionClick);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* The collapsible rows are sent in HTML from the backend
|
|
||||||
* We need tos add a onclick handler for the divs that match `.js-section-start`
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
handleCollapsibleRows() {
|
|
||||||
this.$el.querySelectorAll('.js-section-start').forEach(el => {
|
|
||||||
const titleSection = el.nextSibling;
|
|
||||||
titleSection.addEventListener(
|
|
||||||
'click',
|
|
||||||
this.handleHeaderClick.bind(this, el, el.dataset.section),
|
|
||||||
);
|
|
||||||
el.addEventListener('click', this.handleSectionClick);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
handleHeaderClick(arrowElement, section) {
|
|
||||||
this.updateToggleSection(arrowElement, section);
|
|
||||||
},
|
|
||||||
|
|
||||||
updateToggleSection(arrow, section) {
|
|
||||||
// toggle the arrow class
|
|
||||||
arrow.classList.toggle('fa-caret-right');
|
|
||||||
arrow.classList.toggle('fa-caret-down');
|
|
||||||
|
|
||||||
// hide the sections
|
|
||||||
const sibilings = this.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`);
|
|
||||||
sibilings.forEach(row => row.classList.toggle('hidden'));
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* On click, we toggle the hidden class of
|
|
||||||
* all the rows that match the `data-section` selector
|
|
||||||
*/
|
|
||||||
handleSectionClick(evt) {
|
|
||||||
const clickedArrow = evt.currentTarget;
|
|
||||||
this.updateToggleSection(clickedArrow, clickedArrow.dataset.section);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -124,26 +124,6 @@
|
||||||
float: left;
|
float: left;
|
||||||
padding-left: $gl-padding-8;
|
padding-left: $gl-padding-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-start {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-start,
|
|
||||||
.section-header {
|
|
||||||
&:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
background-color: rgba($white-light, 0.2);
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
position: absolute;
|
|
||||||
height: $job-log-highlight-height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.build-header {
|
.build-header {
|
||||||
|
|
|
@ -59,18 +59,20 @@ class SnippetsFinder < UnionFinder
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
base =
|
base = init_collection
|
||||||
if project
|
|
||||||
snippets_for_a_single_project
|
|
||||||
else
|
|
||||||
snippets_for_multiple_projects
|
|
||||||
end
|
|
||||||
|
|
||||||
base.with_optional_visibility(visibility_from_scope).fresh
|
base.with_optional_visibility(visibility_from_scope).fresh
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def init_collection
|
||||||
|
if project
|
||||||
|
snippets_for_a_single_project
|
||||||
|
else
|
||||||
|
snippets_for_multiple_projects
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Produces a query that retrieves snippets from multiple projects.
|
# Produces a query that retrieves snippets from multiple projects.
|
||||||
#
|
#
|
||||||
# The resulting query will, depending on the user's permissions, include the
|
# The resulting query will, depending on the user's permissions, include the
|
||||||
|
@ -115,7 +117,7 @@ class SnippetsFinder < UnionFinder
|
||||||
# This method requires that `current_user` returns a `User` instead of `nil`,
|
# This method requires that `current_user` returns a `User` instead of `nil`,
|
||||||
# and is optimised for this specific scenario.
|
# and is optimised for this specific scenario.
|
||||||
def snippets_of_authorized_projects
|
def snippets_of_authorized_projects
|
||||||
base = author ? snippets_for_author : Snippet.all
|
base = author ? author.snippets : Snippet.all
|
||||||
|
|
||||||
base
|
base
|
||||||
.only_include_projects_with_snippets_enabled(include_private: true)
|
.only_include_projects_with_snippets_enabled(include_private: true)
|
||||||
|
@ -157,3 +159,5 @@ class SnippetsFinder < UnionFinder
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
SnippetsFinder.prepend_if_ee('EE::SnippetsFinder')
|
||||||
|
|
|
@ -21,7 +21,7 @@ module NotificationBranchSelection
|
||||||
end
|
end
|
||||||
|
|
||||||
is_default_branch = ref == project.default_branch
|
is_default_branch = ref == project.default_branch
|
||||||
is_protected_branch = project.protected_branches.exists?(name: ref)
|
is_protected_branch = ProtectedBranch.protected?(project, ref)
|
||||||
|
|
||||||
case branches_to_be_notified
|
case branches_to_be_notified
|
||||||
when "all"
|
when "all"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Specify sort order explicitly for Group and Project audit events
|
||||||
|
merge_request: 17739
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Removes Collapsible Sections from Job Log
|
||||||
|
merge_request:
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Fix protected branch detection used by notification service
|
||||||
|
merge_request: 18221
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Narrow snippet search scope in GitLab.com
|
||||||
|
merge_request: 17625
|
||||||
|
author:
|
||||||
|
type: performance
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Upgrade to Gitaly v1.67.0
|
||||||
|
merge_request: 18326
|
||||||
|
author:
|
||||||
|
type: changed
|
|
@ -115,16 +115,6 @@ curl --request POST --header "Gitlab-Shared-Secret: <Base64 encoded token>" --da
|
||||||
|
|
||||||
- GitLab-shell
|
- GitLab-shell
|
||||||
|
|
||||||
## Get merge requests for a ref [NOT USED]
|
|
||||||
|
|
||||||
```
|
|
||||||
GET /internal/merge_request_urls
|
|
||||||
```
|
|
||||||
|
|
||||||
**Deprecated**: This used to be called from GitLab shell to fetch the
|
|
||||||
merge requests for a change to output them after a push, but this is
|
|
||||||
now handled in the `/internal/post_receive` call.
|
|
||||||
|
|
||||||
## Authorized Keys Check
|
## Authorized Keys Check
|
||||||
|
|
||||||
This endpoint is called by the GitLab-shell authorized keys
|
This endpoint is called by the GitLab-shell authorized keys
|
||||||
|
|
|
@ -112,10 +112,6 @@ module API
|
||||||
end
|
end
|
||||||
# rubocop: enable CodeReuse/ActiveRecord
|
# rubocop: enable CodeReuse/ActiveRecord
|
||||||
|
|
||||||
get "/merge_request_urls" do
|
|
||||||
merge_request_urls
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get a ssh key using the fingerprint
|
# Get a ssh key using the fingerprint
|
||||||
#
|
#
|
||||||
|
|
|
@ -45,7 +45,7 @@ module Gitlab
|
||||||
|
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
def snippets
|
def snippets
|
||||||
SnippetsFinder.new(current_user)
|
SnippetsFinder.new(current_user, finder_params)
|
||||||
.execute
|
.execute
|
||||||
.includes(:author)
|
.includes(:author)
|
||||||
.reorder(updated_at: :desc)
|
.reorder(updated_at: :desc)
|
||||||
|
@ -67,5 +67,11 @@ module Gitlab
|
||||||
def paginated_objects(relation, page)
|
def paginated_objects(relation, page)
|
||||||
relation.page(page).per(per_page)
|
relation.page(page).per(per_page)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def finder_params
|
||||||
|
{}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Gitlab::SnippetSearchResults.prepend_if_ee('::EE::Gitlab::SnippetSearchResults')
|
||||||
|
|
|
@ -3417,6 +3417,12 @@ msgstr ""
|
||||||
msgid "ClusterIntegration|Copy Service Token"
|
msgid "ClusterIntegration|Copy Service Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ClusterIntegration|Could not load IAM roles"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ClusterIntegration|Could not load Key Pairs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ClusterIntegration|Could not load VPCs for the selected region"
|
msgid "ClusterIntegration|Could not load VPCs for the selected region"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3549,6 +3555,9 @@ msgstr ""
|
||||||
msgid "ClusterIntegration|JupyterHub, a multi-user Hub, spawns, manages, and proxies multiple instances of the single-user Jupyter notebook server. JupyterHub can be used to serve notebooks to a class of students, a corporate data science group, or a scientific research group."
|
msgid "ClusterIntegration|JupyterHub, a multi-user Hub, spawns, manages, and proxies multiple instances of the single-user Jupyter notebook server. JupyterHub can be used to serve notebooks to a class of students, a corporate data science group, or a scientific research group."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ClusterIntegration|Key pair name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ClusterIntegration|Knative"
|
msgid "ClusterIntegration|Knative"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3609,6 +3618,9 @@ msgstr ""
|
||||||
msgid "ClusterIntegration|Loading IAM Roles"
|
msgid "ClusterIntegration|Loading IAM Roles"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ClusterIntegration|Loading Key Pairs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ClusterIntegration|Loading Regions"
|
msgid "ClusterIntegration|Loading Regions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3630,6 +3642,9 @@ msgstr ""
|
||||||
msgid "ClusterIntegration|No IAM Roles found"
|
msgid "ClusterIntegration|No IAM Roles found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ClusterIntegration|No Key Pairs found"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ClusterIntegration|No VPCs found"
|
msgid "ClusterIntegration|No VPCs found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3717,6 +3732,9 @@ msgstr ""
|
||||||
msgid "ClusterIntegration|Search IAM Roles"
|
msgid "ClusterIntegration|Search IAM Roles"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ClusterIntegration|Search Key Pairs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ClusterIntegration|Search VPCs"
|
msgid "ClusterIntegration|Search VPCs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3744,6 +3762,9 @@ msgstr ""
|
||||||
msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services%{endLink}."
|
msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services%{endLink}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ClusterIntegration|Select a region to choose a Key Pair"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ClusterIntegration|Select a region to choose a VPC"
|
msgid "ClusterIntegration|Select a region to choose a VPC"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3762,6 +3783,9 @@ msgstr ""
|
||||||
msgid "ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, first create one on %{startLink}Amazon Web Services%{endLink}."
|
msgid "ClusterIntegration|Select the IAM Role to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role name, first create one on %{startLink}Amazon Web Services%{endLink}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services%{endLink}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ClusterIntegration|Select zone"
|
msgid "ClusterIntegration|Select zone"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3906,6 +3930,9 @@ msgstr ""
|
||||||
msgid "ClusterIntergation|Select a subnet"
|
msgid "ClusterIntergation|Select a subnet"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ClusterIntergation|Select key pair"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ClusterIntergation|Select role name"
|
msgid "ClusterIntergation|Select role name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -14014,9 +14041,15 @@ msgstr ""
|
||||||
msgid "SearchResults|Showing %{count} %{scope} for \"%{term}\""
|
msgid "SearchResults|Showing %{count} %{scope} for \"%{term}\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SearchResults|Showing %{count} %{scope} for \"%{term}\" in your personal and project snippets"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "SearchResults|Showing %{from} - %{to} of %{count} %{scope} for \"%{term}\""
|
msgid "SearchResults|Showing %{from} - %{to} of %{count} %{scope} for \"%{term}\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SearchResults|Showing %{from} - %{to} of %{count} %{scope} for \"%{term}\" in your personal and project snippets"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "SearchResults|We couldn't find any %{scope} matching %{term}"
|
msgid "SearchResults|We couldn't find any %{scope} matching %{term}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -14207,6 +14240,12 @@ msgstr ""
|
||||||
msgid "SecurityDashboard|Project"
|
msgid "SecurityDashboard|Project"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SecurityDashboard|Projects added"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SecurityDashboard|Remove project from dashboard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "SecurityDashboard|Report type"
|
msgid "SecurityDashboard|Report type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -14216,6 +14255,9 @@ msgstr ""
|
||||||
msgid "SecurityDashboard|Security Dashboard"
|
msgid "SecurityDashboard|Security Dashboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SecurityDashboard|Select a project to add by using the project search field above."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "SecurityDashboard|Severity"
|
msgid "SecurityDashboard|Severity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
1
qa/qa.rb
1
qa/qa.rb
|
@ -259,7 +259,6 @@ module QA
|
||||||
module Milestone
|
module Milestone
|
||||||
autoload :New, 'qa/page/project/milestone/new'
|
autoload :New, 'qa/page/project/milestone/new'
|
||||||
autoload :Index, 'qa/page/project/milestone/index'
|
autoload :Index, 'qa/page/project/milestone/index'
|
||||||
autoload :Show, 'qa/page/project/milestone/show'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module Operations
|
module Operations
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module QA
|
|
||||||
module Page
|
|
||||||
module Project
|
|
||||||
module Milestone
|
|
||||||
class Show < Page::Base
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
QA::Page::Project::Milestone::Show.prepend_if_ee('QA::EE::Page::Project::Milestone::Show')
|
|
|
@ -38,66 +38,6 @@ describe 'User browses a job', :js do
|
||||||
expect(page).to have_content('Job has been erased')
|
expect(page).to have_content('Job has been erased')
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_examples 'has collapsible sections' do
|
|
||||||
it 'collapses the section clicked' do
|
|
||||||
wait_for_requests
|
|
||||||
text_to_hide = "Cloning into '/nolith/ci-tests'"
|
|
||||||
text_to_show = 'Waiting for pod'
|
|
||||||
|
|
||||||
expect(page).to have_content(text_to_hide)
|
|
||||||
expect(page).to have_content(text_to_show)
|
|
||||||
|
|
||||||
first('.js-section-start[data-section="get-sources"]').click
|
|
||||||
|
|
||||||
expect(page).not_to have_content(text_to_hide)
|
|
||||||
expect(page).to have_content(text_to_show)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'collapses the section header clicked' do
|
|
||||||
wait_for_requests
|
|
||||||
text_to_hide = "Cloning into '/nolith/ci-tests'"
|
|
||||||
text_to_show = 'Waiting for pod'
|
|
||||||
|
|
||||||
expect(page).to have_content(text_to_hide)
|
|
||||||
expect(page).to have_content(text_to_show)
|
|
||||||
|
|
||||||
first('.js-section-header.js-s-get-sources').click
|
|
||||||
|
|
||||||
expect(page).not_to have_content(text_to_hide)
|
|
||||||
expect(page).to have_content(text_to_show)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when job trace contains sections' do
|
|
||||||
let!(:build) { create(:ci_build, :success, :trace_with_sections, :coverage, pipeline: pipeline) }
|
|
||||||
|
|
||||||
it_behaves_like 'has collapsible sections'
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when job trace contains duplicate sections' do
|
|
||||||
let!(:build) { create(:ci_build, :success, :trace_with_duplicate_sections, :coverage, pipeline: pipeline) }
|
|
||||||
|
|
||||||
it_behaves_like 'has collapsible sections'
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when job trace contains sections' do
|
|
||||||
let!(:build) { create(:ci_build, :success, :trace_with_duplicate_sections, :coverage, pipeline: pipeline) }
|
|
||||||
|
|
||||||
it 'collapses a section' do
|
|
||||||
wait_for_requests
|
|
||||||
text_to_hide = "Cloning into '/nolith/ci-tests'"
|
|
||||||
text_to_show = 'Waiting for pod'
|
|
||||||
|
|
||||||
expect(page).to have_content(text_to_hide)
|
|
||||||
expect(page).to have_content(text_to_show)
|
|
||||||
|
|
||||||
first('.js-section-start[data-section="get-sources"]').click
|
|
||||||
|
|
||||||
expect(page).not_to have_content(text_to_hide)
|
|
||||||
expect(page).to have_content(text_to_show)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a failed job' do
|
context 'with a failed job' do
|
||||||
let!(:build) { create(:ci_build, :failed, :trace_artifact, pipeline: pipeline) }
|
let!(:build) { create(:ci_build, :failed, :trace_artifact, pipeline: pipeline) }
|
||||||
|
|
||||||
|
|
|
@ -150,6 +150,26 @@ describe SnippetsFinder do
|
||||||
|
|
||||||
expect(snippets).to contain_exactly(private_project_snippet, internal_project_snippet, public_project_snippet)
|
expect(snippets).to contain_exactly(private_project_snippet, internal_project_snippet, public_project_snippet)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'filter by author' do
|
||||||
|
let!(:other_user) { create(:user) }
|
||||||
|
let!(:other_private_project_snippet) { create(:project_snippet, :private, project: project, author: other_user) }
|
||||||
|
let!(:other_internal_project_snippet) { create(:project_snippet, :internal, project: project, author: other_user) }
|
||||||
|
let!(:other_public_project_snippet) { create(:project_snippet, :public, project: project, author: other_user) }
|
||||||
|
|
||||||
|
it 'returns all snippets for project members' do
|
||||||
|
project.add_developer(user)
|
||||||
|
|
||||||
|
snippets = described_class.new(user, author: other_user).execute
|
||||||
|
|
||||||
|
expect(snippets)
|
||||||
|
.to contain_exactly(
|
||||||
|
other_private_project_snippet,
|
||||||
|
other_internal_project_snippet,
|
||||||
|
other_public_project_snippet
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the user cannot read cross project' do
|
context 'when the user cannot read cross project' do
|
||||||
|
|
|
@ -7,12 +7,22 @@ import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidde
|
||||||
|
|
||||||
describe('ClusterFormDropdown', () => {
|
describe('ClusterFormDropdown', () => {
|
||||||
let vm;
|
let vm;
|
||||||
|
const firstItem = { name: 'item 1', value: 1 };
|
||||||
|
const secondItem = { name: 'item 2', value: 2 };
|
||||||
|
const items = [firstItem, secondItem, { name: 'item 3', value: 3 }];
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vm = shallowMount(ClusterFormDropdown);
|
vm = shallowMount(ClusterFormDropdown);
|
||||||
});
|
});
|
||||||
afterEach(() => vm.destroy());
|
afterEach(() => vm.destroy());
|
||||||
|
|
||||||
|
describe('when initial value is provided', () => {
|
||||||
|
it('sets selectedItem to initial value', () => {
|
||||||
|
vm.setProps({ items, value: secondItem.value });
|
||||||
|
expect(vm.find(DropdownButton).props('toggleText')).toEqual(secondItem.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when no item is selected', () => {
|
describe('when no item is selected', () => {
|
||||||
it('displays placeholder text', () => {
|
it('displays placeholder text', () => {
|
||||||
const placeholder = 'placeholder';
|
const placeholder = 'placeholder';
|
||||||
|
@ -24,18 +34,19 @@ describe('ClusterFormDropdown', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when an item is selected', () => {
|
describe('when an item is selected', () => {
|
||||||
const selectedItem = { name: 'Name', value: 'value' };
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vm.setData({ selectedItem });
|
vm.setProps({ items });
|
||||||
|
vm.findAll('.js-dropdown-item')
|
||||||
|
.at(1)
|
||||||
|
.trigger('click');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays selected item label', () => {
|
it('displays selected item label', () => {
|
||||||
expect(vm.find(DropdownButton).props('toggleText')).toEqual(selectedItem.name);
|
expect(vm.find(DropdownButton).props('toggleText')).toEqual(secondItem.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets selected value to dropdown hidden input', () => {
|
it('sets selected value to dropdown hidden input', () => {
|
||||||
expect(vm.find(DropdownHiddenInput).props('value')).toEqual(selectedItem.value);
|
expect(vm.find(DropdownHiddenInput).props('value')).toEqual(secondItem.value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -124,9 +135,7 @@ describe('ClusterFormDropdown', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('it filters results by search query', () => {
|
it('it filters results by search query', () => {
|
||||||
const secondItem = { name: 'second item' };
|
const searchQuery = secondItem.name;
|
||||||
const items = [{ name: 'first item' }, secondItem];
|
|
||||||
const searchQuery = 'second';
|
|
||||||
|
|
||||||
vm.setProps({ items });
|
vm.setProps({ items });
|
||||||
vm.setData({ searchQuery });
|
vm.setData({ searchQuery });
|
||||||
|
|
|
@ -14,12 +14,16 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
let store;
|
let store;
|
||||||
let actions;
|
let actions;
|
||||||
let state;
|
let state;
|
||||||
|
let rolesState;
|
||||||
let regionsState;
|
let regionsState;
|
||||||
let vpcsState;
|
let vpcsState;
|
||||||
let subnetsState;
|
let subnetsState;
|
||||||
|
let keyPairsState;
|
||||||
let vpcsActions;
|
let vpcsActions;
|
||||||
|
let rolesActions;
|
||||||
let regionsActions;
|
let regionsActions;
|
||||||
let subnetsActions;
|
let subnetsActions;
|
||||||
|
let keyPairsActions;
|
||||||
let vm;
|
let vm;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -28,16 +32,27 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
setRegion: jest.fn(),
|
setRegion: jest.fn(),
|
||||||
setVpc: jest.fn(),
|
setVpc: jest.fn(),
|
||||||
setSubnet: jest.fn(),
|
setSubnet: jest.fn(),
|
||||||
|
setRole: jest.fn(),
|
||||||
|
setKeyPair: jest.fn(),
|
||||||
};
|
};
|
||||||
regionsActions = {
|
regionsActions = {
|
||||||
fetchItems: jest.fn(),
|
fetchItems: jest.fn(),
|
||||||
};
|
};
|
||||||
|
keyPairsActions = {
|
||||||
|
fetchItems: jest.fn(),
|
||||||
|
};
|
||||||
vpcsActions = {
|
vpcsActions = {
|
||||||
fetchItems: jest.fn(),
|
fetchItems: jest.fn(),
|
||||||
};
|
};
|
||||||
subnetsActions = {
|
subnetsActions = {
|
||||||
fetchItems: jest.fn(),
|
fetchItems: jest.fn(),
|
||||||
};
|
};
|
||||||
|
rolesActions = {
|
||||||
|
fetchItems: jest.fn(),
|
||||||
|
};
|
||||||
|
rolesState = {
|
||||||
|
...clusterDropdownStoreState(),
|
||||||
|
};
|
||||||
regionsState = {
|
regionsState = {
|
||||||
...clusterDropdownStoreState(),
|
...clusterDropdownStoreState(),
|
||||||
};
|
};
|
||||||
|
@ -47,6 +62,9 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
subnetsState = {
|
subnetsState = {
|
||||||
...clusterDropdownStoreState(),
|
...clusterDropdownStoreState(),
|
||||||
};
|
};
|
||||||
|
keyPairsState = {
|
||||||
|
...clusterDropdownStoreState(),
|
||||||
|
};
|
||||||
store = new Vuex.Store({
|
store = new Vuex.Store({
|
||||||
state,
|
state,
|
||||||
actions,
|
actions,
|
||||||
|
@ -66,6 +84,16 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
state: subnetsState,
|
state: subnetsState,
|
||||||
actions: subnetsActions,
|
actions: subnetsActions,
|
||||||
},
|
},
|
||||||
|
roles: {
|
||||||
|
namespaced: true,
|
||||||
|
state: rolesState,
|
||||||
|
actions: rolesActions,
|
||||||
|
},
|
||||||
|
keyPairs: {
|
||||||
|
namespaced: true,
|
||||||
|
state: keyPairsState,
|
||||||
|
actions: keyPairsActions,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -82,13 +110,37 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const findRegionDropdown = () => vm.find(RegionDropdown);
|
const findRegionDropdown = () => vm.find(RegionDropdown);
|
||||||
|
const findKeyPairDropdown = () => vm.find('[field-id="eks-key-pair"]');
|
||||||
const findVpcDropdown = () => vm.find('[field-id="eks-vpc"]');
|
const findVpcDropdown = () => vm.find('[field-id="eks-vpc"]');
|
||||||
const findSubnetDropdown = () => vm.find('[field-id="eks-subnet"]');
|
const findSubnetDropdown = () => vm.find('[field-id="eks-subnet"]');
|
||||||
|
const findRoleDropdown = () => vm.find('[field-id="eks-role"]');
|
||||||
|
|
||||||
describe('when mounted', () => {
|
describe('when mounted', () => {
|
||||||
it('fetches available regions', () => {
|
it('fetches available regions', () => {
|
||||||
expect(regionsActions.fetchItems).toHaveBeenCalled();
|
expect(regionsActions.fetchItems).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fetches available roles', () => {
|
||||||
|
expect(rolesActions.fetchItems).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets isLoadingRoles to RoleDropdown loading property', () => {
|
||||||
|
rolesState.isLoadingItems = true;
|
||||||
|
|
||||||
|
return Vue.nextTick().then(() => {
|
||||||
|
expect(findRoleDropdown().props('loading')).toBe(rolesState.isLoadingItems);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets roles to RoleDropdown items property', () => {
|
||||||
|
expect(findRoleDropdown().props('items')).toBe(rolesState.items);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets RoleDropdown hasErrors to true when loading roles failed', () => {
|
||||||
|
rolesState.loadingItemsError = new Error();
|
||||||
|
|
||||||
|
expect(findRoleDropdown().props('hasErrors')).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets isLoadingRegions to RegionDropdown loading property', () => {
|
it('sets isLoadingRegions to RegionDropdown loading property', () => {
|
||||||
|
@ -107,6 +159,36 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
expect(findRegionDropdown().props('error')).toBe(regionsState.loadingItemsError);
|
expect(findRegionDropdown().props('error')).toBe(regionsState.loadingItemsError);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('disables KeyPairDropdown when no region is selected', () => {
|
||||||
|
expect(findKeyPairDropdown().props('disabled')).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('enables KeyPairDropdown when no region is selected', () => {
|
||||||
|
state.selectedRegion = { name: 'west-1 ' };
|
||||||
|
|
||||||
|
return Vue.nextTick().then(() => {
|
||||||
|
expect(findKeyPairDropdown().props('disabled')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets isLoadingKeyPairs to KeyPairDropdown loading property', () => {
|
||||||
|
keyPairsState.isLoadingItems = true;
|
||||||
|
|
||||||
|
return Vue.nextTick().then(() => {
|
||||||
|
expect(findKeyPairDropdown().props('loading')).toBe(keyPairsState.isLoadingItems);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets keyPairs to KeyPairDropdown items property', () => {
|
||||||
|
expect(findKeyPairDropdown().props('items')).toBe(keyPairsState.items);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets KeyPairDropdown hasErrors to true when loading key pairs fails', () => {
|
||||||
|
keyPairsState.loadingItemsError = new Error();
|
||||||
|
|
||||||
|
expect(findKeyPairDropdown().props('hasErrors')).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
it('disables VpcDropdown when no region is selected', () => {
|
it('disables VpcDropdown when no region is selected', () => {
|
||||||
expect(findVpcDropdown().props('disabled')).toBe(true);
|
expect(findVpcDropdown().props('disabled')).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -131,8 +213,10 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
expect(findVpcDropdown().props('items')).toBe(vpcsState.items);
|
expect(findVpcDropdown().props('items')).toBe(vpcsState.items);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets loadingVpcsError to VpcDropdown hasErrors property', () => {
|
it('sets VpcDropdown hasErrors to true when loading vpcs fails', () => {
|
||||||
expect(findVpcDropdown().props('hasErrors')).toBe(vpcsState.loadingItemsError);
|
vpcsState.loadingItemsError = new Error();
|
||||||
|
|
||||||
|
expect(findVpcDropdown().props('hasErrors')).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('disables SubnetDropdown when no vpc is selected', () => {
|
it('disables SubnetDropdown when no vpc is selected', () => {
|
||||||
|
@ -159,8 +243,10 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
expect(findSubnetDropdown().props('items')).toBe(subnetsState.items);
|
expect(findSubnetDropdown().props('items')).toBe(subnetsState.items);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets loadingSubnetsError to SubnetDropdown hasErrors property', () => {
|
it('sets SubnetDropdown hasErrors to true when loading subnets fails', () => {
|
||||||
expect(findSubnetDropdown().props('hasErrors')).toBe(subnetsState.loadingItemsError);
|
subnetsState.loadingItemsError = new Error();
|
||||||
|
|
||||||
|
expect(findSubnetDropdown().props('hasErrors')).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when region is selected', () => {
|
describe('when region is selected', () => {
|
||||||
|
@ -177,6 +263,14 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
it('fetches available vpcs', () => {
|
it('fetches available vpcs', () => {
|
||||||
expect(vpcsActions.fetchItems).toHaveBeenCalledWith(expect.anything(), { region }, undefined);
|
expect(vpcsActions.fetchItems).toHaveBeenCalledWith(expect.anything(), { region }, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fetches available key pairs', () => {
|
||||||
|
expect(keyPairsActions.fetchItems).toHaveBeenCalledWith(
|
||||||
|
expect.anything(),
|
||||||
|
{ region },
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when vpc is selected', () => {
|
describe('when vpc is selected', () => {
|
||||||
|
@ -206,4 +300,28 @@ describe('EksClusterConfigurationForm', () => {
|
||||||
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet }, undefined);
|
expect(actions.setSubnet).toHaveBeenCalledWith(expect.anything(), { subnet }, undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when role is selected', () => {
|
||||||
|
const role = { name: 'admin' };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
findRoleDropdown().vm.$emit('input', role);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispatches setRole action', () => {
|
||||||
|
expect(actions.setRole).toHaveBeenCalledWith(expect.anything(), { role }, undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when key pair is selected', () => {
|
||||||
|
const keyPair = { name: 'key pair' };
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
findKeyPairDropdown().vm.$emit('input', keyPair);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispatches setKeyPair action', () => {
|
||||||
|
expect(actions.setKeyPair).toHaveBeenCalledWith(expect.anything(), { keyPair }, undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
import { shallowMount } from '@vue/test-utils';
|
|
||||||
|
|
||||||
import ClusterFormDropdown from '~/create_cluster/eks_cluster/components/cluster_form_dropdown.vue';
|
|
||||||
import RoleNameDropdown from '~/create_cluster/eks_cluster/components/role_name_dropdown.vue';
|
|
||||||
|
|
||||||
describe('RoleNameDropdown', () => {
|
|
||||||
let vm;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
vm = shallowMount(RoleNameDropdown);
|
|
||||||
});
|
|
||||||
afterEach(() => vm.destroy());
|
|
||||||
|
|
||||||
it('renders a cluster-form-dropdown', () => {
|
|
||||||
expect(vm.find(ClusterFormDropdown).exists()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets roles to cluster-form-dropdown items property', () => {
|
|
||||||
const roles = [{ name: 'basic' }];
|
|
||||||
|
|
||||||
vm.setProps({ roles });
|
|
||||||
|
|
||||||
expect(vm.find(ClusterFormDropdown).props('items')).toEqual(roles);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets a loading text', () => {
|
|
||||||
expect(vm.find(ClusterFormDropdown).props('loadingText')).toEqual('Loading IAM Roles');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets a placeholder', () => {
|
|
||||||
expect(vm.find(ClusterFormDropdown).props('placeholder')).toEqual('Select role name');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets an empty results text', () => {
|
|
||||||
expect(vm.find(ClusterFormDropdown).props('emptyText')).toEqual('No IAM Roles found');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets a search field placeholder', () => {
|
|
||||||
expect(vm.find(ClusterFormDropdown).props('searchFieldPlaceholder')).toEqual(
|
|
||||||
'Search IAM Roles',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -2,24 +2,36 @@ import testAction from 'helpers/vuex_action_helper';
|
||||||
|
|
||||||
import createState from '~/create_cluster/eks_cluster/store/state';
|
import createState from '~/create_cluster/eks_cluster/store/state';
|
||||||
import * as actions from '~/create_cluster/eks_cluster/store/actions';
|
import * as actions from '~/create_cluster/eks_cluster/store/actions';
|
||||||
import { SET_REGION, SET_VPC, SET_SUBNET } from '~/create_cluster/eks_cluster/store/mutation_types';
|
import {
|
||||||
|
SET_REGION,
|
||||||
|
SET_VPC,
|
||||||
|
SET_KEY_PAIR,
|
||||||
|
SET_SUBNET,
|
||||||
|
SET_ROLE,
|
||||||
|
} from '~/create_cluster/eks_cluster/store/mutation_types';
|
||||||
|
|
||||||
describe('EKS Cluster Store Actions', () => {
|
describe('EKS Cluster Store Actions', () => {
|
||||||
let region;
|
let region;
|
||||||
let vpc;
|
let vpc;
|
||||||
let subnet;
|
let subnet;
|
||||||
|
let role;
|
||||||
|
let keyPair;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
region = { name: 'regions-1' };
|
region = { name: 'regions-1' };
|
||||||
vpc = { name: 'vpc-1' };
|
vpc = { name: 'vpc-1' };
|
||||||
subnet = { name: 'subnet-1' };
|
subnet = { name: 'subnet-1' };
|
||||||
|
role = { name: 'role-1' };
|
||||||
|
keyPair = { name: 'key-pair-1' };
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each`
|
it.each`
|
||||||
action | mutation | payload | payloadDescription
|
action | mutation | payload | payloadDescription
|
||||||
${'setRegion'} | ${SET_REGION} | ${{ region }} | ${'region'}
|
${'setRole'} | ${SET_ROLE} | ${{ role }} | ${'role'}
|
||||||
${'setVpc'} | ${SET_VPC} | ${{ vpc }} | ${'vpc'}
|
${'setRegion'} | ${SET_REGION} | ${{ region }} | ${'region'}
|
||||||
${'setSubnet'} | ${SET_SUBNET} | ${{ subnet }} | ${'subnet'}
|
${'setKeyPair'} | ${SET_KEY_PAIR} | ${{ keyPair }} | ${'key pair'}
|
||||||
|
${'setVpc'} | ${SET_VPC} | ${{ vpc }} | ${'vpc'}
|
||||||
|
${'setSubnet'} | ${SET_SUBNET} | ${{ subnet }} | ${'subnet'}
|
||||||
`(`$action commits $mutation with $payloadDescription payload`, data => {
|
`(`$action commits $mutation with $payloadDescription payload`, data => {
|
||||||
const { action, mutation, payload } = data;
|
const { action, mutation, payload } = data;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import { SET_REGION, SET_VPC, SET_SUBNET } from '~/create_cluster/eks_cluster/store/mutation_types';
|
import {
|
||||||
|
SET_REGION,
|
||||||
|
SET_VPC,
|
||||||
|
SET_KEY_PAIR,
|
||||||
|
SET_SUBNET,
|
||||||
|
SET_ROLE,
|
||||||
|
} from '~/create_cluster/eks_cluster/store/mutation_types';
|
||||||
import createState from '~/create_cluster/eks_cluster/store/state';
|
import createState from '~/create_cluster/eks_cluster/store/state';
|
||||||
import mutations from '~/create_cluster/eks_cluster/store/mutations';
|
import mutations from '~/create_cluster/eks_cluster/store/mutations';
|
||||||
|
|
||||||
|
@ -7,20 +13,26 @@ describe('Create EKS cluster store mutations', () => {
|
||||||
let region;
|
let region;
|
||||||
let vpc;
|
let vpc;
|
||||||
let subnet;
|
let subnet;
|
||||||
|
let role;
|
||||||
|
let keyPair;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
region = { name: 'regions-1' };
|
region = { name: 'regions-1' };
|
||||||
vpc = { name: 'vpc-1' };
|
vpc = { name: 'vpc-1' };
|
||||||
subnet = { name: 'subnet-1' };
|
subnet = { name: 'subnet-1' };
|
||||||
|
role = { name: 'role-1' };
|
||||||
|
keyPair = { name: 'key pair' };
|
||||||
|
|
||||||
state = createState();
|
state = createState();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each`
|
it.each`
|
||||||
mutation | mutatedProperty | payload | expectedValue | expectedValueDescription
|
mutation | mutatedProperty | payload | expectedValue | expectedValueDescription
|
||||||
${SET_REGION} | ${'selectedRegion'} | ${{ region }} | ${region} | ${'selected region payload'}
|
${SET_ROLE} | ${'selectedRole'} | ${{ role }} | ${role} | ${'selected role payload'}
|
||||||
${SET_VPC} | ${'selectedVpc'} | ${{ vpc }} | ${vpc} | ${'selected vpc payload'}
|
${SET_REGION} | ${'selectedRegion'} | ${{ region }} | ${region} | ${'selected region payload'}
|
||||||
${SET_SUBNET} | ${'selectedSubnet'} | ${{ subnet }} | ${subnet} | ${'selected sybnet payload'}
|
${SET_KEY_PAIR} | ${'selectedKeyPair'} | ${{ keyPair }} | ${keyPair} | ${'selected key pair payload'}
|
||||||
|
${SET_VPC} | ${'selectedVpc'} | ${{ vpc }} | ${vpc} | ${'selected vpc payload'}
|
||||||
|
${SET_SUBNET} | ${'selectedSubnet'} | ${{ subnet }} | ${subnet} | ${'selected sybnet payload'}
|
||||||
`(`$mutation sets $mutatedProperty to $expectedValueDescription`, data => {
|
`(`$mutation sets $mutatedProperty to $expectedValueDescription`, data => {
|
||||||
const { mutation, mutatedProperty, payload, expectedValue } = data;
|
const { mutation, mutatedProperty, payload, expectedValue } = data;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import component from '~/jobs/components/job_log.vue';
|
||||||
import createStore from '~/jobs/store';
|
import createStore from '~/jobs/store';
|
||||||
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
||||||
import { resetStore } from '../store/helpers';
|
import { resetStore } from '../store/helpers';
|
||||||
import { logWithCollapsibleSections } from '../mock_data';
|
|
||||||
|
|
||||||
describe('Job Log', () => {
|
describe('Job Log', () => {
|
||||||
const Component = Vue.extend(component);
|
const Component = Vue.extend(component);
|
||||||
|
@ -63,60 +62,4 @@ describe('Job Log', () => {
|
||||||
expect(vm.$el.querySelector('.js-log-animation')).toBeNull();
|
expect(vm.$el.querySelector('.js-log-animation')).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Collapsible sections', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
vm = mountComponentWithStore(Component, {
|
|
||||||
props: {
|
|
||||||
trace: logWithCollapsibleSections.html,
|
|
||||||
isComplete: true,
|
|
||||||
},
|
|
||||||
store,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders open arrow', () => {
|
|
||||||
expect(vm.$el.querySelector('.fa-caret-down')).not.toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('toggles hidden class to the sibilings rows when arrow is clicked', done => {
|
|
||||||
vm.$nextTick()
|
|
||||||
.then(() => {
|
|
||||||
const { section } = vm.$el.querySelector('.js-section-start').dataset;
|
|
||||||
vm.$el.querySelector('.js-section-start').click();
|
|
||||||
|
|
||||||
vm.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`).forEach(el => {
|
|
||||||
expect(el.classList.contains('hidden')).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
vm.$el.querySelector('.js-section-start').click();
|
|
||||||
|
|
||||||
vm.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`).forEach(el => {
|
|
||||||
expect(el.classList.contains('hidden')).toEqual(false);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(done)
|
|
||||||
.catch(done.fail);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('toggles hidden class to the sibilings rows when header section is clicked', done => {
|
|
||||||
vm.$nextTick()
|
|
||||||
.then(() => {
|
|
||||||
const { section } = vm.$el.querySelector('.js-section-header').dataset;
|
|
||||||
vm.$el.querySelector('.js-section-header').click();
|
|
||||||
|
|
||||||
vm.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`).forEach(el => {
|
|
||||||
expect(el.classList.contains('hidden')).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
vm.$el.querySelector('.js-section-header').click();
|
|
||||||
|
|
||||||
vm.$el.querySelectorAll(`.js-s-${section}:not(.js-section-header)`).forEach(el => {
|
|
||||||
expect(el.classList.contains('hidden')).toEqual(false);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(done)
|
|
||||||
.catch(done.fail);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,9 +4,11 @@ import ProjectSelector from '~/vue_shared/components/project_selector/project_se
|
||||||
import ProjectListItem from '~/vue_shared/components/project_selector/project_list_item.vue';
|
import ProjectListItem from '~/vue_shared/components/project_selector/project_list_item.vue';
|
||||||
|
|
||||||
import { GlSearchBoxByType } from '@gitlab/ui';
|
import { GlSearchBoxByType } from '@gitlab/ui';
|
||||||
import { mount } from '@vue/test-utils';
|
import { mount, createLocalVue } from '@vue/test-utils';
|
||||||
import { trimText } from 'spec/helpers/text_helper';
|
import { trimText } from 'spec/helpers/text_helper';
|
||||||
|
|
||||||
|
const localVue = createLocalVue();
|
||||||
|
|
||||||
describe('ProjectSelector component', () => {
|
describe('ProjectSelector component', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
let vm;
|
let vm;
|
||||||
|
@ -22,6 +24,7 @@ describe('ProjectSelector component', () => {
|
||||||
jasmine.clock().install();
|
jasmine.clock().install();
|
||||||
|
|
||||||
wrapper = mount(Vue.extend(ProjectSelector), {
|
wrapper = mount(Vue.extend(ProjectSelector), {
|
||||||
|
localVue,
|
||||||
propsData: {
|
propsData: {
|
||||||
projectSearchResults: searchResults,
|
projectSearchResults: searchResults,
|
||||||
selectedProjects: selected,
|
selectedProjects: selected,
|
||||||
|
|
|
@ -770,47 +770,6 @@ describe API::Internal::Base do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET /internal/merge_request_urls' do
|
|
||||||
let(:repo_name) { "#{project.full_path}" }
|
|
||||||
let(:changes) { URI.escape("#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch") }
|
|
||||||
|
|
||||||
before do
|
|
||||||
project.add_developer(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns link to create new merge request' do
|
|
||||||
get api("/internal/merge_request_urls?project=#{repo_name}&changes=#{changes}"), params: { secret_token: secret_token }
|
|
||||||
|
|
||||||
expect(json_response).to match [{
|
|
||||||
"branch_name" => "new_branch",
|
|
||||||
"url" => "http://#{Gitlab.config.gitlab.host}/#{project.full_path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
|
|
||||||
"new_merge_request" => true
|
|
||||||
}]
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns empty array if printing_merge_request_link_enabled is false' do
|
|
||||||
project.update!(printing_merge_request_link_enabled: false)
|
|
||||||
|
|
||||||
get api("/internal/merge_request_urls?project=#{repo_name}&changes=#{changes}"), params: { secret_token: secret_token }
|
|
||||||
|
|
||||||
expect(json_response).to eq([])
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a gl_repository parameter' do
|
|
||||||
let(:gl_repository) { "project-#{project.id}" }
|
|
||||||
|
|
||||||
it 'returns link to create new merge request' do
|
|
||||||
get api("/internal/merge_request_urls?gl_repository=#{gl_repository}&changes=#{changes}"), params: { secret_token: secret_token }
|
|
||||||
|
|
||||||
expect(json_response).to match [{
|
|
||||||
"branch_name" => "new_branch",
|
|
||||||
"url" => "http://#{Gitlab.config.gitlab.host}/#{project.full_path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
|
|
||||||
"new_merge_request" => true
|
|
||||||
}]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# TODO: Uncomment when the end-point is reenabled
|
# TODO: Uncomment when the end-point is reenabled
|
||||||
# describe 'POST /notify_post_receive' do
|
# describe 'POST /notify_post_receive' do
|
||||||
# let(:valid_params) do
|
# let(:valid_params) do
|
||||||
|
@ -951,6 +910,19 @@ describe API::Internal::Base do
|
||||||
expect(json_response['messages']).to include(build_basic_message(message))
|
expect(json_response['messages']).to include(build_basic_message(message))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns the link to an existing merge request when it exists' do
|
||||||
|
merge_request = create(:merge_request, source_project: project, source_branch: branch_name, target_branch: 'master')
|
||||||
|
|
||||||
|
post api('/internal/post_receive'), params: valid_params
|
||||||
|
|
||||||
|
message = <<~MESSAGE.strip
|
||||||
|
View merge request for feature:
|
||||||
|
#{project_merge_request_url(project, merge_request)}
|
||||||
|
MESSAGE
|
||||||
|
|
||||||
|
expect(json_response['messages']).to include(build_basic_message(message))
|
||||||
|
end
|
||||||
|
|
||||||
it 'returns no merge request messages if printing_merge_request_link_enabled is false' do
|
it 'returns no merge request messages if printing_merge_request_link_enabled is false' do
|
||||||
project.update!(printing_merge_request_link_enabled: false)
|
project.update!(printing_merge_request_link_enabled: false)
|
||||||
|
|
||||||
|
|
|
@ -369,6 +369,48 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'on a protected branch with protected branches defined using wildcards' do
|
||||||
|
before do
|
||||||
|
create(:protected_branch, project: project, name: '*-stable')
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:data) do
|
||||||
|
Gitlab::DataBuilder::Push.build(
|
||||||
|
project: project,
|
||||||
|
user: user,
|
||||||
|
ref: '1-stable'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'pushing tags' do
|
||||||
|
let(:data) do
|
||||||
|
Gitlab::DataBuilder::Push.build(
|
||||||
|
project: project,
|
||||||
|
user: user,
|
||||||
|
ref: "#{Gitlab::Git::TAG_REF_PREFIX}test"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like "triggered #{service_name} service", event_type: "push"
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'notification enabled only for default branch' do
|
||||||
|
it_behaves_like "untriggered #{service_name} service", event_type: "push", branches_to_be_notified: "default"
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'notification enabled only for protected branches' do
|
||||||
|
it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "protected"
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'notification enabled only for default and protected branches' do
|
||||||
|
it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "default_and_protected"
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'notification enabled for all branches' do
|
||||||
|
it_behaves_like "triggered #{service_name} service", event_type: "push", branches_to_be_notified: "all"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'on a neither protected nor default branch' do
|
context 'on a neither protected nor default branch' do
|
||||||
let(:data) do
|
let(:data) do
|
||||||
Gitlab::DataBuilder::Push.build(
|
Gitlab::DataBuilder::Push.build(
|
||||||
|
@ -570,6 +612,36 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'on a protected branch with protected branches defined usin wildcards' do
|
||||||
|
before do
|
||||||
|
create(:protected_branch, project: project, name: '*-stable')
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:pipeline) do
|
||||||
|
create(:ci_pipeline,
|
||||||
|
project: project, status: :failed,
|
||||||
|
sha: project.commit.sha, ref: '1-stable')
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
|
||||||
|
|
||||||
|
context 'notification enabled only for default branch' do
|
||||||
|
it_behaves_like "untriggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default"
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'notification enabled only for protected branches' do
|
||||||
|
it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "protected"
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'notification enabled only for default and protected branches' do
|
||||||
|
it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "default_and_protected"
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'notification enabled for all branches' do
|
||||||
|
it_behaves_like "triggered #{service_name} service", event_type: "pipeline", branches_to_be_notified: "all"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'on a neither protected nor default branch' do
|
context 'on a neither protected nor default branch' do
|
||||||
let(:pipeline) do
|
let(:pipeline) do
|
||||||
create(:ci_pipeline,
|
create(:ci_pipeline,
|
||||||
|
|
Loading…
Reference in New Issue