Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
981fb44c36
commit
2332c32045
34 changed files with 348 additions and 284 deletions
|
@ -1,10 +1,6 @@
|
|||
---
|
||||
Database/MultipleDatabases:
|
||||
Exclude:
|
||||
- ee/lib/gitlab/geo/database_tasks.rb
|
||||
- ee/lib/gitlab/geo/geo_tasks.rb
|
||||
- ee/lib/gitlab/geo/health_check.rb
|
||||
- ee/lib/gitlab/geo/log_cursor/daemon.rb
|
||||
- ee/spec/services/ee/merge_requests/update_service_spec.rb
|
||||
- lib/backup/database.rb
|
||||
- lib/backup/manager.rb
|
||||
|
|
|
@ -34,7 +34,10 @@ export default {
|
|||
};
|
||||
},
|
||||
update(data) {
|
||||
return data.localWorkItem;
|
||||
return data.workItem;
|
||||
},
|
||||
skip() {
|
||||
return !this.workItemId;
|
||||
},
|
||||
error() {
|
||||
this.$emit(
|
||||
|
@ -46,10 +49,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
workItemTitle() {
|
||||
return this.workItem?.widgets?.nodes.find(
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
(widget) => widget.__typename === 'LocalTitleWidget',
|
||||
)?.contentText;
|
||||
return this.workItem?.title;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#import './widget.fragment.graphql'
|
||||
|
||||
mutation createWorkItem($input: LocalCreateWorkItemInput) {
|
||||
localCreateWorkItem(input: $input) @client {
|
||||
mutation createWorkItem($input: WorkItemCreateInput!) {
|
||||
workItemCreate(input: $input) {
|
||||
workItem {
|
||||
id
|
||||
type
|
||||
widgets {
|
||||
title
|
||||
workItemType {
|
||||
id
|
||||
}
|
||||
widgets @client {
|
||||
nodes {
|
||||
...WidgetBase
|
||||
... on LocalTitleWidget {
|
||||
contentText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,24 +20,18 @@ export function createApolloProvider() {
|
|||
defaultClient.cache.writeQuery({
|
||||
query: workItemQuery,
|
||||
variables: {
|
||||
id: '1',
|
||||
id: 'gid://gitlab/WorkItem/1',
|
||||
},
|
||||
data: {
|
||||
localWorkItem: {
|
||||
__typename: 'LocalWorkItem',
|
||||
id: '1',
|
||||
id: 'gid://gitlab/WorkItem/1',
|
||||
type: 'FEATURE',
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
title: 'Test Work Item',
|
||||
widgets: {
|
||||
__typename: 'LocalWorkItemWidgetConnection',
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'LocalTitleWidget',
|
||||
type: 'TITLE',
|
||||
enabled: true,
|
||||
// eslint-disable-next-line @gitlab/require-i18n-strings
|
||||
contentText: 'Test Work Item Title',
|
||||
},
|
||||
],
|
||||
nodes: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,53 +1,16 @@
|
|||
import { uuids } from '~/lib/utils/uuids';
|
||||
import workItemQuery from './work_item.query.graphql';
|
||||
|
||||
export const resolvers = {
|
||||
Mutation: {
|
||||
localCreateWorkItem(_, { input }, { cache }) {
|
||||
const id = uuids()[0];
|
||||
const workItem = {
|
||||
__typename: 'LocalWorkItem',
|
||||
type: 'FEATURE',
|
||||
id,
|
||||
widgets: {
|
||||
__typename: 'LocalWorkItemWidgetConnection',
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'LocalTitleWidget',
|
||||
type: 'TITLE',
|
||||
enabled: true,
|
||||
contentText: input.title,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
cache.writeQuery({
|
||||
query: workItemQuery,
|
||||
variables: { id },
|
||||
data: { localWorkItem: workItem },
|
||||
});
|
||||
|
||||
return {
|
||||
__typename: 'LocalCreateWorkItemPayload',
|
||||
workItem,
|
||||
};
|
||||
},
|
||||
|
||||
localUpdateWorkItem(_, { input }, { cache }) {
|
||||
const workItemTitle = {
|
||||
__typename: 'LocalTitleWidget',
|
||||
type: 'TITLE',
|
||||
enabled: true,
|
||||
contentText: input.title,
|
||||
};
|
||||
const workItem = {
|
||||
__typename: 'LocalWorkItem',
|
||||
type: 'FEATURE',
|
||||
id: input.id,
|
||||
title: input.title,
|
||||
widgets: {
|
||||
__typename: 'LocalWorkItemWidgetConnection',
|
||||
nodes: [workItemTitle],
|
||||
nodes: [],
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -22,14 +22,10 @@ type LocalWorkItemWidgetConnection {
|
|||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type LocalTitleWidget implements LocalWorkItemWidget {
|
||||
type: LocalWidgetType!
|
||||
contentText: String!
|
||||
}
|
||||
|
||||
type LocalWorkItem {
|
||||
id: ID!
|
||||
type: LocalWorkItemType!
|
||||
title: String!
|
||||
widgets: [LocalWorkItemWidgetConnection]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#import './widget.fragment.graphql'
|
||||
|
||||
mutation updateWorkItem($input: LocalUpdateWorkItemInput) {
|
||||
localUpdateWorkItem(input: $input) @client {
|
||||
mutation workItemUpdate($input: WorkItemUpdateInput!) {
|
||||
workItemUpdate(input: $input) {
|
||||
workItem {
|
||||
id
|
||||
type
|
||||
widgets {
|
||||
title
|
||||
workItemType {
|
||||
id
|
||||
}
|
||||
widgets @client {
|
||||
nodes {
|
||||
...WidgetBase
|
||||
... on LocalTitleWidget {
|
||||
contentText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
#import './widget.fragment.graphql'
|
||||
|
||||
query WorkItem($id: ID!) {
|
||||
localWorkItem(id: $id) @client {
|
||||
workItem(id: $id) {
|
||||
id
|
||||
type
|
||||
widgets {
|
||||
title
|
||||
workItemType {
|
||||
id
|
||||
}
|
||||
widgets @client {
|
||||
nodes {
|
||||
...WidgetBase
|
||||
... on LocalTitleWidget {
|
||||
contentText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<script>
|
||||
import { GlButton, GlAlert, GlLoadingIcon, GlDropdown, GlDropdownItem } from '@gitlab/ui';
|
||||
import { s__ } from '~/locale';
|
||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||
import workItemQuery from '../graphql/work_item.query.graphql';
|
||||
import createWorkItemMutation from '../graphql/create_work_item.mutation.graphql';
|
||||
import projectWorkItemTypesQuery from '../graphql/project_work_item_types.query.graphql';
|
||||
|
||||
|
@ -67,19 +69,43 @@ export default {
|
|||
variables: {
|
||||
input: {
|
||||
title: this.title,
|
||||
projectPath: this.fullPath,
|
||||
workItemTypeId: this.selectedWorkItemType?.id,
|
||||
},
|
||||
},
|
||||
update(store, { data: { workItemCreate } }) {
|
||||
const { id, title, workItemType } = workItemCreate.workItem;
|
||||
|
||||
store.writeQuery({
|
||||
query: workItemQuery,
|
||||
variables: {
|
||||
id,
|
||||
},
|
||||
data: {
|
||||
workItem: {
|
||||
__typename: 'WorkItem',
|
||||
id,
|
||||
title,
|
||||
workItemType,
|
||||
widgets: {
|
||||
__typename: 'LocalWorkItemWidgetConnection',
|
||||
nodes: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const {
|
||||
data: {
|
||||
localCreateWorkItem: {
|
||||
workItemCreate: {
|
||||
workItem: { id, type },
|
||||
},
|
||||
},
|
||||
} = response;
|
||||
if (!this.isModal) {
|
||||
this.$router.push({ name: 'workItem', params: { id } });
|
||||
this.$router.push({ name: 'workItem', params: { id: `${getIdFromGraphQLId(id)}` } });
|
||||
} else {
|
||||
this.$emit('onCreate', { id, title: this.title, type });
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<script>
|
||||
import { GlAlert } from '@gitlab/ui';
|
||||
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
|
||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||
import Tracking from '~/tracking';
|
||||
import workItemQuery from '../graphql/work_item.query.graphql';
|
||||
import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql';
|
||||
import { widgetTypes, WI_TITLE_TRACK_LABEL } from '../constants';
|
||||
import { WI_TITLE_TRACK_LABEL } from '../constants';
|
||||
|
||||
import ItemTitle from '../components/item_title.vue';
|
||||
|
||||
|
@ -14,6 +15,7 @@ export default {
|
|||
components: {
|
||||
ItemTitle,
|
||||
GlAlert,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
mixins: [trackingMixin],
|
||||
props: {
|
||||
|
@ -24,7 +26,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
workItem: null,
|
||||
workItem: {},
|
||||
error: false,
|
||||
};
|
||||
},
|
||||
|
@ -33,12 +35,9 @@ export default {
|
|||
query: workItemQuery,
|
||||
variables() {
|
||||
return {
|
||||
id: this.id,
|
||||
id: this.gid,
|
||||
};
|
||||
},
|
||||
update(data) {
|
||||
return data.localWorkItem;
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
|
@ -50,19 +49,19 @@ export default {
|
|||
property: '[type_work_item]',
|
||||
};
|
||||
},
|
||||
titleWidgetData() {
|
||||
return this.workItem?.widgets?.nodes?.find((widget) => widget.type === widgetTypes.title);
|
||||
gid() {
|
||||
return convertToGraphQLId('WorkItem', this.id);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async updateWorkItem(title) {
|
||||
async updateWorkItem(updatedTitle) {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: updateWorkItemMutation,
|
||||
variables: {
|
||||
input: {
|
||||
id: this.id,
|
||||
title,
|
||||
id: this.gid,
|
||||
title: updatedTitle,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -82,12 +81,18 @@ export default {
|
|||
}}</gl-alert>
|
||||
<!-- Title widget placeholder -->
|
||||
<div>
|
||||
<item-title
|
||||
v-if="titleWidgetData"
|
||||
:initial-title="titleWidgetData.contentText"
|
||||
data-testid="title"
|
||||
@title-changed="updateWorkItem"
|
||||
<gl-loading-icon
|
||||
v-if="$apollo.queries.workItem.loading"
|
||||
size="md"
|
||||
data-testid="loading-types"
|
||||
/>
|
||||
<template v-else>
|
||||
<item-title
|
||||
:initial-title="workItem.title"
|
||||
data-testid="title"
|
||||
@title-changed="updateWorkItem"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
@ -243,51 +243,6 @@ module SortingHelper
|
|||
sort_options_hash[sort_value]
|
||||
end
|
||||
|
||||
def issuable_sort_options(viewing_issues, viewing_merge_requests)
|
||||
options = [
|
||||
{ value: sort_value_priority, text: sort_title_priority, href: page_filter_path(sort: sort_value_priority) },
|
||||
{ value: sort_value_created_date, text: sort_title_created_date, href: page_filter_path(sort: sort_value_created_date) },
|
||||
{ value: sort_value_recently_updated, text: sort_title_recently_updated, href: page_filter_path(sort: sort_value_recently_updated) },
|
||||
{ value: sort_value_milestone, text: sort_title_milestone, href: page_filter_path(sort: sort_value_milestone) }
|
||||
]
|
||||
|
||||
options.concat([due_date_option]) if viewing_issues
|
||||
|
||||
options.concat([popularity_option, label_priority_option])
|
||||
options.concat([merged_option, closed_option]) if viewing_merge_requests
|
||||
options.concat([relative_position_option]) if viewing_issues
|
||||
|
||||
options.concat([title_option])
|
||||
end
|
||||
|
||||
def due_date_option
|
||||
{ value: sort_value_due_date, text: sort_title_due_date, href: page_filter_path(sort: sort_value_due_date) }
|
||||
end
|
||||
|
||||
def popularity_option
|
||||
{ value: sort_value_popularity, text: sort_title_popularity, href: page_filter_path(sort: sort_value_popularity) }
|
||||
end
|
||||
|
||||
def label_priority_option
|
||||
{ value: sort_value_label_priority, text: sort_title_label_priority, href: page_filter_path(sort: sort_value_label_priority) }
|
||||
end
|
||||
|
||||
def merged_option
|
||||
{ value: sort_value_merged_date, text: sort_title_merged_date, href: page_filter_path(sort: sort_value_merged_date) }
|
||||
end
|
||||
|
||||
def closed_option
|
||||
{ value: sort_value_closed_date, text: sort_title_closed_date, href: page_filter_path(sort: sort_value_closed_date) }
|
||||
end
|
||||
|
||||
def relative_position_option
|
||||
{ value: sort_value_relative_position, text: sort_title_relative_position, href: page_filter_path(sort: sort_value_relative_position) }
|
||||
end
|
||||
|
||||
def title_option
|
||||
{ value: sort_value_title, text: sort_title_title, href: page_filter_path(sort: sort_value_title) }
|
||||
end
|
||||
|
||||
def sort_direction_icon(sort_value)
|
||||
case sort_value
|
||||
when sort_value_milestone, sort_value_due_date, sort_value_merged_date, sort_value_closed_date, /_asc\z/
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
|
||||
= cache(cache_key, expires_in: 1.day) do
|
||||
- if @merge_request.closed_or_merged_without_fork?
|
||||
.gl-alert.gl-alert-danger.gl-mb-5
|
||||
.gl-alert-container
|
||||
= sprite_icon('error', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
|
||||
.gl-alert-content
|
||||
.gl-alert-body
|
||||
The source project of this merge request has been removed.
|
||||
= render 'shared/global_alert',
|
||||
alert_class: 'gl-mb-5',
|
||||
variant: :danger,
|
||||
dismissible: false do
|
||||
.gl-alert-body
|
||||
= _('The source project of this merge request has been removed.')
|
||||
|
||||
.detail-page-header.border-bottom-0.pt-0.pb-0
|
||||
.detail-page-header-body
|
||||
|
@ -45,9 +45,9 @@
|
|||
%li= link_to _('Report abuse'), new_abuse_report_path(user_id: @merge_request.author.id, ref_url: merge_request_url(@merge_request))
|
||||
|
||||
- if can_update_merge_request
|
||||
= link_to _('Edit'), edit_project_merge_request_path(@project, @merge_request), class: "d-none d-md-block btn gl-button btn-default btn-grouped js-issuable-edit", data: { qa_selector: "edit_button" }
|
||||
= link_to _('Edit'), edit_project_merge_request_path(@project, @merge_request), class: "gl-display-none gl-md-display-block btn gl-button btn-default btn-grouped js-issuable-edit", data: { qa_selector: "edit_button" }
|
||||
|
||||
- if can_update_merge_request && !are_close_and_open_buttons_hidden
|
||||
= render 'projects/merge_requests/close_reopen_draft_report_toggle'
|
||||
- elsif !@merge_request.merged?
|
||||
= link_to _('Report abuse'), new_abuse_report_path(user_id: @merge_request.author.id, ref_url: merge_request_url(@merge_request)), class: 'gl-display-none gl-md-display-block gl-button btn btn-default float-right gl-ml-3', title: _('Report abuse')
|
||||
= link_to _('Report abuse'), new_abuse_report_path(user_id: @merge_request.author.id, ref_url: merge_request_url(@merge_request)), class: 'gl-display-none gl-md-display-block gl-button btn btn-default gl-float-right gl-ml-3', title: _('Report abuse')
|
||||
|
|
|
@ -1,9 +1,26 @@
|
|||
- sort_value = @sort
|
||||
- sort_title = issuable_sort_option_title(sort_value)
|
||||
- viewing_issues = controller.controller_name == 'issues' || controller.action_name == 'issues'
|
||||
- viewing_merge_requests = controller.controller_name == 'merge_requests'
|
||||
- items = issuable_sort_options(viewing_issues, viewing_merge_requests)
|
||||
- selected = issuable_sort_option_overrides[@sort] || @sort
|
||||
|
||||
.gl-ml-3
|
||||
.dropdown.inline.gl-ml-3.issue-sort-dropdown
|
||||
.btn-group{ role: 'group' }
|
||||
= gl_redirect_listbox_tag(items, selected, data: { right: true })
|
||||
= issuable_sort_direction_button(@sort)
|
||||
.btn-group{ role: 'group' }
|
||||
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'gl-button btn btn-default' }
|
||||
= sort_title
|
||||
= sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3")
|
||||
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
|
||||
%li
|
||||
= sortable_item(sort_title_priority, page_filter_path(sort: sort_value_priority), sort_title)
|
||||
= sortable_item(sort_title_created_date, page_filter_path(sort: sort_value_created_date), sort_title)
|
||||
= sortable_item(sort_title_recently_updated, page_filter_path(sort: sort_value_recently_updated), sort_title)
|
||||
= sortable_item(sort_title_milestone, page_filter_path(sort: sort_value_milestone), sort_title)
|
||||
= sortable_item(sort_title_due_date, page_filter_path(sort: sort_value_due_date), sort_title) if viewing_issues
|
||||
= sortable_item(sort_title_popularity, page_filter_path(sort: sort_value_popularity), sort_title)
|
||||
= sortable_item(sort_title_label_priority, page_filter_path(sort: sort_value_label_priority), sort_title)
|
||||
= sortable_item(sort_title_merged_date, page_filter_path(sort: sort_value_merged_date), sort_title) if viewing_merge_requests
|
||||
= sortable_item(sort_title_closed_date, page_filter_path(sort: sort_value_closed_date), sort_title) if viewing_merge_requests
|
||||
= sortable_item(sort_title_relative_position, page_filter_path(sort: sort_value_relative_position), sort_title) if viewing_issues
|
||||
= sortable_item(sort_title_title, page_filter_path(sort: sort_value_title), sort_title)
|
||||
= render_if_exists('shared/ee/issuable/sort_dropdown', viewing_issues: viewing_issues, sort_title: sort_title)
|
||||
= issuable_sort_direction_button(sort_value)
|
||||
|
|
|
@ -163,9 +163,8 @@ For more information, see [Deployment safety](deployment_safety.md).
|
|||
Typically, large enterprise organizations have an explicit permission boundary
|
||||
between [developers and operators](https://about.gitlab.com/topics/devops/).
|
||||
Developers build and test their code, and operators deploy and monitor the
|
||||
application. With group-level protected environments, the permission of each
|
||||
group is carefully configured in order to prevent unauthorized access and
|
||||
maintain proper separation of duty. Group-level protected environments
|
||||
application. With group-level protected environments, operators can
|
||||
restrict access to critical environments from developers. Group-level protected environments
|
||||
extend the [project-level protected environments](#protecting-environments)
|
||||
to the group-level.
|
||||
|
||||
|
@ -194,12 +193,6 @@ and are protected at the same time.
|
|||
|
||||
### Configure group-level memberships
|
||||
|
||||
In an enterprise organization, with thousands of projects under a single group,
|
||||
ensuring that all of the [project-level protected environments](#protecting-environments)
|
||||
are properly configured is not a scalable solution. For example, a developer
|
||||
might gain privileged access to a higher environment when they are given the Maintainer role
|
||||
for a new project. Group-level protected environments can be a solution in this situation.
|
||||
|
||||
To maximize the effectiveness of group-level protected environments,
|
||||
[group-level memberships](../../user/group/index.md) must be correctly
|
||||
configured:
|
||||
|
@ -237,7 +230,7 @@ Having this configuration in place:
|
|||
- If a user is about to run a deployment job in a project but disallowed to
|
||||
deploy to the environment, the deployment job fails with an error message.
|
||||
|
||||
### Protect a group-level environment
|
||||
### Protect critical environments under a group
|
||||
|
||||
To protect a group-level environment:
|
||||
|
||||
|
|
|
@ -36,6 +36,6 @@ git tag
|
|||
git push origin --tags
|
||||
```
|
||||
|
||||
## Additional resources
|
||||
## Related topics
|
||||
|
||||
- [Tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging) Git reference page
|
||||
|
|
|
@ -51,7 +51,7 @@ secret_detection:
|
|||
else
|
||||
# determine commit range so that we can fetch the appropriate depth
|
||||
# check the exit code to determine if we need to limit the commit_list.txt to CI_COMMIT_SHA.
|
||||
if ! git log --no-merges --pretty=format:"%H" ${CI_COMMIT_BEFORE_SHA}..${CI_COMMIT_SHA} >${CI_COMMIT_SHA}_commit_list.txt;
|
||||
if ! git log --pretty=format:"%H" ${CI_COMMIT_BEFORE_SHA}..${CI_COMMIT_SHA} >${CI_COMMIT_SHA}_commit_list.txt;
|
||||
then
|
||||
echo "unable to determine commit range, limiting to ${CI_COMMIT_SHA}"
|
||||
echo ${CI_COMMIT_SHA} >${CI_COMMIT_SHA}_commit_list.txt
|
||||
|
|
|
@ -19,8 +19,7 @@ module Gitlab
|
|||
variables.concat(project.predefined_variables)
|
||||
variables.concat(pipeline.predefined_variables)
|
||||
variables.concat(job.runner.predefined_variables) if job.runnable? && job.runner
|
||||
variables.concat(kubernetes_variables(job))
|
||||
variables.concat(deployment_variables(environment: environment, job: job))
|
||||
variables.concat(kubernetes_variables(environment: environment, job: job))
|
||||
variables.concat(job.yaml_variables)
|
||||
variables.concat(user_variables(job.user))
|
||||
variables.concat(job.dependency_variables) if dependencies
|
||||
|
@ -33,11 +32,15 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def kubernetes_variables(job)
|
||||
def kubernetes_variables(environment:, job:)
|
||||
::Gitlab::Ci::Variables::Collection.new.tap do |collection|
|
||||
# Should get merged with the cluster kubeconfig in deployment_variables, see
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/335089
|
||||
# NOTE: deployment_variables will be removed as part of cleanup for
|
||||
# https://gitlab.com/groups/gitlab-org/configure/-/epics/8
|
||||
# Until then, we need to make both the old and the new KUBECONFIG contexts available
|
||||
collection.concat(deployment_variables(environment: environment, job: job))
|
||||
template = ::Ci::GenerateKubeconfigService.new(job).execute
|
||||
kubeconfig_yaml = collection['KUBECONFIG']&.value
|
||||
template.merge_yaml(kubeconfig_yaml) if kubeconfig_yaml.present?
|
||||
|
||||
if template.valid?
|
||||
collection.append(key: 'KUBECONFIG', value: template.to_yaml, public: false, file: true)
|
||||
|
|
|
@ -14,6 +14,7 @@ module Gitlab
|
|||
@clusters = []
|
||||
@users = []
|
||||
@contexts = []
|
||||
@current_context = nil
|
||||
end
|
||||
|
||||
def valid?
|
||||
|
@ -32,14 +33,45 @@ module Gitlab
|
|||
contexts << new_entry(:context, **args)
|
||||
end
|
||||
|
||||
def merge_yaml(kubeconfig_yaml)
|
||||
return unless kubeconfig_yaml
|
||||
|
||||
kubeconfig_yaml = YAML.safe_load(kubeconfig_yaml, symbolize_names: true)
|
||||
kubeconfig_yaml[:users].each do |user|
|
||||
add_user(
|
||||
name: user[:name],
|
||||
token: user.dig(:user, :token)
|
||||
)
|
||||
end
|
||||
kubeconfig_yaml[:clusters].each do |cluster|
|
||||
ca_pem = cluster.dig(:cluster, :'certificate-authority-data')&.yield_self do |data|
|
||||
Base64.strict_decode64(data)
|
||||
end
|
||||
|
||||
add_cluster(
|
||||
name: cluster[:name],
|
||||
url: cluster.dig(:cluster, :server),
|
||||
ca_pem: ca_pem
|
||||
)
|
||||
end
|
||||
kubeconfig_yaml[:contexts].each do |context|
|
||||
add_context(
|
||||
name: context[:name],
|
||||
**context[:context]&.slice(:cluster, :user, :namespace)
|
||||
)
|
||||
end
|
||||
@current_context = kubeconfig_yaml[:'current-context']
|
||||
end
|
||||
|
||||
def to_h
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'Config',
|
||||
clusters: clusters.map(&:to_h),
|
||||
users: users.map(&:to_h),
|
||||
contexts: contexts.map(&:to_h)
|
||||
}
|
||||
contexts: contexts.map(&:to_h),
|
||||
'current-context': current_context
|
||||
}.compact
|
||||
end
|
||||
|
||||
def to_yaml
|
||||
|
@ -48,7 +80,7 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
attr_reader :clusters, :users, :contexts
|
||||
attr_reader :clusters, :users, :contexts, :current_context
|
||||
|
||||
def new_entry(entry, **args)
|
||||
ENTRIES.fetch(entry).new(**args)
|
||||
|
|
|
@ -36924,6 +36924,9 @@ msgstr ""
|
|||
msgid "The snippet is visible to any logged in user except external users."
|
||||
msgstr ""
|
||||
|
||||
msgid "The source project of this merge request has been removed."
|
||||
msgstr ""
|
||||
|
||||
msgid "The specified tab is invalid, please select another"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -78,14 +78,14 @@ RSpec.describe 'Dashboard Issues filtering', :js do
|
|||
end
|
||||
|
||||
it 'remembers last sorting value' do
|
||||
pajamas_sort_by(s_('SortOptions|Created date'))
|
||||
sort_by('Created date')
|
||||
visit_issues(assignee_username: user.username)
|
||||
|
||||
expect(page).to have_button('Created date')
|
||||
end
|
||||
|
||||
it 'keeps sorting issues after visiting Projects Issues page' do
|
||||
pajamas_sort_by(s_('SortOptions|Created date'))
|
||||
sort_by('Created date')
|
||||
visit project_issues_path(project)
|
||||
|
||||
expect(page).to have_button('Created date')
|
||||
|
|
|
@ -115,9 +115,6 @@ RSpec.describe 'Dashboard Merge Requests' do
|
|||
within("span[aria-label='#{n_("%d merge request", "%d merge requests", 3) % 3}']") do
|
||||
expect(page).to have_content('3')
|
||||
end
|
||||
|
||||
find('.dashboard-shortcuts-merge_requests').click
|
||||
|
||||
expect(find('.js-assigned-mr-count')).to have_content('2')
|
||||
expect(find('.js-reviewer-mr-count')).to have_content('1')
|
||||
end
|
||||
|
@ -168,16 +165,16 @@ RSpec.describe 'Dashboard Merge Requests' do
|
|||
expect(page).to have_content('Please select at least one filter to see results')
|
||||
end
|
||||
|
||||
it 'shows sorted merge requests', :js do
|
||||
pajamas_sort_by(s_('SortOptions|Created date'))
|
||||
it 'shows sorted merge requests' do
|
||||
sort_by('Created date')
|
||||
|
||||
visit merge_requests_dashboard_path(assignee_username: current_user.username)
|
||||
|
||||
expect(find('.issues-filters')).to have_content('Created date')
|
||||
end
|
||||
|
||||
it 'keeps sorting merge requests after visiting Projects MR page', :js do
|
||||
pajamas_sort_by(s_('SortOptions|Created date'))
|
||||
it 'keeps sorting merge requests after visiting Projects MR page' do
|
||||
sort_by('Created date')
|
||||
|
||||
visit project_merge_requests_path(project)
|
||||
|
||||
|
|
|
@ -88,14 +88,14 @@ RSpec.describe 'Sort Issuable List' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'custom sorting', :js do
|
||||
context 'custom sorting' do
|
||||
let(:issuable_type) { :merge_request }
|
||||
|
||||
it 'supports sorting in asc and desc order' do
|
||||
visit_merge_requests_with_state(project, 'open')
|
||||
|
||||
click_button('Created date')
|
||||
find('.dropdown-item', text: 'Updated date').click
|
||||
click_link('Updated date')
|
||||
|
||||
expect(first_merge_request).to include(last_updated_issuable.title)
|
||||
expect(last_merge_request).to include(first_updated_issuable.title)
|
||||
|
|
|
@ -556,7 +556,7 @@ RSpec.describe 'Filter issues', :js do
|
|||
sort_toggle = find('.filter-dropdown-container .dropdown')
|
||||
sort_toggle.click
|
||||
|
||||
find('.dropdown-item', text: 'Created date').click
|
||||
find('.filter-dropdown-container .dropdown-menu li a', text: 'Created date').click
|
||||
wait_for_requests
|
||||
|
||||
expect(find('.issues-list .issue:first-of-type .issue-title-text a')).to have_content(new_issue.title)
|
||||
|
|
|
@ -5,7 +5,6 @@ require "spec_helper"
|
|||
RSpec.describe "User sorts issues" do
|
||||
include SortingHelper
|
||||
include IssueHelpers
|
||||
include Spec::Support::Helpers::Features::SortingHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
@ -25,22 +24,26 @@ RSpec.describe "User sorts issues" do
|
|||
sign_in(user)
|
||||
end
|
||||
|
||||
it 'keeps the sort option', :js do
|
||||
it 'keeps the sort option' do
|
||||
visit(project_issues_path(project))
|
||||
|
||||
pajamas_sort_by(s_('SortOptions|Milestone'))
|
||||
find('.filter-dropdown-container .dropdown').click
|
||||
|
||||
page.within('ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link('Milestone')
|
||||
end
|
||||
|
||||
visit(issues_dashboard_path(assignee_username: user.username))
|
||||
|
||||
expect(find('.filter-dropdown-container button.dropdown-toggle')).to have_content('Milestone')
|
||||
expect(find('.issues-filters a.is-active')).to have_content('Milestone')
|
||||
|
||||
visit(project_issues_path(project))
|
||||
|
||||
expect(find('.filter-dropdown-container button.dropdown-toggle')).to have_content('Milestone')
|
||||
expect(find('.issues-filters a.is-active')).to have_content('Milestone')
|
||||
|
||||
visit(issues_group_path(group))
|
||||
|
||||
expect(find('.filter-dropdown-container button.dropdown-toggle')).to have_content('Milestone')
|
||||
expect(find('.issues-filters a.is-active')).to have_content('Milestone')
|
||||
end
|
||||
|
||||
it 'sorts by popularity', :js do
|
||||
|
|
|
@ -109,7 +109,7 @@ RSpec.describe 'Merge requests > User lists merge requests' do
|
|||
expect(count_merge_requests).to eq(4)
|
||||
end
|
||||
|
||||
it 'sorts by milestone due date' do
|
||||
it 'sorts by milestone' do
|
||||
visit_merge_requests(project, sort: sort_value_milestone)
|
||||
|
||||
expect(first_merge_request).to include('fix')
|
||||
|
@ -130,12 +130,12 @@ RSpec.describe 'Merge requests > User lists merge requests' do
|
|||
expect(count_merge_requests).to eq(4)
|
||||
end
|
||||
|
||||
it 'filters on one label and sorts by milestone due date' do
|
||||
it 'filters on one label and sorts by due date' do
|
||||
label = create(:label, project: project)
|
||||
create(:label_link, label: label, target: @fix)
|
||||
|
||||
visit_merge_requests(project, label_name: [label.name],
|
||||
sort: sort_value_milestone)
|
||||
sort: sort_value_due_date)
|
||||
|
||||
expect(first_merge_request).to include('fix')
|
||||
expect(count_merge_requests).to eq(1)
|
||||
|
@ -150,19 +150,19 @@ RSpec.describe 'Merge requests > User lists merge requests' do
|
|||
create(:label_link, label: label2, target: @fix)
|
||||
end
|
||||
|
||||
it 'sorts by milestone due date' do
|
||||
it 'sorts by due date' do
|
||||
visit_merge_requests(project, label_name: [label.name, label2.name],
|
||||
sort: sort_value_milestone)
|
||||
sort: sort_value_due_date)
|
||||
|
||||
expect(first_merge_request).to include('fix')
|
||||
expect(count_merge_requests).to eq(1)
|
||||
end
|
||||
|
||||
context 'filter on assignee and' do
|
||||
it 'sorts by milestone due date' do
|
||||
it 'sorts by due soon' do
|
||||
visit_merge_requests(project, label_name: [label.name, label2.name],
|
||||
assignee_id: user.id,
|
||||
sort: sort_value_milestone)
|
||||
sort: sort_value_due_date)
|
||||
|
||||
expect(first_merge_request).to include('fix')
|
||||
expect(count_merge_requests).to eq(1)
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'User sorts merge requests', :js do
|
||||
RSpec.describe 'User sorts merge requests' do
|
||||
include CookieHelper
|
||||
include Spec::Support::Helpers::Features::SortingHelpers
|
||||
|
||||
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
|
||||
let!(:merge_request2) do
|
||||
|
@ -23,19 +22,23 @@ RSpec.describe 'User sorts merge requests', :js do
|
|||
end
|
||||
|
||||
it 'keeps the sort option' do
|
||||
pajamas_sort_by(s_('SortOptions|Milestone'))
|
||||
find('.filter-dropdown-container .dropdown').click
|
||||
|
||||
page.within('ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link('Milestone')
|
||||
end
|
||||
|
||||
visit(merge_requests_dashboard_path(assignee_username: user.username))
|
||||
|
||||
expect(find('.filter-dropdown-container button.dropdown-toggle')).to have_content('Milestone')
|
||||
expect(find('.issues-filters a.is-active')).to have_content('Milestone')
|
||||
|
||||
visit(project_merge_requests_path(project))
|
||||
|
||||
expect(find('.filter-dropdown-container button.dropdown-toggle')).to have_content('Milestone')
|
||||
expect(find('.issues-filters a.is-active')).to have_content('Milestone')
|
||||
|
||||
visit(merge_requests_group_path(group))
|
||||
|
||||
expect(find('.filter-dropdown-container button.dropdown-toggle')).to have_content('Milestone')
|
||||
expect(find('.issues-filters a.is-active')).to have_content('Milestone')
|
||||
end
|
||||
|
||||
it 'fallbacks to issuable_sort cookie key when remembering the sorting option' do
|
||||
|
@ -43,13 +46,17 @@ RSpec.describe 'User sorts merge requests', :js do
|
|||
|
||||
visit(merge_requests_dashboard_path(assignee_username: user.username))
|
||||
|
||||
expect(find('.filter-dropdown-container button.dropdown-toggle')).to have_content('Milestone')
|
||||
expect(find('.issues-filters a.is-active')).to have_content('Milestone')
|
||||
end
|
||||
|
||||
it 'separates remember sorting with issues' do
|
||||
create(:issue, project: project)
|
||||
|
||||
pajamas_sort_by(s_('SortOptions|Milestone'))
|
||||
find('.filter-dropdown-container .dropdown').click
|
||||
|
||||
page.within('ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link('Milestone')
|
||||
end
|
||||
|
||||
visit(project_issues_path(project))
|
||||
|
||||
|
@ -66,7 +73,11 @@ RSpec.describe 'User sorts merge requests', :js do
|
|||
end
|
||||
|
||||
it 'sorts by popularity' do
|
||||
pajamas_sort_by(s_('SortOptions|Popularity'))
|
||||
find('.filter-dropdown-container .dropdown').click
|
||||
|
||||
page.within('ul.dropdown-menu.dropdown-menu-right li') do
|
||||
click_link('Popularity')
|
||||
end
|
||||
|
||||
page.within('.mr-list') do
|
||||
page.within('li.merge-request:nth-child(1)') do
|
||||
|
|
|
@ -6,7 +6,7 @@ require "spec_helper"
|
|||
# to check if the sorting option set by user is being kept persisted while going through pages.
|
||||
# The `it`s are named here by convention `starting point -> some pages -> final point`.
|
||||
# All those specs are moved out to this spec intentionally to keep them all in one place.
|
||||
RSpec.describe "User sorts things", :js do
|
||||
RSpec.describe "User sorts things" do
|
||||
include Spec::Support::Helpers::Features::SortingHelpers
|
||||
include DashboardHelper
|
||||
|
||||
|
@ -21,11 +21,11 @@ RSpec.describe "User sorts things", :js do
|
|||
end
|
||||
|
||||
it "issues -> project home page -> issues" do
|
||||
sort_option = s_('SortOptions|Updated date')
|
||||
sort_option = 'Updated date'
|
||||
|
||||
visit(project_issues_path(project))
|
||||
|
||||
pajamas_sort_by(sort_option)
|
||||
sort_by(sort_option)
|
||||
|
||||
visit(project_path(project))
|
||||
visit(project_issues_path(project))
|
||||
|
@ -34,11 +34,11 @@ RSpec.describe "User sorts things", :js do
|
|||
end
|
||||
|
||||
it "merge requests -> dashboard merge requests" do
|
||||
sort_option = s_('SortOptions|Updated date')
|
||||
sort_option = 'Updated date'
|
||||
|
||||
visit(project_merge_requests_path(project))
|
||||
|
||||
pajamas_sort_by(sort_option)
|
||||
sort_by(sort_option)
|
||||
|
||||
visit(assigned_mrs_dashboard_path)
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
export const workItemQueryResponse = {
|
||||
localWorkItem: {
|
||||
__typename: 'LocalWorkItem',
|
||||
workItem: {
|
||||
__typename: 'WorkItem',
|
||||
id: '1',
|
||||
type: 'FEATURE',
|
||||
title: 'Test',
|
||||
workItemType: {
|
||||
__typename: 'WorkItemType',
|
||||
id: 'work-item-type-1',
|
||||
},
|
||||
widgets: {
|
||||
__typename: 'LocalWorkItemWidgetConnection',
|
||||
nodes: [
|
||||
|
@ -17,20 +21,29 @@ export const workItemQueryResponse = {
|
|||
};
|
||||
|
||||
export const updateWorkItemMutationResponse = {
|
||||
__typename: 'LocalUpdateWorkItemPayload',
|
||||
workItem: {
|
||||
__typename: 'LocalWorkItem',
|
||||
id: '1',
|
||||
widgets: {
|
||||
__typename: 'LocalWorkItemWidgetConnection',
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'LocalTitleWidget',
|
||||
type: 'TITLE',
|
||||
enabled: true,
|
||||
contentText: 'Updated title',
|
||||
data: {
|
||||
workItemUpdate: {
|
||||
__typename: 'LocalUpdateWorkItemPayload',
|
||||
workItem: {
|
||||
__typename: 'LocalWorkItem',
|
||||
id: '1',
|
||||
title: 'Updated title',
|
||||
workItemType: {
|
||||
__typename: 'WorkItemType',
|
||||
id: 'work-item-type-1',
|
||||
},
|
||||
],
|
||||
widgets: {
|
||||
__typename: 'LocalWorkItemWidgetConnection',
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'LocalTitleWidget',
|
||||
type: 'TITLE',
|
||||
enabled: true,
|
||||
contentText: 'Updated title',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -48,3 +61,20 @@ export const projectWorkItemTypesQueryResponse = {
|
|||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const createWorkItemMutationResponse = {
|
||||
data: {
|
||||
workItemCreate: {
|
||||
__typename: 'WorkItemCreatePayload',
|
||||
workItem: {
|
||||
__typename: 'WorkItem',
|
||||
id: '1',
|
||||
title: 'Updated title',
|
||||
workItemType: {
|
||||
__typename: 'WorkItemType',
|
||||
id: 'work-item-type-1',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,7 +8,8 @@ import CreateWorkItem from '~/work_items/pages/create_work_item.vue';
|
|||
import ItemTitle from '~/work_items/components/item_title.vue';
|
||||
import { resolvers } from '~/work_items/graphql/resolvers';
|
||||
import projectWorkItemTypesQuery from '~/work_items/graphql/project_work_item_types.query.graphql';
|
||||
import { projectWorkItemTypesQueryResponse } from '../mock_data';
|
||||
import createWorkItemMutation from '~/work_items/graphql/create_work_item.mutation.graphql';
|
||||
import { projectWorkItemTypesQueryResponse, createWorkItemMutationResponse } from '../mock_data';
|
||||
|
||||
jest.mock('~/lib/utils/uuids', () => ({ uuids: () => ['testuuid'] }));
|
||||
|
||||
|
@ -19,6 +20,7 @@ describe('Create work item component', () => {
|
|||
let fakeApollo;
|
||||
|
||||
const querySuccessHandler = jest.fn().mockResolvedValue(projectWorkItemTypesQueryResponse);
|
||||
const mutationSuccessHandler = jest.fn().mockResolvedValue(createWorkItemMutationResponse);
|
||||
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findTitleInput = () => wrapper.findComponent(ItemTitle);
|
||||
|
@ -30,8 +32,19 @@ describe('Create work item component', () => {
|
|||
const findContent = () => wrapper.find('[data-testid="content"]');
|
||||
const findLoadingTypesIcon = () => wrapper.find('[data-testid="loading-types"]');
|
||||
|
||||
const createComponent = ({ data = {}, props = {}, queryHandler = querySuccessHandler } = {}) => {
|
||||
fakeApollo = createMockApollo([[projectWorkItemTypesQuery, queryHandler]], resolvers);
|
||||
const createComponent = ({
|
||||
data = {},
|
||||
props = {},
|
||||
queryHandler = querySuccessHandler,
|
||||
mutationHandler = mutationSuccessHandler,
|
||||
} = {}) => {
|
||||
fakeApollo = createMockApollo(
|
||||
[
|
||||
[projectWorkItemTypesQuery, queryHandler],
|
||||
[createWorkItemMutation, mutationHandler],
|
||||
],
|
||||
resolvers,
|
||||
);
|
||||
wrapper = shallowMount(CreateWorkItem, {
|
||||
apolloProvider: fakeApollo,
|
||||
data() {
|
||||
|
@ -126,7 +139,7 @@ describe('Create work item component', () => {
|
|||
wrapper.find('form').trigger('submit');
|
||||
await waitForPromises();
|
||||
|
||||
const expected = { id: 'testuuid', title: mockTitle, type: 'FEATURE' };
|
||||
const expected = { id: '1', title: mockTitle };
|
||||
expect(wrapper.emitted('onCreate')).toEqual([[expected]]);
|
||||
});
|
||||
|
||||
|
|
|
@ -9,11 +9,12 @@ import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutati
|
|||
import WorkItemsRoot from '~/work_items/pages/work_item_root.vue';
|
||||
import ItemTitle from '~/work_items/components/item_title.vue';
|
||||
import { resolvers } from '~/work_items/graphql/resolvers';
|
||||
import { workItemQueryResponse } from '../mock_data';
|
||||
import { workItemQueryResponse, updateWorkItemMutationResponse } from '../mock_data';
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
const WORK_ITEM_ID = '1';
|
||||
const WORK_ITEM_GID = `gid://gitlab/WorkItem/${WORK_ITEM_ID}`;
|
||||
|
||||
describe('Work items root component', () => {
|
||||
const mockUpdatedTitle = 'Updated title';
|
||||
|
@ -23,15 +24,19 @@ describe('Work items root component', () => {
|
|||
const findTitle = () => wrapper.findComponent(ItemTitle);
|
||||
|
||||
const createComponent = ({ queryResponse = workItemQueryResponse } = {}) => {
|
||||
fakeApollo = createMockApollo([], resolvers, {
|
||||
possibleTypes: {
|
||||
LocalWorkItemWidget: ['LocalTitleWidget'],
|
||||
fakeApollo = createMockApollo(
|
||||
[[updateWorkItemMutation, jest.fn().mockResolvedValue(updateWorkItemMutationResponse)]],
|
||||
resolvers,
|
||||
{
|
||||
possibleTypes: {
|
||||
LocalWorkItemWidget: ['LocalTitleWidget'],
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
fakeApollo.clients.defaultClient.cache.writeQuery({
|
||||
query: workItemQuery,
|
||||
variables: {
|
||||
id: WORK_ITEM_ID,
|
||||
id: WORK_ITEM_GID,
|
||||
},
|
||||
data: queryResponse,
|
||||
});
|
||||
|
@ -49,7 +54,7 @@ describe('Work items root component', () => {
|
|||
fakeApollo = null;
|
||||
});
|
||||
|
||||
it('renders the title if title is in the widgets list', () => {
|
||||
it('renders the title', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findTitle().exists()).toBe(true);
|
||||
|
@ -66,35 +71,11 @@ describe('Work items root component', () => {
|
|||
mutation: updateWorkItemMutation,
|
||||
variables: {
|
||||
input: {
|
||||
id: WORK_ITEM_ID,
|
||||
id: WORK_ITEM_GID,
|
||||
title: mockUpdatedTitle,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await waitForPromises();
|
||||
expect(findTitle().props('initialTitle')).toBe(mockUpdatedTitle);
|
||||
});
|
||||
|
||||
it('does not render the title if title is not in the widgets list', () => {
|
||||
const queryResponse = {
|
||||
workItem: {
|
||||
...workItemQueryResponse.workItem,
|
||||
widgets: {
|
||||
__typename: 'WorkItemWidgetConnection',
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'SomeOtherWidget',
|
||||
type: 'OTHER',
|
||||
contentText: 'Test',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
createComponent({ queryResponse });
|
||||
|
||||
expect(findTitle().exists()).toBe(false);
|
||||
});
|
||||
|
||||
describe('tracking', () => {
|
||||
|
|
|
@ -21,6 +21,7 @@ describe('Work items router', () => {
|
|||
mocks: {
|
||||
$apollo: {
|
||||
queries: {
|
||||
workItem: {},
|
||||
workItemTypes: {},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -158,7 +158,6 @@ RSpec.describe Gitlab::Ci::Variables::Builder do
|
|||
allow(pipeline).to receive(:predefined_variables) { [var('C', 3), var('D', 3)] }
|
||||
allow(job).to receive(:runner) { double(predefined_variables: [var('D', 4), var('E', 4)]) }
|
||||
allow(builder).to receive(:kubernetes_variables) { [var('E', 5), var('F', 5)] }
|
||||
allow(builder).to receive(:deployment_variables) { [var('F', 6), var('G', 6)] }
|
||||
allow(job).to receive(:yaml_variables) { [var('G', 7), var('H', 7)] }
|
||||
allow(builder).to receive(:user_variables) { [var('H', 8), var('I', 8)] }
|
||||
allow(job).to receive(:dependency_variables) { [var('I', 9), var('J', 9)] }
|
||||
|
@ -177,7 +176,6 @@ RSpec.describe Gitlab::Ci::Variables::Builder do
|
|||
var('C', 3), var('D', 3),
|
||||
var('D', 4), var('E', 4),
|
||||
var('E', 5), var('F', 5),
|
||||
var('F', 6), var('G', 6),
|
||||
var('G', 7), var('H', 7),
|
||||
var('H', 8), var('I', 8),
|
||||
var('I', 9), var('J', 9),
|
||||
|
@ -193,7 +191,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder do
|
|||
expect(subject.to_hash).to match(
|
||||
'A' => '1', 'B' => '2',
|
||||
'C' => '3', 'D' => '4',
|
||||
'E' => '5', 'F' => '6',
|
||||
'E' => '5', 'F' => '5',
|
||||
'G' => '7', 'H' => '8',
|
||||
'I' => '9', 'J' => '10',
|
||||
'K' => '11', 'L' => '12',
|
||||
|
@ -231,7 +229,7 @@ RSpec.describe Gitlab::Ci::Variables::Builder do
|
|||
let(:template) { double(to_yaml: 'example-kubeconfig', valid?: template_valid) }
|
||||
let(:template_valid) { true }
|
||||
|
||||
subject { builder.kubernetes_variables(job) }
|
||||
subject { builder.kubernetes_variables(environment: nil, job: job) }
|
||||
|
||||
before do
|
||||
allow(Ci::GenerateKubeconfigService).to receive(:new).with(job).and_return(service)
|
||||
|
@ -244,6 +242,16 @@ RSpec.describe Gitlab::Ci::Variables::Builder do
|
|||
|
||||
it { is_expected.not_to include(key: 'KUBECONFIG', value: 'example-kubeconfig', public: false, file: true) }
|
||||
end
|
||||
|
||||
it 'includes #deployment_variables and merges the KUBECONFIG values', :aggregate_failures do
|
||||
expect(builder).to receive(:deployment_variables).and_return([
|
||||
{ key: 'KUBECONFIG', value: 'deployment-kubeconfig' },
|
||||
{ key: 'OTHER', value: 'some value' }
|
||||
])
|
||||
expect(template).to receive(:merge_yaml).with('deployment-kubeconfig')
|
||||
expect(subject['KUBECONFIG'].value).to eq('example-kubeconfig')
|
||||
expect(subject['OTHER'].value).to eq('some value')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#deployment_variables' do
|
||||
|
|
|
@ -39,6 +39,51 @@ RSpec.describe Gitlab::Kubernetes::Kubeconfig::Template do
|
|||
it { is_expected.to eq(YAML.dump(template.to_h.deep_stringify_keys)) }
|
||||
end
|
||||
|
||||
describe '#merge_yaml' do
|
||||
it 'appends to the configuration and overwrites the current context' do
|
||||
template.add_cluster(name: 'hello-cluster', url: 'hello-url')
|
||||
template.add_context(name: 'hello-context', cluster: 'hello-cluster', user: 'hello-user')
|
||||
template.add_user(name: 'hello-user', token: 'hello-token')
|
||||
ca_pem = Base64.strict_encode64('a certificate')
|
||||
template.merge_yaml(<<~YAML)
|
||||
apiVersion: v1
|
||||
kind: Config
|
||||
clusters:
|
||||
- name: 'gitlab-deploy'
|
||||
cluster:
|
||||
server: url
|
||||
certificate-authority-data: #{ca_pem.inspect}
|
||||
contexts:
|
||||
- name: gitlab-deploy
|
||||
context:
|
||||
cluster: gitlab-deploy
|
||||
namespace: namespace
|
||||
user: gitlab-deploy
|
||||
current-context: gitlab-deploy
|
||||
users:
|
||||
- name: 'gitlab-deploy'
|
||||
user: { token: token }
|
||||
YAML
|
||||
expect(template.to_h).to eq({
|
||||
apiVersion: 'v1',
|
||||
kind: 'Config',
|
||||
clusters: [
|
||||
{ name: 'hello-cluster', cluster: { server: 'hello-url' } },
|
||||
{ name: 'gitlab-deploy', cluster: { server: 'url', 'certificate-authority-data': ca_pem } }
|
||||
],
|
||||
contexts: [
|
||||
{ name: 'hello-context', context: { cluster: 'hello-cluster', user: 'hello-user' } },
|
||||
{ name: 'gitlab-deploy', context: { cluster: 'gitlab-deploy', namespace: 'namespace', user: 'gitlab-deploy' } }
|
||||
],
|
||||
users: [
|
||||
{ name: 'hello-user', user: { token: 'hello-token' } },
|
||||
{ name: 'gitlab-deploy', user: { token: 'token' } }
|
||||
],
|
||||
'current-context': 'gitlab-deploy'
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
describe 'adding entries' do
|
||||
let(:entry) { instance_double(entry_class, to_h: attributes) }
|
||||
let(:attributes) do
|
||||
|
|
|
@ -21,14 +21,6 @@ module Spec
|
|||
click_link(value)
|
||||
end
|
||||
end
|
||||
|
||||
# pajamas_sort_by is used to sort new pajamas dropdowns. When
|
||||
# all of the dropdowns are converted, pajamas_sort_by can be renamed to sort_by
|
||||
# https://gitlab.com/groups/gitlab-org/-/epics/7551
|
||||
def pajamas_sort_by(value)
|
||||
find('.filter-dropdown-container .dropdown').click
|
||||
find('.dropdown-item', text: value).click
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue