Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c86c0e0146
commit
2e9f877e8b
12
.rubocop.yml
12
.rubocop.yml
|
@ -18,6 +18,7 @@ inherit_from:
|
|||
inherit_mode:
|
||||
merge:
|
||||
- Include
|
||||
- Exclude
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.7
|
||||
|
@ -597,3 +598,14 @@ FactoryBot/InlineAssociation:
|
|||
Include:
|
||||
- 'spec/factories/**/*.rb'
|
||||
- 'ee/spec/factories/**/*.rb'
|
||||
|
||||
# WIP: https://gitlab.com/gitlab-org/gitlab/-/issues/321982
|
||||
Gitlab/NamespacedClass:
|
||||
Exclude:
|
||||
- 'config/**/*.rb'
|
||||
- 'db/**/*.rb'
|
||||
- 'ee/bin/**/*'
|
||||
- 'ee/db/**/*.rb'
|
||||
- 'ee/elastic/**/*.rb'
|
||||
- 'scripts/**/*'
|
||||
- 'spec/migrations/**/*.rb'
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
# - guidelines for use found in
|
||||
# https://docs.gitlab.com/ee/development/contributing/style_guides.html#resolving-rubocop-exceptions.
|
||||
|
||||
# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/267606
|
||||
FactoryBot/InlineAssociation:
|
||||
Exclude:
|
||||
- 'ee/spec/factories/analytics/cycle_analytics/group_stages.rb'
|
||||
|
@ -28,6 +29,7 @@ FactoryBot/InlineAssociation:
|
|||
- 'spec/factories/uploads.rb'
|
||||
- 'spec/factories/wiki_pages.rb'
|
||||
|
||||
# WIP: See https://gitlab.com/gitlab-org/gitlab/-/issues/220040
|
||||
Rails/SaveBang:
|
||||
Exclude:
|
||||
- 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
|
||||
|
@ -1174,22 +1176,9 @@ RSpec/AnyInstanceOf:
|
|||
- 'spec/workers/wait_for_cluster_creation_worker_spec.rb'
|
||||
- 'ee/spec/workers/security/auto_fix_worker_spec.rb'
|
||||
|
||||
# WIP: https://gitlab.com/gitlab-org/gitlab/-/issues/321982
|
||||
Gitlab/NamespacedClass:
|
||||
Exclude:
|
||||
- 'config/**/*.rb'
|
||||
- 'db/**/*.rb'
|
||||
- 'ee/bin/**/*'
|
||||
- 'ee/db/**/*.rb'
|
||||
- 'ee/elastic/**/*.rb'
|
||||
- 'scripts/**/*'
|
||||
- 'spec/migrations/**/*.rb'
|
||||
# The list above represents the permanent exclusions for this rule
|
||||
# due to the fact these files are related to infrastructure code.
|
||||
# This list should eventually be moved to .rubocop.yml after all TODOs
|
||||
# are addressed.
|
||||
#
|
||||
# The list below represents the classes that require
|
||||
# a namespace as they make the domain related code.
|
||||
- 'app/channels/issues_channel.rb'
|
||||
- 'app/controllers/abuse_reports_controller.rb'
|
||||
- 'app/controllers/acme_challenges_controller.rb'
|
||||
|
|
|
@ -36,11 +36,11 @@ export function formatIssue(issue) {
|
|||
}
|
||||
|
||||
export function formatListIssues(listIssues) {
|
||||
const issues = {};
|
||||
let listIssuesCount;
|
||||
const boardItems = {};
|
||||
let listItemsCount;
|
||||
|
||||
const listData = listIssues.nodes.reduce((map, list) => {
|
||||
listIssuesCount = list.issues.count;
|
||||
listItemsCount = list.issues.count;
|
||||
let sortedIssues = list.issues.edges.map((issueNode) => ({
|
||||
...issueNode.node,
|
||||
}));
|
||||
|
@ -58,14 +58,14 @@ export function formatListIssues(listIssues) {
|
|||
assignees: i.assignees?.nodes || [],
|
||||
};
|
||||
|
||||
issues[id] = listIssue;
|
||||
boardItems[id] = listIssue;
|
||||
|
||||
return id;
|
||||
}),
|
||||
};
|
||||
}, {});
|
||||
|
||||
return { listData, issues, listIssuesCount };
|
||||
return { listData, boardItems, listItemsCount };
|
||||
}
|
||||
|
||||
export function formatListsPageInfo(lists) {
|
||||
|
|
|
@ -32,12 +32,12 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapState(['filterParams', 'highlightedLists']),
|
||||
...mapGetters(['getIssuesByList']),
|
||||
...mapGetters(['getBoardItemsByList']),
|
||||
highlighted() {
|
||||
return this.highlightedLists.includes(this.list.id);
|
||||
},
|
||||
listIssues() {
|
||||
return this.getIssuesByList(this.list.id);
|
||||
listItems() {
|
||||
return this.getBoardItemsByList(this.list.id);
|
||||
},
|
||||
isListDraggable() {
|
||||
return isListDraggable(this.list);
|
||||
|
@ -87,7 +87,7 @@ export default {
|
|||
<board-list
|
||||
ref="board-list"
|
||||
:disabled="disabled"
|
||||
:issues="listIssues"
|
||||
:board-items="listItems"
|
||||
:list="list"
|
||||
:can-admin-list="canAdminList"
|
||||
/>
|
||||
|
|
|
@ -12,8 +12,8 @@ import BoardNewIssue from './board_new_issue.vue';
|
|||
export default {
|
||||
name: 'BoardList',
|
||||
i18n: {
|
||||
loadingIssues: __('Loading issues'),
|
||||
loadingMoreissues: __('Loading more issues'),
|
||||
loading: __('Loading'),
|
||||
loadingMoreboardItems: __('Loading more'),
|
||||
showingAllIssues: __('Showing all issues'),
|
||||
},
|
||||
components: {
|
||||
|
@ -30,7 +30,7 @@ export default {
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
issues: {
|
||||
boardItems: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
|
@ -51,11 +51,11 @@ export default {
|
|||
...mapState(['pageInfoByListId', 'listsFlags']),
|
||||
paginatedIssueText() {
|
||||
return sprintf(__('Showing %{pageSize} of %{total} issues'), {
|
||||
pageSize: this.issues.length,
|
||||
pageSize: this.boardItems.length,
|
||||
total: this.list.issuesCount,
|
||||
});
|
||||
},
|
||||
issuesSizeExceedsMax() {
|
||||
boardItemsSizeExceedsMax() {
|
||||
return this.list.maxIssueCount > 0 && this.list.issuesCount > this.list.maxIssueCount;
|
||||
},
|
||||
hasNextPage() {
|
||||
|
@ -72,7 +72,7 @@ export default {
|
|||
return this.canAdminList ? this.$refs.list.$el : this.$refs.list;
|
||||
},
|
||||
showingAllIssues() {
|
||||
return this.issues.length === this.list.issuesCount;
|
||||
return this.boardItems.length === this.list.issuesCount;
|
||||
},
|
||||
treeRootWrapper() {
|
||||
return this.canAdminList ? Draggable : 'ul';
|
||||
|
@ -85,14 +85,14 @@ export default {
|
|||
tag: 'ul',
|
||||
'ghost-class': 'board-card-drag-active',
|
||||
'data-list-id': this.list.id,
|
||||
value: this.issues,
|
||||
value: this.boardItems,
|
||||
};
|
||||
|
||||
return this.canAdminList ? options : {};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
issues() {
|
||||
boardItems() {
|
||||
this.$nextTick(() => {
|
||||
this.showCount = this.scrollHeight() > Math.ceil(this.listHeight());
|
||||
});
|
||||
|
@ -201,7 +201,7 @@ export default {
|
|||
<div
|
||||
v-if="loading"
|
||||
class="gl-mt-4 gl-text-center"
|
||||
:aria-label="$options.i18n.loadingIssues"
|
||||
:aria-label="$options.i18n.loading"
|
||||
data-testid="board_list_loading"
|
||||
>
|
||||
<gl-loading-icon />
|
||||
|
@ -214,25 +214,25 @@ export default {
|
|||
v-bind="treeRootOptions"
|
||||
:data-board="list.id"
|
||||
:data-board-type="list.listType"
|
||||
:class="{ 'bg-danger-100': issuesSizeExceedsMax }"
|
||||
:class="{ 'bg-danger-100': boardItemsSizeExceedsMax }"
|
||||
class="board-list gl-w-full gl-h-full gl-list-style-none gl-mb-0 gl-p-2 js-board-list"
|
||||
data-testid="tree-root-wrapper"
|
||||
@start="handleDragOnStart"
|
||||
@end="handleDragOnEnd"
|
||||
>
|
||||
<board-card
|
||||
v-for="(issue, index) in issues"
|
||||
v-for="(item, index) in boardItems"
|
||||
ref="issue"
|
||||
:key="issue.id"
|
||||
:key="item.id"
|
||||
:index="index"
|
||||
:list="list"
|
||||
:issue="issue"
|
||||
:issue="item"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
<li v-if="showCount" class="board-list-count gl-text-center" data-issue-id="-1">
|
||||
<gl-loading-icon
|
||||
v-if="loadingMore"
|
||||
:label="$options.i18n.loadingMoreissues"
|
||||
:label="$options.i18n.loadingMoreboardItems"
|
||||
data-testid="count-loading-icon"
|
||||
/>
|
||||
<span v-if="showingAllIssues">{{ $options.i18n.showingAllIssues }}</span>
|
||||
|
|
|
@ -289,9 +289,9 @@ export default {
|
|||
})
|
||||
.then(({ data }) => {
|
||||
const { lists } = data[boardType]?.board;
|
||||
const listIssues = formatListIssues(lists);
|
||||
const listItems = formatListIssues(lists);
|
||||
const listPageInfo = formatListsPageInfo(lists);
|
||||
commit(types.RECEIVE_ITEMS_FOR_LIST_SUCCESS, { listIssues, listPageInfo, listId });
|
||||
commit(types.RECEIVE_ITEMS_FOR_LIST_SUCCESS, { listItems, listPageInfo, listId });
|
||||
})
|
||||
.catch(() => commit(types.RECEIVE_ITEMS_FOR_LIST_FAILURE, listId));
|
||||
},
|
||||
|
@ -304,8 +304,8 @@ export default {
|
|||
{ state, commit },
|
||||
{ issueId, issueIid, issuePath, fromListId, toListId, moveBeforeId, moveAfterId },
|
||||
) => {
|
||||
const originalIssue = state.issues[issueId];
|
||||
const fromList = state.issuesByListId[fromListId];
|
||||
const originalIssue = state.boardItems[issueId];
|
||||
const fromList = state.boardItemsByListId[fromListId];
|
||||
const originalIndex = fromList.indexOf(Number(issueId));
|
||||
commit(types.MOVE_ISSUE, { originalIssue, fromListId, toListId, moveBeforeId, moveAfterId });
|
||||
|
||||
|
|
|
@ -4,17 +4,17 @@ import { inactiveId } from '../constants';
|
|||
export default {
|
||||
isSidebarOpen: (state) => state.activeId !== inactiveId,
|
||||
isSwimlanesOn: () => false,
|
||||
getIssueById: (state) => (id) => {
|
||||
return state.issues[id] || {};
|
||||
getBoardItemById: (state) => (id) => {
|
||||
return state.boardItems[id] || {};
|
||||
},
|
||||
|
||||
getIssuesByList: (state, getters) => (listId) => {
|
||||
const listIssueIds = state.issuesByListId[listId] || [];
|
||||
return listIssueIds.map((id) => getters.getIssueById(id));
|
||||
getBoardItemsByList: (state, getters) => (listId) => {
|
||||
const listItemsIds = state.boardItemsByListId[listId] || [];
|
||||
return listItemsIds.map((id) => getters.getBoardItemById(id));
|
||||
},
|
||||
|
||||
activeIssue: (state) => {
|
||||
return state.issues[state.activeId] || {};
|
||||
return state.boardItems[state.activeId] || {};
|
||||
},
|
||||
|
||||
groupPathForActiveIssue: (_, getters) => {
|
||||
|
|
|
@ -11,13 +11,13 @@ const notImplemented = () => {
|
|||
};
|
||||
|
||||
export const removeIssueFromList = ({ state, listId, issueId }) => {
|
||||
Vue.set(state.issuesByListId, listId, pull(state.issuesByListId[listId], issueId));
|
||||
Vue.set(state.boardItemsByListId, listId, pull(state.boardItemsByListId[listId], issueId));
|
||||
const list = state.boardLists[listId];
|
||||
Vue.set(state.boardLists, listId, { ...list, issuesCount: list.issuesCount - 1 });
|
||||
};
|
||||
|
||||
export const addIssueToList = ({ state, listId, issueId, moveBeforeId, moveAfterId, atIndex }) => {
|
||||
const listIssues = state.issuesByListId[listId];
|
||||
const listIssues = state.boardItemsByListId[listId];
|
||||
let newIndex = atIndex || 0;
|
||||
if (moveBeforeId) {
|
||||
newIndex = listIssues.indexOf(moveBeforeId) + 1;
|
||||
|
@ -25,7 +25,7 @@ export const addIssueToList = ({ state, listId, issueId, moveBeforeId, moveAfter
|
|||
newIndex = listIssues.indexOf(moveAfterId);
|
||||
}
|
||||
listIssues.splice(newIndex, 0, issueId);
|
||||
Vue.set(state.issuesByListId, listId, listIssues);
|
||||
Vue.set(state.boardItemsByListId, listId, listIssues);
|
||||
const list = state.boardLists[listId];
|
||||
Vue.set(state.boardLists, listId, { ...list, issuesCount: list.issuesCount + 1 });
|
||||
};
|
||||
|
@ -108,14 +108,13 @@ export default {
|
|||
Vue.set(state.listsFlags, listId, { [fetchNext ? 'isLoadingMore' : 'isLoading']: true });
|
||||
},
|
||||
|
||||
[mutationTypes.RECEIVE_ITEMS_FOR_LIST_SUCCESS]: (state, { listIssues, listPageInfo, listId }) => {
|
||||
const { listData, issues } = listIssues;
|
||||
Vue.set(state, 'issues', { ...state.issues, ...issues });
|
||||
|
||||
[mutationTypes.RECEIVE_ITEMS_FOR_LIST_SUCCESS]: (state, { listItems, listPageInfo, listId }) => {
|
||||
const { listData, boardItems } = listItems;
|
||||
Vue.set(state, 'boardItems', { ...state.boardItems, ...boardItems });
|
||||
Vue.set(
|
||||
state.issuesByListId,
|
||||
state.boardItemsByListId,
|
||||
listId,
|
||||
union(state.issuesByListId[listId] || [], listData[listId]),
|
||||
union(state.boardItemsByListId[listId] || [], listData[listId]),
|
||||
);
|
||||
Vue.set(state.pageInfoByListId, listId, listPageInfo[listId]);
|
||||
Vue.set(state.listsFlags, listId, { isLoading: false, isLoadingMore: false });
|
||||
|
@ -129,18 +128,18 @@ export default {
|
|||
},
|
||||
|
||||
[mutationTypes.RESET_ISSUES]: (state) => {
|
||||
Object.keys(state.issuesByListId).forEach((listId) => {
|
||||
Vue.set(state.issuesByListId, listId, []);
|
||||
Object.keys(state.boardItemsByListId).forEach((listId) => {
|
||||
Vue.set(state.boardItemsByListId, listId, []);
|
||||
});
|
||||
},
|
||||
|
||||
[mutationTypes.UPDATE_ISSUE_BY_ID]: (state, { issueId, prop, value }) => {
|
||||
if (!state.issues[issueId]) {
|
||||
if (!state.boardItems[issueId]) {
|
||||
/* eslint-disable-next-line @gitlab/require-i18n-strings */
|
||||
throw new Error('No issue found.');
|
||||
}
|
||||
|
||||
Vue.set(state.issues[issueId], prop, value);
|
||||
Vue.set(state.boardItems[issueId], prop, value);
|
||||
},
|
||||
|
||||
[mutationTypes.SET_ASSIGNEE_LOADING](state, isLoading) {
|
||||
|
@ -167,7 +166,7 @@ export default {
|
|||
const toList = state.boardLists[toListId];
|
||||
|
||||
const issue = moveIssueListHelper(originalIssue, fromList, toList);
|
||||
Vue.set(state.issues, issue.id, issue);
|
||||
Vue.set(state.boardItems, issue.id, issue);
|
||||
|
||||
removeIssueFromList({ state, listId: fromListId, issueId: issue.id });
|
||||
addIssueToList({ state, listId: toListId, issueId: issue.id, moveBeforeId, moveAfterId });
|
||||
|
@ -175,7 +174,7 @@ export default {
|
|||
|
||||
[mutationTypes.MOVE_ISSUE_SUCCESS]: (state, { issue }) => {
|
||||
const issueId = getIdFromGraphQLId(issue.id);
|
||||
Vue.set(state.issues, issueId, formatIssue({ ...issue, id: issueId }));
|
||||
Vue.set(state.boardItems, issueId, formatIssue({ ...issue, id: issueId }));
|
||||
},
|
||||
|
||||
[mutationTypes.MOVE_ISSUE_FAILURE]: (
|
||||
|
@ -183,7 +182,7 @@ export default {
|
|||
{ originalIssue, fromListId, toListId, originalIndex },
|
||||
) => {
|
||||
state.error = s__('Boards|An error occurred while moving the issue. Please try again.');
|
||||
Vue.set(state.issues, originalIssue.id, originalIssue);
|
||||
Vue.set(state.boardItems, originalIssue.id, originalIssue);
|
||||
removeIssueFromList({ state, listId: toListId, issueId: originalIssue.id });
|
||||
addIssueToList({
|
||||
state,
|
||||
|
@ -216,7 +215,7 @@ export default {
|
|||
issueId: issue.id,
|
||||
atIndex: position,
|
||||
});
|
||||
Vue.set(state.issues, issue.id, issue);
|
||||
Vue.set(state.boardItems, issue.id, issue);
|
||||
},
|
||||
|
||||
[mutationTypes.ADD_ISSUE_TO_LIST_FAILURE]: (state, { list, issueId }) => {
|
||||
|
@ -226,7 +225,7 @@ export default {
|
|||
|
||||
[mutationTypes.REMOVE_ISSUE_FROM_LIST]: (state, { list, issue }) => {
|
||||
removeIssueFromList({ state, listId: list.id, issueId: issue.id });
|
||||
Vue.delete(state.issues, issue.id);
|
||||
Vue.delete(state.boardItems, issue.id);
|
||||
},
|
||||
|
||||
[mutationTypes.SET_CURRENT_PAGE]: () => {
|
||||
|
|
|
@ -9,10 +9,10 @@ export default () => ({
|
|||
sidebarType: '',
|
||||
boardLists: {},
|
||||
listsFlags: {},
|
||||
issuesByListId: {},
|
||||
boardItemsByListId: {},
|
||||
isSettingAssignees: false,
|
||||
pageInfoByListId: {},
|
||||
issues: {},
|
||||
boardItems: {},
|
||||
filterParams: {},
|
||||
boardConfig: {},
|
||||
labels: [],
|
||||
|
|
|
@ -443,7 +443,7 @@ $gl-avatar-size: 40px;
|
|||
$border-radius-default: 4px;
|
||||
$border-radius-small: 2px;
|
||||
$border-radius-large: 8px;
|
||||
$default-icon-size: 18px;
|
||||
$default-icon-size: 16px;
|
||||
$layout-link-gray: #7e7c7c;
|
||||
$btn-side-margin: 10px;
|
||||
$btn-sm-side-margin: 7px;
|
||||
|
|
|
@ -32,11 +32,6 @@
|
|||
@include media-breakpoint-down(md) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
img {
|
||||
width: $default-icon-size;
|
||||
height: $default-icon-size;
|
||||
}
|
||||
}
|
||||
|
||||
.decline-page {
|
||||
|
|
|
@ -106,17 +106,6 @@
|
|||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.omniauth-btn {
|
||||
width: 100%;
|
||||
padding: $gl-padding-8;
|
||||
|
||||
img {
|
||||
width: $default-icon-size;
|
||||
height: $default-icon-size;
|
||||
margin-right: $gl-padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.new-session-tabs {
|
||||
|
|
|
@ -2142,11 +2142,6 @@ table.code {
|
|||
width: 100%;
|
||||
padding: 8px;
|
||||
}
|
||||
.login-page .omniauth-container .omniauth-btn img {
|
||||
width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
margin-right: 16px;
|
||||
}
|
||||
.login-page .new-session-tabs {
|
||||
display: flex;
|
||||
box-shadow: 0 0 0 1px #dbdbdb;
|
||||
|
|
|
@ -13,7 +13,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
before_action :authorize_create_pipeline!, only: [:new, :create, :config_variables]
|
||||
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
|
||||
before_action do
|
||||
push_frontend_feature_flag(:pipelines_security_report_summary, project)
|
||||
push_frontend_feature_flag(:pipelines_security_report_summary, project, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:new_pipeline_form, project, default_enabled: true)
|
||||
push_frontend_feature_flag(:graphql_pipeline_details, project, type: :development, default_enabled: :yaml)
|
||||
push_frontend_feature_flag(:graphql_pipeline_details_users, current_user, type: :development, default_enabled: :yaml)
|
||||
|
|
|
@ -138,11 +138,11 @@ module AuthHelper
|
|||
label = label_for_provider(provider)
|
||||
|
||||
if provider_has_custom_icon?(provider)
|
||||
image_tag(icon_for_provider(provider), alt: label, title: "Sign in with #{label}")
|
||||
image_tag(icon_for_provider(provider), alt: label, title: "Sign in with #{label}", class: "gl-button-icon")
|
||||
elsif provider_has_builtin_icon?(provider)
|
||||
file_name = "#{provider.to_s.split('_').first}_#{size}.png"
|
||||
|
||||
image_tag("auth_buttons/#{file_name}", alt: label, title: "Sign in with #{label}")
|
||||
image_tag("auth_buttons/#{file_name}", alt: label, title: "Sign in with #{label}", class: "gl-button-icon")
|
||||
else
|
||||
label
|
||||
end
|
||||
|
|
|
@ -376,8 +376,7 @@ class MergeRequest < ApplicationRecord
|
|||
alias_attribute :auto_merge_enabled, :merge_when_pipeline_succeeds
|
||||
alias_method :issuing_parent, :target_project
|
||||
|
||||
delegate :active?, :builds_with_coverage, to: :head_pipeline, prefix: true, allow_nil: true
|
||||
delegate :success?, :active?, to: :actual_head_pipeline, prefix: true, allow_nil: true
|
||||
delegate :builds_with_coverage, to: :head_pipeline, prefix: true, allow_nil: true
|
||||
|
||||
RebaseLockTimeout = Class.new(StandardError)
|
||||
|
||||
|
@ -437,6 +436,18 @@ class MergeRequest < ApplicationRecord
|
|||
target_project.latest_pipeline(target_branch, sha)
|
||||
end
|
||||
|
||||
def head_pipeline_active?
|
||||
!!head_pipeline&.active?
|
||||
end
|
||||
|
||||
def actual_head_pipeline_active?
|
||||
!!actual_head_pipeline&.active?
|
||||
end
|
||||
|
||||
def actual_head_pipeline_success?
|
||||
!!actual_head_pipeline&.success?
|
||||
end
|
||||
|
||||
# Pattern used to extract `!123` merge request references from text
|
||||
#
|
||||
# This pattern supports cross-project references.
|
||||
|
|
|
@ -216,8 +216,10 @@ class Snippet < ApplicationRecord
|
|||
def blobs
|
||||
return [] unless repository_exists?
|
||||
|
||||
branch = default_branch
|
||||
list_files(branch).map { |file| Blob.lazy(repository, branch, file) }
|
||||
files = list_files(default_branch)
|
||||
items = files.map { |file| [default_branch, file] }
|
||||
|
||||
repository.blobs_at(items).compact
|
||||
end
|
||||
|
||||
def hook_attrs
|
||||
|
|
|
@ -115,10 +115,8 @@ class SnippetRepository < ApplicationRecord
|
|||
end
|
||||
|
||||
def invalid_path_error?(err)
|
||||
(err.is_a?(Gitlab::Git::Index::IndexError) &&
|
||||
err.message.downcase.start_with?('invalid path', 'path cannot include directory traversal')) ||
|
||||
(err.is_a?(Gitlab::Git::CommandError) &&
|
||||
err.message.include?('CreateFile: invalid path'))
|
||||
err.is_a?(Gitlab::Git::Index::IndexError) &&
|
||||
err.message.downcase.start_with?('invalid path', 'path cannot include directory traversal')
|
||||
end
|
||||
|
||||
def invalid_signature_error?(err)
|
||||
|
|
|
@ -20,4 +20,4 @@
|
|||
= recaptcha_tags
|
||||
|
||||
.submit-container.move-submit-down
|
||||
= f.submit _('Sign in'), class: 'gl-button btn btn-success', data: { qa_selector: 'sign_in_button' }
|
||||
= f.submit _('Sign in'), class: 'gl-button btn btn-confirm', data: { qa_selector: 'sign_in_button' }
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
.d-flex.justify-content-between.flex-wrap
|
||||
- providers.each do |provider|
|
||||
- has_icon = provider_has_icon?(provider)
|
||||
= button_to omniauth_authorize_path(:user, provider), id: "oauth-login-#{provider}", class: "btn gl-button btn-default d-flex align-items-center omniauth-btn text-left oauth-login #{qa_class_for_provider(provider)}" do
|
||||
= button_to omniauth_authorize_path(:user, provider), id: "oauth-login-#{provider}", class: "btn gl-button btn-default omniauth-btn oauth-login #{qa_class_for_provider(provider)}" do
|
||||
- if has_icon
|
||||
= provider_image_tag(provider)
|
||||
%span
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Update the Sign In button to use the new confirm button variant, migrate OAuth
|
||||
buttons to use the default variant of GlButton.
|
||||
merge_request: 53254
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix bug when snippet blobs array contain a nil value
|
||||
merge_request: 54552
|
||||
author:
|
||||
type: fixed
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
title: Fix snippet commit bug because of different Gitaly error
|
||||
merge_request: 54662
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'BulkImports: Import Label timestamps'
|
||||
merge_request: 54678
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Updates authorization for linting endpoint
|
||||
merge_request: 54492
|
||||
author:
|
||||
type: changed
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/235943
|
|||
milestone: '13.0'
|
||||
type: development
|
||||
group: group::dynamic analysis
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: marginalia
|
||||
introduced_by_url:
|
||||
rollout_issue_url:
|
||||
milestone:
|
||||
type: ops
|
||||
group:
|
||||
default_enabled: false
|
|
@ -4,11 +4,6 @@ require 'marginalia'
|
|||
|
||||
::Marginalia::Comment.extend(::Gitlab::Marginalia::Comment)
|
||||
|
||||
# Patch to modify 'Marginalia::ActiveRecordInstrumentation.annotate_sql' method with feature check.
|
||||
# Orignal Marginalia::ActiveRecordInstrumentation is included to ActiveRecord::ConnectionAdapters::PostgreSQLAdapter in the Marginalia Railtie.
|
||||
# Refer: https://github.com/basecamp/marginalia/blob/v1.8.0/lib/marginalia/railtie.rb#L67
|
||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.prepend(Gitlab::Marginalia::ActiveRecordInstrumentation)
|
||||
|
||||
# By default, PostgreSQL only tracks the first 1024 bytes of a SQL
|
||||
# query. Prepending the comment allows us to trace the source of the
|
||||
# query without having to increase the `track_activity_query_size`
|
||||
|
@ -25,5 +20,3 @@ Marginalia::Comment.components << :line if Rails.env.development?
|
|||
Gitlab::Marginalia.set_application_name
|
||||
|
||||
Gitlab::Marginalia.enable_sidekiq_instrumentation
|
||||
|
||||
Gitlab::Marginalia.set_enabled_from_feature_flag
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# end
|
||||
|
||||
if git.lines_of_code > 2_000
|
||||
warn "This merge request is definitely too big (more than #{git.lines_of_code} lines changed), please split it into multiple merge requests."
|
||||
warn "This merge request is definitely too big (#{git.lines_of_code} lines changed), please split it into multiple merge requests."
|
||||
elsif git.lines_of_code > 500
|
||||
warn "This merge request is quite big (more than #{git.lines_of_code} lines changed), please consider splitting it into multiple merge requests."
|
||||
warn "This merge request is quite big (#{git.lines_of_code} lines changed), please consider splitting it into multiple merge requests."
|
||||
end
|
||||
|
|
|
@ -161,6 +161,9 @@ To reveal existing RuboCop exceptions in the code that have been excluded via `.
|
|||
|
||||
This allows you to reveal existing RuboCop exceptions during your daily work cycle and fix them along the way.
|
||||
|
||||
NOTE:
|
||||
Permanent `Exclude`s should be defined in `.rubocop.yml` instead of `.rubocop_manual_todo.yml`.
|
||||
|
||||
## Database migrations
|
||||
|
||||
See the dedicated [Database Migrations Style Guide](../migration_style_guide.md).
|
||||
|
|
|
@ -47,16 +47,3 @@ Examples of queries with comments as observed in `development.log`:
|
|||
```sql
|
||||
/*application:sidekiq,jid:e7d6668a39a991e323009833,job_class:ExpireJobCacheWorker,correlation_id:rYF4mey9CH3,line:/app/workers/expire_job_cache_worker.rb:14:in `perform'*/ SELECT "ci_pipelines".* FROM "ci_pipelines" WHERE "ci_pipelines"."id" = $1 LIMIT $2 [["id", 64], ["LIMIT", 1]]
|
||||
```
|
||||
|
||||
## Enable/Disable the feature
|
||||
|
||||
Enabling or disabling the feature requires a **restart/SIGHUP** of the Web and
|
||||
Sidekiq workers, as the feature flag's state is memoized upon starting up.
|
||||
|
||||
The `feature_flag` for this feature is **disabled** by default. You can enable
|
||||
or disable it with:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:marginalia)
|
||||
Feature.disable(:marginalia)
|
||||
```
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 163 KiB |
|
@ -52,7 +52,7 @@ To use the security dashboards and vulnerability reports:
|
|||
At the pipeline level, the Security section displays the vulnerabilities present in the branch of
|
||||
the project the pipeline ran against.
|
||||
|
||||
![Pipeline Security Dashboard](img/pipeline_security_dashboard_v13_3.png)
|
||||
![Pipeline Security Dashboard](img/pipeline_security_dashboard_v13_10.png)
|
||||
|
||||
Visit the page for any pipeline that ran any of the [supported reports](#supported-reports). To view
|
||||
the pipeline's security findings, select the **Security** tab when viewing the pipeline.
|
||||
|
|
|
@ -24,7 +24,12 @@ The following resources are migrated to the target instance:
|
|||
- description
|
||||
- attributes
|
||||
- subgroups
|
||||
- Labels ([Introduced in 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/292429))
|
||||
- Group Labels ([Introduced in 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/292429))
|
||||
- title
|
||||
- description
|
||||
- color
|
||||
- created_at ([Introduced in 13.10](https://gitlab.com/gitlab-org/gitlab/-/issues/300007))
|
||||
- updated_at ([Introduced in 13.10](https://gitlab.com/gitlab-org/gitlab/-/issues/300007))
|
||||
- Members ([Introduced in 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/299415))
|
||||
Group members are associated with the imported group if:
|
||||
- The user already exists in the target GitLab instance and
|
||||
|
|
|
@ -11,7 +11,7 @@ module API
|
|||
optional :include_merged_yaml, type: Boolean, desc: 'Whether or not to include merged CI config yaml in the response'
|
||||
end
|
||||
post '/lint' do
|
||||
unauthorized! unless Gitlab::CurrentSettings.signup_enabled? && current_user
|
||||
unauthorized! if Gitlab::CurrentSettings.signup_disabled? && current_user.nil?
|
||||
|
||||
result = Gitlab::Ci::YamlProcessor.new(params[:content], user: current_user).execute
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ module BulkImports
|
|||
title
|
||||
description
|
||||
color
|
||||
created_at: createdAt
|
||||
updated_at: updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
module Gitlab
|
||||
module CurrentSettings
|
||||
class << self
|
||||
def signup_disabled?
|
||||
!signup_enabled?
|
||||
end
|
||||
|
||||
def current_application_settings
|
||||
Gitlab::SafeRequestStore.fetch(:current_application_settings) { ensure_application_settings! }
|
||||
end
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
module Gitlab
|
||||
module Marginalia
|
||||
cattr_accessor :enabled, default: false
|
||||
|
||||
def self.set_application_name
|
||||
::Marginalia.application_name = Gitlab.process_name
|
||||
end
|
||||
|
@ -13,12 +11,5 @@ module Gitlab
|
|||
::Marginalia::SidekiqInstrumentation.enable!
|
||||
end
|
||||
end
|
||||
|
||||
def self.set_enabled_from_feature_flag
|
||||
# During db:create and db:bootstrap skip feature query as DB is not available yet.
|
||||
return false unless Gitlab::Database.cached_table_exists?('features')
|
||||
|
||||
self.enabled = Feature.enabled?(:marginalia, type: :ops)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Patch to annotate sql only when the feature is enabled.
|
||||
module Gitlab
|
||||
module Marginalia
|
||||
module ActiveRecordInstrumentation
|
||||
def annotate_sql(sql)
|
||||
Gitlab::Marginalia.enabled ? super(sql) : sql
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4808,6 +4808,9 @@ msgstr ""
|
|||
msgid "Boards|An error occurred while fetching issues. Please reload the page."
|
||||
msgstr ""
|
||||
|
||||
msgid "Boards|An error occurred while fetching the board epics. Please reload the page."
|
||||
msgstr ""
|
||||
|
||||
msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
|
||||
msgstr ""
|
||||
|
||||
|
@ -17897,7 +17900,7 @@ msgstr ""
|
|||
msgid "Loading issues"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading more issues"
|
||||
msgid "Loading more"
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading snippet"
|
||||
|
|
|
@ -207,14 +207,14 @@ RSpec.describe Projects::SnippetsController do
|
|||
subject
|
||||
|
||||
expect(assigns(:snippet)).to eq(project_snippet)
|
||||
expect(assigns(:blobs)).to eq(project_snippet.blobs)
|
||||
expect(assigns(:blobs).map(&:name)).to eq(project_snippet.blobs.map(&:name))
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
|
||||
it 'does not show the blobs expanded by default' do
|
||||
subject
|
||||
|
||||
expect(project_snippet.blobs.map(&:expanded?)).to be_all(false)
|
||||
expect(assigns(:blobs).map(&:expanded?)).to be_all(false)
|
||||
end
|
||||
|
||||
context 'when param expanded is set' do
|
||||
|
@ -223,7 +223,7 @@ RSpec.describe Projects::SnippetsController do
|
|||
it 'shows all blobs expanded' do
|
||||
subject
|
||||
|
||||
expect(project_snippet.blobs.map(&:expanded?)).to be_all(true)
|
||||
expect(assigns(:blobs).map(&:expanded?)).to be_all(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,8 +29,8 @@ const createComponent = ({
|
|||
state = {},
|
||||
} = {}) => {
|
||||
const store = createStore({
|
||||
issuesByListId: mockIssuesByListId,
|
||||
issues,
|
||||
boardItemsByListId: mockIssuesByListId,
|
||||
boardItems: issues,
|
||||
pageInfoByListId: {
|
||||
'gid://gitlab/List/1': { hasNextPage: true },
|
||||
'gid://gitlab/List/2': {},
|
||||
|
@ -65,7 +65,7 @@ const createComponent = ({
|
|||
propsData: {
|
||||
disabled: false,
|
||||
list,
|
||||
issues: [issue],
|
||||
boardItems: [issue],
|
||||
canAdminList: true,
|
||||
...componentProps,
|
||||
},
|
||||
|
|
|
@ -24,7 +24,7 @@ describe('~/boards/components/sidebar/board_sidebar_due_date.vue', () => {
|
|||
|
||||
const createWrapper = ({ dueDate = null } = {}) => {
|
||||
store = createStore();
|
||||
store.state.issues = { [TEST_ISSUE.id]: { ...TEST_ISSUE, dueDate } };
|
||||
store.state.boardItems = { [TEST_ISSUE.id]: { ...TEST_ISSUE, dueDate } };
|
||||
store.state.activeId = TEST_ISSUE.id;
|
||||
|
||||
wrapper = shallowMount(BoardSidebarDueDate, {
|
||||
|
@ -61,7 +61,7 @@ describe('~/boards/components/sidebar/board_sidebar_due_date.vue', () => {
|
|||
createWrapper();
|
||||
|
||||
jest.spyOn(wrapper.vm, 'setActiveIssueDueDate').mockImplementation(() => {
|
||||
store.state.issues[TEST_ISSUE.id].dueDate = TEST_DUE_DATE;
|
||||
store.state.boardItems[TEST_ISSUE.id].dueDate = TEST_DUE_DATE;
|
||||
});
|
||||
findDatePicker().vm.$emit('input', TEST_PARSED_DATE);
|
||||
await wrapper.vm.$nextTick();
|
||||
|
@ -86,7 +86,7 @@ describe('~/boards/components/sidebar/board_sidebar_due_date.vue', () => {
|
|||
createWrapper();
|
||||
|
||||
jest.spyOn(wrapper.vm, 'setActiveIssueDueDate').mockImplementation(() => {
|
||||
store.state.issues[TEST_ISSUE.id].dueDate = null;
|
||||
store.state.boardItems[TEST_ISSUE.id].dueDate = null;
|
||||
});
|
||||
findDatePicker().vm.$emit('clear');
|
||||
await wrapper.vm.$nextTick();
|
||||
|
@ -104,7 +104,7 @@ describe('~/boards/components/sidebar/board_sidebar_due_date.vue', () => {
|
|||
createWrapper({ dueDate: TEST_DUE_DATE });
|
||||
|
||||
jest.spyOn(wrapper.vm, 'setActiveIssueDueDate').mockImplementation(() => {
|
||||
store.state.issues[TEST_ISSUE.id].dueDate = null;
|
||||
store.state.boardItems[TEST_ISSUE.id].dueDate = null;
|
||||
});
|
||||
findResetButton().vm.$emit('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
|
|
|
@ -34,7 +34,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
|
|||
|
||||
const createWrapper = (issue = TEST_ISSUE_A) => {
|
||||
store = createStore();
|
||||
store.state.issues = { [issue.id]: { ...issue } };
|
||||
store.state.boardItems = { [issue.id]: { ...issue } };
|
||||
store.dispatch('setActiveId', { id: issue.id });
|
||||
|
||||
wrapper = shallowMount(BoardSidebarIssueTitle, {
|
||||
|
@ -74,7 +74,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
|
|||
createWrapper();
|
||||
|
||||
jest.spyOn(wrapper.vm, 'setActiveIssueTitle').mockImplementation(() => {
|
||||
store.state.issues[TEST_ISSUE_A.id].title = TEST_TITLE;
|
||||
store.state.boardItems[TEST_ISSUE_A.id].title = TEST_TITLE;
|
||||
});
|
||||
findFormInput().vm.$emit('input', TEST_TITLE);
|
||||
findForm().vm.$emit('submit', { preventDefault: () => {} });
|
||||
|
@ -147,7 +147,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
|
|||
createWrapper(TEST_ISSUE_B);
|
||||
|
||||
jest.spyOn(wrapper.vm, 'setActiveIssueTitle').mockImplementation(() => {
|
||||
store.state.issues[TEST_ISSUE_B.id].title = TEST_TITLE;
|
||||
store.state.boardItems[TEST_ISSUE_B.id].title = TEST_TITLE;
|
||||
});
|
||||
findFormInput().vm.$emit('input', TEST_TITLE);
|
||||
findCancelButton().vm.$emit('click');
|
||||
|
|
|
@ -25,7 +25,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
|
|||
|
||||
const createWrapper = ({ labels = [] } = {}) => {
|
||||
store = createStore();
|
||||
store.state.issues = { [TEST_ISSUE.id]: { ...TEST_ISSUE, labels } };
|
||||
store.state.boardItems = { [TEST_ISSUE.id]: { ...TEST_ISSUE, labels } };
|
||||
store.state.activeId = TEST_ISSUE.id;
|
||||
|
||||
wrapper = shallowMount(BoardSidebarLabelsSelect, {
|
||||
|
@ -66,7 +66,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
|
|||
|
||||
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => TEST_LABELS);
|
||||
findLabelsSelect().vm.$emit('updateSelectedLabels', TEST_LABELS_PAYLOAD);
|
||||
store.state.issues[TEST_ISSUE.id].labels = TEST_LABELS;
|
||||
store.state.boardItems[TEST_ISSUE.id].labels = TEST_LABELS;
|
||||
await wrapper.vm.$nextTick();
|
||||
});
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ describe('~/boards/components/sidebar/board_sidebar_milestone_select.vue', () =>
|
|||
|
||||
const createWrapper = ({ milestone = null, loading = false } = {}) => {
|
||||
store = createStore();
|
||||
store.state.issues = { [TEST_ISSUE.id]: { ...TEST_ISSUE, milestone } };
|
||||
store.state.boardItems = { [TEST_ISSUE.id]: { ...TEST_ISSUE, milestone } };
|
||||
store.state.activeId = TEST_ISSUE.id;
|
||||
|
||||
wrapper = shallowMount(BoardSidebarMilestoneSelect, {
|
||||
|
@ -113,7 +113,7 @@ describe('~/boards/components/sidebar/board_sidebar_milestone_select.vue', () =>
|
|||
createWrapper();
|
||||
|
||||
jest.spyOn(wrapper.vm, 'setActiveIssueMilestone').mockImplementation(() => {
|
||||
store.state.issues[TEST_ISSUE.id].milestone = TEST_MILESTONE;
|
||||
store.state.boardItems[TEST_ISSUE.id].milestone = TEST_MILESTONE;
|
||||
});
|
||||
findDropdownItem().vm.$emit('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
|
@ -137,7 +137,7 @@ describe('~/boards/components/sidebar/board_sidebar_milestone_select.vue', () =>
|
|||
createWrapper({ milestone: TEST_MILESTONE });
|
||||
|
||||
jest.spyOn(wrapper.vm, 'setActiveIssueMilestone').mockImplementation(() => {
|
||||
store.state.issues[TEST_ISSUE.id].milestone = null;
|
||||
store.state.boardItems[TEST_ISSUE.id].milestone = null;
|
||||
});
|
||||
findUnsetMilestoneItem().vm.$emit('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
|
|
|
@ -22,7 +22,7 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
|
|||
|
||||
const createComponent = (activeIssue = { ...mockActiveIssue }) => {
|
||||
store = createStore();
|
||||
store.state.issues = { [activeIssue.id]: activeIssue };
|
||||
store.state.boardItems = { [activeIssue.id]: activeIssue };
|
||||
store.state.activeId = activeIssue.id;
|
||||
|
||||
wrapper = mount(BoardSidebarSubscription, {
|
||||
|
|
|
@ -573,7 +573,7 @@ describe('fetchItemsForList', () => {
|
|||
},
|
||||
{
|
||||
type: types.RECEIVE_ITEMS_FOR_LIST_SUCCESS,
|
||||
payload: { listIssues: formattedIssues, listPageInfo, listId },
|
||||
payload: { listItems: formattedIssues, listPageInfo, listId },
|
||||
},
|
||||
],
|
||||
[],
|
||||
|
@ -624,8 +624,8 @@ describe('moveIssue', () => {
|
|||
boardType: 'group',
|
||||
disabled: false,
|
||||
boardLists: mockLists,
|
||||
issuesByListId: listIssues,
|
||||
issues,
|
||||
boardItemsByListId: listIssues,
|
||||
boardItems: issues,
|
||||
};
|
||||
|
||||
it('should commit MOVE_ISSUE mutation and MOVE_ISSUE_SUCCESS mutation when successful', (done) => {
|
||||
|
@ -905,7 +905,7 @@ describe('addListIssue', () => {
|
|||
});
|
||||
|
||||
describe('setActiveIssueLabels', () => {
|
||||
const state = { issues: { [mockIssue.id]: mockIssue } };
|
||||
const state = { boardItems: { [mockIssue.id]: mockIssue } };
|
||||
const getters = { activeIssue: mockIssue };
|
||||
const testLabelIds = labels.map((label) => label.id);
|
||||
const input = {
|
||||
|
@ -950,7 +950,7 @@ describe('setActiveIssueLabels', () => {
|
|||
});
|
||||
|
||||
describe('setActiveIssueDueDate', () => {
|
||||
const state = { issues: { [mockIssue.id]: mockIssue } };
|
||||
const state = { boardItems: { [mockIssue.id]: mockIssue } };
|
||||
const getters = { activeIssue: mockIssue };
|
||||
const testDueDate = '2020-02-20';
|
||||
const input = {
|
||||
|
@ -1001,7 +1001,7 @@ describe('setActiveIssueDueDate', () => {
|
|||
});
|
||||
|
||||
describe('setActiveIssueSubscribed', () => {
|
||||
const state = { issues: { [mockActiveIssue.id]: mockActiveIssue } };
|
||||
const state = { boardItems: { [mockActiveIssue.id]: mockActiveIssue } };
|
||||
const getters = { activeIssue: mockActiveIssue };
|
||||
const subscribedState = true;
|
||||
const input = {
|
||||
|
@ -1052,7 +1052,7 @@ describe('setActiveIssueSubscribed', () => {
|
|||
});
|
||||
|
||||
describe('setActiveIssueMilestone', () => {
|
||||
const state = { issues: { [mockIssue.id]: mockIssue } };
|
||||
const state = { boardItems: { [mockIssue.id]: mockIssue } };
|
||||
const getters = { activeIssue: mockIssue };
|
||||
const testMilestone = {
|
||||
...mockMilestone,
|
||||
|
@ -1106,7 +1106,7 @@ describe('setActiveIssueMilestone', () => {
|
|||
});
|
||||
|
||||
describe('setActiveIssueTitle', () => {
|
||||
const state = { issues: { [mockIssue.id]: mockIssue } };
|
||||
const state = { boardItems: { [mockIssue.id]: mockIssue } };
|
||||
const getters = { activeIssue: mockIssue };
|
||||
const testTitle = 'Test Title';
|
||||
const input = {
|
||||
|
|
|
@ -38,15 +38,15 @@ describe('Boards - Getters', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getIssueById', () => {
|
||||
const state = { issues: { 1: 'issue' } };
|
||||
describe('getBoardItemById', () => {
|
||||
const state = { boardItems: { 1: 'issue' } };
|
||||
|
||||
it.each`
|
||||
id | expected
|
||||
${'1'} | ${'issue'}
|
||||
${''} | ${{}}
|
||||
`('returns $expected when $id is passed to state', ({ id, expected }) => {
|
||||
expect(getters.getIssueById(state)(id)).toEqual(expected);
|
||||
expect(getters.getBoardItemById(state)(id)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -56,7 +56,7 @@ describe('Boards - Getters', () => {
|
|||
${'1'} | ${'issue'}
|
||||
${''} | ${{}}
|
||||
`('returns $expected when $id is passed to state', ({ id, expected }) => {
|
||||
const state = { issues: { 1: 'issue' }, activeId: id };
|
||||
const state = { boardItems: { 1: 'issue' }, activeId: id };
|
||||
|
||||
expect(getters.activeIssue(state)).toEqual(expected);
|
||||
});
|
||||
|
@ -94,17 +94,18 @@ describe('Boards - Getters', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getIssuesByList', () => {
|
||||
describe('getBoardItemsByList', () => {
|
||||
const boardsState = {
|
||||
issuesByListId: mockIssuesByListId,
|
||||
issues,
|
||||
boardItemsByListId: mockIssuesByListId,
|
||||
boardItems: issues,
|
||||
};
|
||||
it('returns issues for a given listId', () => {
|
||||
const getIssueById = (issueId) => [mockIssue, mockIssue2].find(({ id }) => id === issueId);
|
||||
const getBoardItemById = (issueId) =>
|
||||
[mockIssue, mockIssue2].find(({ id }) => id === issueId);
|
||||
|
||||
expect(getters.getIssuesByList(boardsState, { getIssueById })('gid://gitlab/List/2')).toEqual(
|
||||
mockIssues,
|
||||
);
|
||||
expect(
|
||||
getters.getBoardItemsByList(boardsState, { getBoardItemById })('gid://gitlab/List/2'),
|
||||
).toEqual(mockIssues);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -222,24 +222,24 @@ describe('Board Store Mutations', () => {
|
|||
});
|
||||
|
||||
describe('RESET_ISSUES', () => {
|
||||
it('should remove issues from issuesByListId state', () => {
|
||||
const issuesByListId = {
|
||||
it('should remove issues from boardItemsByListId state', () => {
|
||||
const boardItemsByListId = {
|
||||
'gid://gitlab/List/1': [mockIssue.id],
|
||||
};
|
||||
|
||||
state = {
|
||||
...state,
|
||||
issuesByListId,
|
||||
boardItemsByListId,
|
||||
};
|
||||
|
||||
mutations[types.RESET_ISSUES](state);
|
||||
|
||||
expect(state.issuesByListId).toEqual({ 'gid://gitlab/List/1': [] });
|
||||
expect(state.boardItemsByListId).toEqual({ 'gid://gitlab/List/1': [] });
|
||||
});
|
||||
});
|
||||
|
||||
describe('RECEIVE_ITEMS_FOR_LIST_SUCCESS', () => {
|
||||
it('updates issuesByListId and issues on state', () => {
|
||||
it('updates boardItemsByListId and issues on state', () => {
|
||||
const listIssues = {
|
||||
'gid://gitlab/List/1': [mockIssue.id],
|
||||
};
|
||||
|
@ -249,10 +249,10 @@ describe('Board Store Mutations', () => {
|
|||
|
||||
state = {
|
||||
...state,
|
||||
issuesByListId: {
|
||||
boardItemsByListId: {
|
||||
'gid://gitlab/List/1': [],
|
||||
},
|
||||
issues: {},
|
||||
boardItems: {},
|
||||
boardLists: initialBoardListsState,
|
||||
};
|
||||
|
||||
|
@ -264,13 +264,13 @@ describe('Board Store Mutations', () => {
|
|||
};
|
||||
|
||||
mutations.RECEIVE_ITEMS_FOR_LIST_SUCCESS(state, {
|
||||
listIssues: { listData: listIssues, issues },
|
||||
listItems: { listData: listIssues, boardItems: issues },
|
||||
listPageInfo,
|
||||
listId: 'gid://gitlab/List/1',
|
||||
});
|
||||
|
||||
expect(state.issuesByListId).toEqual(listIssues);
|
||||
expect(state.issues).toEqual(issues);
|
||||
expect(state.boardItemsByListId).toEqual(listIssues);
|
||||
expect(state.boardItems).toEqual(issues);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -306,7 +306,7 @@ describe('Board Store Mutations', () => {
|
|||
state = {
|
||||
...state,
|
||||
error: undefined,
|
||||
issues: {
|
||||
boardItems: {
|
||||
...issue,
|
||||
},
|
||||
};
|
||||
|
@ -320,7 +320,7 @@ describe('Board Store Mutations', () => {
|
|||
value,
|
||||
});
|
||||
|
||||
expect(state.issues[issueId]).toEqual({ ...issue[issueId], id: '2' });
|
||||
expect(state.boardItems[issueId]).toEqual({ ...issue[issueId], id: '2' });
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -346,7 +346,7 @@ describe('Board Store Mutations', () => {
|
|||
});
|
||||
|
||||
describe('MOVE_ISSUE', () => {
|
||||
it('updates issuesByListId, moving issue between lists', () => {
|
||||
it('updates boardItemsByListId, moving issue between lists', () => {
|
||||
const listIssues = {
|
||||
'gid://gitlab/List/1': [mockIssue.id, mockIssue2.id],
|
||||
'gid://gitlab/List/2': [],
|
||||
|
@ -359,9 +359,9 @@ describe('Board Store Mutations', () => {
|
|||
|
||||
state = {
|
||||
...state,
|
||||
issuesByListId: listIssues,
|
||||
boardItemsByListId: listIssues,
|
||||
boardLists: initialBoardListsState,
|
||||
issues,
|
||||
boardItems: issues,
|
||||
};
|
||||
|
||||
mutations.MOVE_ISSUE(state, {
|
||||
|
@ -375,7 +375,7 @@ describe('Board Store Mutations', () => {
|
|||
'gid://gitlab/List/2': [mockIssue2.id],
|
||||
};
|
||||
|
||||
expect(state.issuesByListId).toEqual(updatedListIssues);
|
||||
expect(state.boardItemsByListId).toEqual(updatedListIssues);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -387,19 +387,19 @@ describe('Board Store Mutations', () => {
|
|||
|
||||
state = {
|
||||
...state,
|
||||
issues,
|
||||
boardItems: issues,
|
||||
};
|
||||
|
||||
mutations.MOVE_ISSUE_SUCCESS(state, {
|
||||
issue: rawIssue,
|
||||
});
|
||||
|
||||
expect(state.issues).toEqual({ 436: { ...mockIssue, id: 436 } });
|
||||
expect(state.boardItems).toEqual({ 436: { ...mockIssue, id: 436 } });
|
||||
});
|
||||
});
|
||||
|
||||
describe('MOVE_ISSUE_FAILURE', () => {
|
||||
it('updates issuesByListId, reverting moving issue between lists, and sets error message', () => {
|
||||
it('updates boardItemsByListId, reverting moving issue between lists, and sets error message', () => {
|
||||
const listIssues = {
|
||||
'gid://gitlab/List/1': [mockIssue.id],
|
||||
'gid://gitlab/List/2': [mockIssue2.id],
|
||||
|
@ -407,7 +407,7 @@ describe('Board Store Mutations', () => {
|
|||
|
||||
state = {
|
||||
...state,
|
||||
issuesByListId: listIssues,
|
||||
boardItemsByListId: listIssues,
|
||||
boardLists: initialBoardListsState,
|
||||
};
|
||||
|
||||
|
@ -423,7 +423,7 @@ describe('Board Store Mutations', () => {
|
|||
'gid://gitlab/List/2': [],
|
||||
};
|
||||
|
||||
expect(state.issuesByListId).toEqual(updatedListIssues);
|
||||
expect(state.boardItemsByListId).toEqual(updatedListIssues);
|
||||
expect(state.error).toEqual('An error occurred while moving the issue. Please try again.');
|
||||
});
|
||||
});
|
||||
|
@ -449,7 +449,7 @@ describe('Board Store Mutations', () => {
|
|||
});
|
||||
|
||||
describe('ADD_ISSUE_TO_LIST', () => {
|
||||
it('adds issue to issues state and issue id in list in issuesByListId', () => {
|
||||
it('adds issue to issues state and issue id in list in boardItemsByListId', () => {
|
||||
const listIssues = {
|
||||
'gid://gitlab/List/1': [mockIssue.id],
|
||||
};
|
||||
|
@ -459,8 +459,8 @@ describe('Board Store Mutations', () => {
|
|||
|
||||
state = {
|
||||
...state,
|
||||
issuesByListId: listIssues,
|
||||
issues,
|
||||
boardItemsByListId: listIssues,
|
||||
boardItems: issues,
|
||||
boardLists: initialBoardListsState,
|
||||
};
|
||||
|
||||
|
@ -468,14 +468,14 @@ describe('Board Store Mutations', () => {
|
|||
|
||||
mutations.ADD_ISSUE_TO_LIST(state, { list: mockLists[0], issue: mockIssue2 });
|
||||
|
||||
expect(state.issuesByListId['gid://gitlab/List/1']).toContain(mockIssue2.id);
|
||||
expect(state.issues[mockIssue2.id]).toEqual(mockIssue2);
|
||||
expect(state.boardItemsByListId['gid://gitlab/List/1']).toContain(mockIssue2.id);
|
||||
expect(state.boardItems[mockIssue2.id]).toEqual(mockIssue2);
|
||||
expect(state.boardLists['gid://gitlab/List/1'].issuesCount).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ADD_ISSUE_TO_LIST_FAILURE', () => {
|
||||
it('removes issue id from list in issuesByListId and sets error message', () => {
|
||||
it('removes issue id from list in boardItemsByListId and sets error message', () => {
|
||||
const listIssues = {
|
||||
'gid://gitlab/List/1': [mockIssue.id, mockIssue2.id],
|
||||
};
|
||||
|
@ -486,20 +486,20 @@ describe('Board Store Mutations', () => {
|
|||
|
||||
state = {
|
||||
...state,
|
||||
issuesByListId: listIssues,
|
||||
issues,
|
||||
boardItemsByListId: listIssues,
|
||||
boardItems: issues,
|
||||
boardLists: initialBoardListsState,
|
||||
};
|
||||
|
||||
mutations.ADD_ISSUE_TO_LIST_FAILURE(state, { list: mockLists[0], issueId: mockIssue2.id });
|
||||
|
||||
expect(state.issuesByListId['gid://gitlab/List/1']).not.toContain(mockIssue2.id);
|
||||
expect(state.boardItemsByListId['gid://gitlab/List/1']).not.toContain(mockIssue2.id);
|
||||
expect(state.error).toBe('An error occurred while creating the issue. Please try again.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('REMOVE_ISSUE_FROM_LIST', () => {
|
||||
it('removes issue id from list in issuesByListId and deletes issue from state', () => {
|
||||
it('removes issue id from list in boardItemsByListId and deletes issue from state', () => {
|
||||
const listIssues = {
|
||||
'gid://gitlab/List/1': [mockIssue.id, mockIssue2.id],
|
||||
};
|
||||
|
@ -510,15 +510,15 @@ describe('Board Store Mutations', () => {
|
|||
|
||||
state = {
|
||||
...state,
|
||||
issuesByListId: listIssues,
|
||||
issues,
|
||||
boardItemsByListId: listIssues,
|
||||
boardItems: issues,
|
||||
boardLists: initialBoardListsState,
|
||||
};
|
||||
|
||||
mutations.ADD_ISSUE_TO_LIST_FAILURE(state, { list: mockLists[0], issueId: mockIssue2.id });
|
||||
|
||||
expect(state.issuesByListId['gid://gitlab/List/1']).not.toContain(mockIssue2.id);
|
||||
expect(state.issues).not.toContain(mockIssue2);
|
||||
expect(state.boardItemsByListId['gid://gitlab/List/1']).not.toContain(mockIssue2.id);
|
||||
expect(state.boardItems).not.toContain(mockIssue2);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -5,16 +5,22 @@ require 'spec_helper'
|
|||
RSpec.describe Projects::PipelinesController, '(JavaScript fixtures)', type: :controller do
|
||||
include JavaScriptFixturesHelpers
|
||||
|
||||
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
|
||||
let(:project) { create(:project, :repository, namespace: namespace, path: 'pipelines-project') }
|
||||
let(:commit) { create(:commit, project: project) }
|
||||
let(:commit_without_author) { RepoHelpers.another_sample_commit }
|
||||
let!(:user) { create(:user, developer_projects: [project], email: commit.author_email) }
|
||||
let!(:pipeline) { create(:ci_pipeline, project: project, sha: commit.id, user: user) }
|
||||
let!(:pipeline_without_author) { create(:ci_pipeline, project: project, sha: commit_without_author.id) }
|
||||
let!(:pipeline_without_commit) { create(:ci_pipeline, status: :success, project: project, sha: '0000') }
|
||||
let_it_be(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
|
||||
let_it_be(:project) { create(:project, :repository, namespace: namespace, path: 'pipelines-project') }
|
||||
|
||||
render_views
|
||||
let_it_be(:commit_without_author) { RepoHelpers.another_sample_commit }
|
||||
let!(:pipeline_without_author) { create(:ci_pipeline, project: project, sha: commit_without_author.id) }
|
||||
let!(:build_pipeline_without_author) { create(:ci_build, pipeline: pipeline_without_author, stage: 'test') }
|
||||
|
||||
let_it_be(:pipeline_without_commit) { create(:ci_pipeline, status: :success, project: project, sha: '0000') }
|
||||
let!(:build_pipeline_without_commit) { create(:ci_build, pipeline: pipeline_without_commit, stage: 'test') }
|
||||
|
||||
let(:commit) { create(:commit, project: project) }
|
||||
let(:user) { create(:user, developer_projects: [project], email: commit.author_email) }
|
||||
let!(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project, sha: commit.id, user: user) }
|
||||
let!(:build_success) { create(:ci_build, pipeline: pipeline, stage: 'build') }
|
||||
let!(:build_test) { create(:ci_build, pipeline: pipeline, stage: 'test') }
|
||||
let!(:build_deploy_failed) { create(:ci_build, status: :failed, pipeline: pipeline, stage: 'deploy') }
|
||||
|
||||
before(:all) do
|
||||
clean_frontend_fixtures('pipelines/')
|
||||
|
@ -32,4 +38,14 @@ RSpec.describe Projects::PipelinesController, '(JavaScript fixtures)', type: :co
|
|||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it "pipelines/test_report.json" do
|
||||
get :test_report, params: {
|
||||
namespace_id: namespace,
|
||||
project_id: project,
|
||||
id: pipeline.id
|
||||
}, format: :json
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Projects::PipelinesController, "(JavaScript fixtures)", type: :controller do
|
||||
include JavaScriptFixturesHelpers
|
||||
|
||||
let(:namespace) { create(:namespace, name: "frontend-fixtures") }
|
||||
let(:project) { create(:project, :repository, namespace: namespace, path: "pipelines-project") }
|
||||
let(:commit) { create(:commit, project: project) }
|
||||
let(:user) { create(:user, developer_projects: [project], email: commit.author_email) }
|
||||
let(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project, user: user) }
|
||||
|
||||
render_views
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
it "pipelines/test_report.json" do
|
||||
get :test_report, params: {
|
||||
namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
id: pipeline.id
|
||||
}, format: :json
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
|
@ -2,328 +2,6 @@ const PIPELINE_RUNNING = 'RUNNING';
|
|||
const PIPELINE_CANCELED = 'CANCELED';
|
||||
const PIPELINE_FAILED = 'FAILED';
|
||||
|
||||
export const pipelineWithStages = {
|
||||
id: 20333396,
|
||||
user: {
|
||||
id: 128633,
|
||||
name: 'Rémy Coutable',
|
||||
username: 'rymai',
|
||||
state: 'active',
|
||||
avatar_url:
|
||||
'https://secure.gravatar.com/avatar/263da227929cc0035cb0eba512bcf81a?s=80\u0026d=identicon',
|
||||
web_url: 'https://gitlab.com/rymai',
|
||||
path: '/rymai',
|
||||
},
|
||||
active: true,
|
||||
coverage: '58.24',
|
||||
source: 'push',
|
||||
created_at: '2018-04-11T14:04:53.881Z',
|
||||
updated_at: '2018-04-11T14:05:00.792Z',
|
||||
path: '/gitlab-org/gitlab/pipelines/20333396',
|
||||
flags: {
|
||||
latest: true,
|
||||
stuck: false,
|
||||
auto_devops: false,
|
||||
yaml_errors: false,
|
||||
retryable: false,
|
||||
cancelable: true,
|
||||
failure_reason: false,
|
||||
},
|
||||
details: {
|
||||
status: {
|
||||
icon: 'status_running',
|
||||
text: 'running',
|
||||
label: 'running',
|
||||
group: 'running',
|
||||
has_details: true,
|
||||
details_path: '/gitlab-org/gitlab/pipelines/20333396',
|
||||
favicon:
|
||||
'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_running-2eb56be2871937954b2ba6d6f4ee9fdf7e5e1c146ac45f7be98119ccaca1aca9.ico',
|
||||
},
|
||||
duration: null,
|
||||
finished_at: null,
|
||||
stages: [
|
||||
{
|
||||
name: 'build',
|
||||
title: 'build: skipped',
|
||||
status: {
|
||||
icon: 'status_skipped',
|
||||
text: 'skipped',
|
||||
label: 'skipped',
|
||||
group: 'skipped',
|
||||
has_details: true,
|
||||
details_path: '/gitlab-org/gitlab/pipelines/20333396#build',
|
||||
favicon:
|
||||
'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_skipped-a2eee568a5bffdb494050c7b62dde241de9189280836288ac8923d369f16222d.ico',
|
||||
},
|
||||
path: '/gitlab-org/gitlab/pipelines/20333396#build',
|
||||
dropdown_path: '/gitlab-org/gitlab/pipelines/20333396/stage.json?stage=build',
|
||||
},
|
||||
{
|
||||
name: 'prepare',
|
||||
title: 'prepare: passed',
|
||||
status: {
|
||||
icon: 'status_success',
|
||||
text: 'passed',
|
||||
label: 'passed',
|
||||
group: 'success',
|
||||
has_details: true,
|
||||
details_path: '/gitlab-org/gitlab/pipelines/20333396#prepare',
|
||||
favicon:
|
||||
'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_success-26f59841becbef8c6fe414e9e74471d8bfd6a91b5855c19fe7f5923a40a7da47.ico',
|
||||
},
|
||||
path: '/gitlab-org/gitlab/pipelines/20333396#prepare',
|
||||
dropdown_path: '/gitlab-org/gitlab/pipelines/20333396/stage.json?stage=prepare',
|
||||
},
|
||||
{
|
||||
name: 'test',
|
||||
title: 'test: running',
|
||||
status: {
|
||||
icon: 'status_running',
|
||||
text: 'running',
|
||||
label: 'running',
|
||||
group: 'running',
|
||||
has_details: true,
|
||||
details_path: '/gitlab-org/gitlab/pipelines/20333396#test',
|
||||
favicon:
|
||||
'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_running-2eb56be2871937954b2ba6d6f4ee9fdf7e5e1c146ac45f7be98119ccaca1aca9.ico',
|
||||
},
|
||||
path: '/gitlab-org/gitlab/pipelines/20333396#test',
|
||||
dropdown_path: '/gitlab-org/gitlab/pipelines/20333396/stage.json?stage=test',
|
||||
},
|
||||
{
|
||||
name: 'post-test',
|
||||
title: 'post-test: created',
|
||||
status: {
|
||||
icon: 'status_created',
|
||||
text: 'created',
|
||||
label: 'created',
|
||||
group: 'created',
|
||||
has_details: true,
|
||||
details_path: '/gitlab-org/gitlab/pipelines/20333396#post-test',
|
||||
favicon:
|
||||
'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_created-e997aa0b7db73165df8a9d6803932b18d7b7cc37d604d2d96e378fea2dba9c5f.ico',
|
||||
},
|
||||
path: '/gitlab-org/gitlab/pipelines/20333396#post-test',
|
||||
dropdown_path: '/gitlab-org/gitlab/pipelines/20333396/stage.json?stage=post-test',
|
||||
},
|
||||
{
|
||||
name: 'pages',
|
||||
title: 'pages: created',
|
||||
status: {
|
||||
icon: 'status_created',
|
||||
text: 'created',
|
||||
label: 'created',
|
||||
group: 'created',
|
||||
has_details: true,
|
||||
details_path: '/gitlab-org/gitlab/pipelines/20333396#pages',
|
||||
favicon:
|
||||
'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_created-e997aa0b7db73165df8a9d6803932b18d7b7cc37d604d2d96e378fea2dba9c5f.ico',
|
||||
},
|
||||
path: '/gitlab-org/gitlab/pipelines/20333396#pages',
|
||||
dropdown_path: '/gitlab-org/gitlab/pipelines/20333396/stage.json?stage=pages',
|
||||
},
|
||||
{
|
||||
name: 'post-cleanup',
|
||||
title: 'post-cleanup: created',
|
||||
status: {
|
||||
icon: 'status_created',
|
||||
text: 'created',
|
||||
label: 'created',
|
||||
group: 'created',
|
||||
has_details: true,
|
||||
details_path: '/gitlab-org/gitlab/pipelines/20333396#post-cleanup',
|
||||
favicon:
|
||||
'https://assets.gitlab-static.net/assets/ci_favicons/favicon_status_created-e997aa0b7db73165df8a9d6803932b18d7b7cc37d604d2d96e378fea2dba9c5f.ico',
|
||||
},
|
||||
path: '/gitlab-org/gitlab/pipelines/20333396#post-cleanup',
|
||||
dropdown_path: '/gitlab-org/gitlab/pipelines/20333396/stage.json?stage=post-cleanup',
|
||||
},
|
||||
],
|
||||
artifacts: [
|
||||
{
|
||||
name: 'gitlab:assets:compile',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:22:54.730Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411438/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411438/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411438/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'rspec-mysql 12 28',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:22:45.136Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411397/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411397/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411397/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'rspec-mysql 6 28',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:22:41.523Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411391/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411391/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411391/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'rspec-pg geo 0 1',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:22:13.287Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411353/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411353/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411353/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'rspec-mysql 0 28',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:22:06.834Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411385/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411385/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411385/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'spinach-mysql 0 2',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:21:51.409Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411423/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411423/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411423/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'karma',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:21:20.934Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411440/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411440/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411440/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'spinach-pg 0 2',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:20:01.028Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411419/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411419/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411419/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'spinach-pg 1 2',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:19:04.336Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411421/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411421/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411421/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'sast',
|
||||
expired: null,
|
||||
expire_at: null,
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411442/artifacts/download',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411442/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'code_quality',
|
||||
expired: false,
|
||||
expire_at: '2018-04-18T14:16:24.484Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411441/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411441/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411441/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'cache gems',
|
||||
expired: null,
|
||||
expire_at: null,
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411447/artifacts/download',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411447/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'dependency_scanning',
|
||||
expired: null,
|
||||
expire_at: null,
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411443/artifacts/download',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411443/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'compile-assets',
|
||||
expired: false,
|
||||
expire_at: '2018-04-18T14:12:07.638Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411334/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411334/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411334/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'setup-test-env',
|
||||
expired: false,
|
||||
expire_at: '2018-04-18T14:10:27.024Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411336/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411336/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411336/artifacts/browse',
|
||||
},
|
||||
{
|
||||
name: 'retrieve-tests-metadata',
|
||||
expired: false,
|
||||
expire_at: '2018-05-12T14:06:35.926Z',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411333/artifacts/download',
|
||||
keep_path: '/gitlab-org/gitlab/-/jobs/62411333/artifacts/keep',
|
||||
browse_path: '/gitlab-org/gitlab/-/jobs/62411333/artifacts/browse',
|
||||
},
|
||||
],
|
||||
manual_actions: [
|
||||
{
|
||||
name: 'package-and-qa',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411330/play',
|
||||
playable: true,
|
||||
},
|
||||
{
|
||||
name: 'review-docs-deploy',
|
||||
path: '/gitlab-org/gitlab/-/jobs/62411332/play',
|
||||
playable: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
ref: {
|
||||
name: 'master',
|
||||
path: '/gitlab-org/gitlab/commits/master',
|
||||
tag: false,
|
||||
branch: true,
|
||||
},
|
||||
commit: {
|
||||
id: 'e6a2885c503825792cb8a84a8731295e361bd059',
|
||||
short_id: 'e6a2885c',
|
||||
title: "Merge branch 'ce-to-ee-2018-04-11' into 'master'",
|
||||
created_at: '2018-04-11T14:04:39.000Z',
|
||||
parent_ids: [
|
||||
'5d9b5118f6055f72cff1a82b88133609912f2c1d',
|
||||
'6fdc6ee76a8062fe41b1a33f7c503334a6ebdc02',
|
||||
],
|
||||
message:
|
||||
"Merge branch 'ce-to-ee-2018-04-11' into 'master'\n\nCE upstream - 2018-04-11 12:26 UTC\n\nSee merge request gitlab-org/gitlab-ee!5326",
|
||||
author_name: 'Rémy Coutable',
|
||||
author_email: 'remy@rymai.me',
|
||||
authored_date: '2018-04-11T14:04:39.000Z',
|
||||
committer_name: 'Rémy Coutable',
|
||||
committer_email: 'remy@rymai.me',
|
||||
committed_date: '2018-04-11T14:04:39.000Z',
|
||||
author: {
|
||||
id: 128633,
|
||||
name: 'Rémy Coutable',
|
||||
username: 'rymai',
|
||||
state: 'active',
|
||||
avatar_url:
|
||||
'https://secure.gravatar.com/avatar/263da227929cc0035cb0eba512bcf81a?s=80\u0026d=identicon',
|
||||
web_url: 'https://gitlab.com/rymai',
|
||||
path: '/rymai',
|
||||
},
|
||||
author_gravatar_url:
|
||||
'https://secure.gravatar.com/avatar/263da227929cc0035cb0eba512bcf81a?s=80\u0026d=identicon',
|
||||
commit_url:
|
||||
'https://gitlab.com/gitlab-org/gitlab/commit/e6a2885c503825792cb8a84a8731295e361bd059',
|
||||
commit_path: '/gitlab-org/gitlab/commit/e6a2885c503825792cb8a84a8731295e361bd059',
|
||||
},
|
||||
cancel_path: '/gitlab-org/gitlab/pipelines/20333396/cancel',
|
||||
triggered_by: null,
|
||||
triggered: [],
|
||||
};
|
||||
|
||||
const threeWeeksAgo = new Date();
|
||||
threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import Store from '~/pipelines/stores/pipelines_store';
|
|||
import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
|
||||
import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
|
||||
|
||||
import { pipelineWithStages, stageReply, users, mockSearch, branches } from './mock_data';
|
||||
import { stageReply, users, mockSearch, branches } from './mock_data';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
||||
|
@ -27,6 +27,9 @@ const mockProjectId = '21';
|
|||
const mockPipelinesEndpoint = `/${mockProjectPath}/pipelines.json`;
|
||||
const mockPipelinesResponse = getJSONFixture('pipelines/pipelines.json');
|
||||
const mockPipelinesIds = mockPipelinesResponse.pipelines.map(({ id }) => id);
|
||||
const mockPipelineWithStages = mockPipelinesResponse.pipelines.find(
|
||||
(p) => p.details.stages && p.details.stages.length,
|
||||
);
|
||||
|
||||
describe('Pipelines', () => {
|
||||
let wrapper;
|
||||
|
@ -611,14 +614,15 @@ describe('Pipelines', () => {
|
|||
mock.onGet(mockPipelinesEndpoint, { scope: 'all', page: '1' }).reply(
|
||||
200,
|
||||
{
|
||||
pipelines: [pipelineWithStages],
|
||||
pipelines: [mockPipelineWithStages],
|
||||
count: { all: '1' },
|
||||
},
|
||||
{
|
||||
'POLL-INTERVAL': 100,
|
||||
},
|
||||
);
|
||||
mock.onGet(pipelineWithStages.details.stages[0].dropdown_path).reply(200, stageReply);
|
||||
|
||||
mock.onGet(mockPipelineWithStages.details.stages[0].dropdown_path).reply(200, stageReply);
|
||||
|
||||
createComponent();
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ describe('Pipelines Table Row', () => {
|
|||
it('should render an icon for each stage', () => {
|
||||
expect(
|
||||
wrapper.findAll(
|
||||
'.table-section:nth-child(4) [data-testid="mini-pipeline-graph-dropdown-toggle"]',
|
||||
'.table-section:nth-child(5) [data-testid="mini-pipeline-graph-dropdown-toggle"]',
|
||||
).length,
|
||||
).toEqual(pipeline.details.stages.length);
|
||||
});
|
||||
|
@ -182,9 +182,10 @@ describe('Pipelines Table Row', () => {
|
|||
expect(wrapper.find('.js-pipelines-retry-button').attributes('title')).toMatch('Retry');
|
||||
expect(wrapper.find('.js-pipelines-cancel-button').exists()).toBe(true);
|
||||
expect(wrapper.find('.js-pipelines-cancel-button').attributes('title')).toMatch('Cancel');
|
||||
const dropdownMenu = wrapper.find('.dropdown-menu');
|
||||
|
||||
expect(dropdownMenu.text()).toContain(scheduledJobAction.name);
|
||||
const actionsMenu = wrapper.find('[data-testid="pipelines-manual-actions-dropdown"]');
|
||||
|
||||
expect(actionsMenu.text()).toContain(scheduledJobAction.name);
|
||||
});
|
||||
|
||||
it('emits `retryPipeline` event when retry button is clicked and toggles loading', () => {
|
||||
|
|
|
@ -6,6 +6,7 @@ RSpec.describe BulkImports::Groups::Pipelines::LabelsPipeline do
|
|||
let(:user) { create(:user) }
|
||||
let(:group) { create(:group) }
|
||||
let(:cursor) { 'cursor' }
|
||||
let(:timestamp) { Time.new(2020, 01, 01).utc }
|
||||
let(:entity) do
|
||||
create(
|
||||
:bulk_import_entity,
|
||||
|
@ -20,21 +21,23 @@ RSpec.describe BulkImports::Groups::Pipelines::LabelsPipeline do
|
|||
|
||||
subject { described_class.new(context) }
|
||||
|
||||
def extractor_data(title:, has_next_page:, cursor: nil)
|
||||
data = [
|
||||
{
|
||||
'title' => title,
|
||||
'description' => 'desc',
|
||||
'color' => '#428BCA'
|
||||
}
|
||||
]
|
||||
def label_data(title)
|
||||
{
|
||||
'title' => title,
|
||||
'description' => 'desc',
|
||||
'color' => '#428BCA',
|
||||
'created_at' => timestamp.to_s,
|
||||
'updated_at' => timestamp.to_s
|
||||
}
|
||||
end
|
||||
|
||||
def extractor_data(title:, has_next_page:, cursor: nil)
|
||||
page_info = {
|
||||
'end_cursor' => cursor,
|
||||
'has_next_page' => has_next_page
|
||||
}
|
||||
|
||||
BulkImports::Pipeline::ExtractedData.new(data: data, page_info: page_info)
|
||||
BulkImports::Pipeline::ExtractedData.new(data: [label_data(title)], page_info: page_info)
|
||||
end
|
||||
|
||||
describe '#run' do
|
||||
|
@ -55,6 +58,8 @@ RSpec.describe BulkImports::Groups::Pipelines::LabelsPipeline do
|
|||
expect(label.title).to eq('label2')
|
||||
expect(label.description).to eq('desc')
|
||||
expect(label.color).to eq('#428BCA')
|
||||
expect(label.created_at).to eq(timestamp)
|
||||
expect(label.updated_at).to eq(timestamp)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -92,19 +97,15 @@ RSpec.describe BulkImports::Groups::Pipelines::LabelsPipeline do
|
|||
|
||||
describe '#load' do
|
||||
it 'creates the label' do
|
||||
data = {
|
||||
'title' => 'label',
|
||||
'description' => 'description',
|
||||
'color' => '#FFFFFF'
|
||||
}
|
||||
data = label_data('label')
|
||||
|
||||
expect { subject.load(context, data) }.to change(Label, :count).by(1)
|
||||
|
||||
label = group.labels.first
|
||||
|
||||
expect(label.title).to eq(data['title'])
|
||||
expect(label.description).to eq(data['description'])
|
||||
expect(label.color).to eq(data['color'])
|
||||
data.each do |key, value|
|
||||
expect(label[key]).to eq(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -24,6 +24,26 @@ RSpec.describe Gitlab::CurrentSettings do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.signup_disabled?' do
|
||||
subject { described_class.signup_disabled? }
|
||||
|
||||
context 'when signup is enabled' do
|
||||
before do
|
||||
create(:application_setting, signup_enabled: true)
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
|
||||
context 'when signup is disabled' do
|
||||
before do
|
||||
create(:application_setting, signup_enabled: false)
|
||||
end
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#current_application_settings', :use_clean_rails_memory_store_caching do
|
||||
it 'allows keys to be called directly' do
|
||||
db_settings = create(:application_setting,
|
||||
|
|
|
@ -37,26 +37,9 @@ RSpec.describe 'Marginalia spec' do
|
|||
}
|
||||
end
|
||||
|
||||
context 'when the feature is enabled' do
|
||||
before do
|
||||
stub_feature(true)
|
||||
end
|
||||
|
||||
it 'generates a query that includes the component and value' do
|
||||
component_map.each do |component, value|
|
||||
expect(recorded.log.last).to include("#{component}:#{value}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the feature is disabled' do
|
||||
before do
|
||||
stub_feature(false)
|
||||
end
|
||||
|
||||
it 'excludes annotations in generated queries' do
|
||||
expect(recorded.log.last).not_to include("/*")
|
||||
expect(recorded.log.last).not_to include("*/")
|
||||
it 'generates a query that includes the component and value' do
|
||||
component_map.each do |component, value|
|
||||
expect(recorded.log.last).to include("#{component}:#{value}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -90,9 +73,27 @@ RSpec.describe 'Marginalia spec' do
|
|||
}
|
||||
end
|
||||
|
||||
context 'when the feature is enabled' do
|
||||
before do
|
||||
stub_feature(true)
|
||||
it 'generates a query that includes the component and value' do
|
||||
component_map.each do |component, value|
|
||||
expect(recorded.log.last).to include("#{component}:#{value}")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'for ActionMailer delivery jobs' do
|
||||
let(:delivery_job) { MarginaliaTestMailer.first_user.deliver_later }
|
||||
|
||||
let(:recorded) do
|
||||
ActiveRecord::QueryRecorder.new do
|
||||
delivery_job.perform_now
|
||||
end
|
||||
end
|
||||
|
||||
let(:component_map) do
|
||||
{
|
||||
"application" => "sidekiq",
|
||||
"jid" => delivery_job.job_id,
|
||||
"job_class" => delivery_job.arguments.first
|
||||
}
|
||||
end
|
||||
|
||||
it 'generates a query that includes the component and value' do
|
||||
|
@ -100,47 +101,7 @@ RSpec.describe 'Marginalia spec' do
|
|||
expect(recorded.log.last).to include("#{component}:#{value}")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'for ActionMailer delivery jobs' do
|
||||
let(:delivery_job) { MarginaliaTestMailer.first_user.deliver_later }
|
||||
|
||||
let(:recorded) do
|
||||
ActiveRecord::QueryRecorder.new do
|
||||
delivery_job.perform_now
|
||||
end
|
||||
end
|
||||
|
||||
let(:component_map) do
|
||||
{
|
||||
"application" => "sidekiq",
|
||||
"jid" => delivery_job.job_id,
|
||||
"job_class" => delivery_job.arguments.first
|
||||
}
|
||||
end
|
||||
|
||||
it 'generates a query that includes the component and value' do
|
||||
component_map.each do |component, value|
|
||||
expect(recorded.log.last).to include("#{component}:#{value}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the feature is disabled' do
|
||||
before do
|
||||
stub_feature(false)
|
||||
end
|
||||
|
||||
it 'excludes annotations in generated queries' do
|
||||
expect(recorded.log.last).not_to include("/*")
|
||||
expect(recorded.log.last).not_to include("*/")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def stub_feature(value)
|
||||
stub_feature_flags(marginalia: value)
|
||||
Gitlab::Marginalia.set_enabled_from_feature_flag
|
||||
end
|
||||
|
||||
def make_request(correlation_id)
|
||||
|
|
|
@ -3082,32 +3082,83 @@ RSpec.describe MergeRequest, factory_default: :keep do
|
|||
end
|
||||
|
||||
describe "#head_pipeline_active? " do
|
||||
it do
|
||||
is_expected
|
||||
.to delegate_method(:active?)
|
||||
.to(:head_pipeline)
|
||||
.with_prefix
|
||||
.with_arguments(allow_nil: true)
|
||||
context 'when project lacks a head_pipeline relation' do
|
||||
before do
|
||||
subject.head_pipeline = nil
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(subject.head_pipeline_active?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project has a head_pipeline relation' do
|
||||
let(:pipeline) { create(:ci_empty_pipeline) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:head_pipeline) { pipeline }
|
||||
end
|
||||
|
||||
it 'accesses the value from the head_pipeline' do
|
||||
expect(subject.head_pipeline)
|
||||
.to receive(:active?)
|
||||
|
||||
subject.head_pipeline_active?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#actual_head_pipeline_success? " do
|
||||
it do
|
||||
is_expected
|
||||
.to delegate_method(:success?)
|
||||
.to(:actual_head_pipeline)
|
||||
.with_prefix
|
||||
.with_arguments(allow_nil: true)
|
||||
context 'when project lacks an actual_head_pipeline relation' do
|
||||
before do
|
||||
allow(subject).to receive(:actual_head_pipeline) { nil }
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(subject.actual_head_pipeline_success?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project has a actual_head_pipeline relation' do
|
||||
let(:pipeline) { create(:ci_empty_pipeline) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:actual_head_pipeline) { pipeline }
|
||||
end
|
||||
|
||||
it 'accesses the value from the actual_head_pipeline' do
|
||||
expect(subject.actual_head_pipeline)
|
||||
.to receive(:success?)
|
||||
|
||||
subject.actual_head_pipeline_success?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#actual_head_pipeline_active? " do
|
||||
it do
|
||||
is_expected
|
||||
.to delegate_method(:active?)
|
||||
.to(:actual_head_pipeline)
|
||||
.with_prefix
|
||||
.with_arguments(allow_nil: true)
|
||||
context 'when project lacks an actual_head_pipeline relation' do
|
||||
before do
|
||||
allow(subject).to receive(:actual_head_pipeline) { nil }
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(subject.actual_head_pipeline_active?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when project has a actual_head_pipeline relation' do
|
||||
let(:pipeline) { create(:ci_empty_pipeline) }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:actual_head_pipeline) { pipeline }
|
||||
end
|
||||
|
||||
it 'accesses the value from the actual_head_pipeline' do
|
||||
expect(subject.actual_head_pipeline)
|
||||
.to receive(:active?)
|
||||
|
||||
subject.actual_head_pipeline_active?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -496,6 +496,16 @@ RSpec.describe Snippet do
|
|||
it 'returns array of blobs' do
|
||||
expect(snippet.blobs).to all(be_a(Blob))
|
||||
end
|
||||
|
||||
context 'when file does not exist' do
|
||||
it 'removes nil values from the blobs array' do
|
||||
allow(snippet).to receive(:list_files).and_return(%w(LICENSE non_existent_snippet_file))
|
||||
|
||||
blobs = snippet.blobs
|
||||
expect(blobs.count).to eq 1
|
||||
expect(blobs.first.name).to eq 'LICENSE'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ RSpec.describe SnippetPresenter do
|
|||
let(:snippet) { create(:snippet, :repository, author: user) }
|
||||
|
||||
it 'returns repository first blob' do
|
||||
expect(subject).to eq snippet.blobs.first
|
||||
expect(subject.name).to eq snippet.blobs.first.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,9 @@ require 'spec_helper'
|
|||
RSpec.describe API::Lint do
|
||||
describe 'POST /ci/lint' do
|
||||
context 'when signup settings are disabled' do
|
||||
Gitlab::CurrentSettings.signup_enabled = false
|
||||
before do
|
||||
Gitlab::CurrentSettings.signup_enabled = false
|
||||
end
|
||||
|
||||
context 'when unauthenticated' do
|
||||
it 'returns authentication error' do
|
||||
|
@ -16,22 +18,25 @@ RSpec.describe API::Lint do
|
|||
end
|
||||
|
||||
context 'when authenticated' do
|
||||
it 'returns unauthorized error' do
|
||||
post api('/ci/lint'), params: { content: 'content' }
|
||||
let_it_be(:api_user) { create(:user) }
|
||||
it 'returns authorized' do
|
||||
post api('/ci/lint', api_user), params: { content: 'content' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when signup settings are enabled' do
|
||||
Gitlab::CurrentSettings.signup_enabled = true
|
||||
before do
|
||||
Gitlab::CurrentSettings.signup_enabled = true
|
||||
end
|
||||
|
||||
context 'when unauthenticated' do
|
||||
it 'returns authentication error' do
|
||||
it 'returns authorized success' do
|
||||
post api('/ci/lint'), params: { content: 'content' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -249,9 +249,6 @@ RSpec.configure do |config|
|
|||
unstub_all_feature_flags
|
||||
end
|
||||
|
||||
# Enable Marginalia feature for all specs in the test suite.
|
||||
Gitlab::Marginalia.enabled = true
|
||||
|
||||
# Stub these calls due to being expensive operations
|
||||
# It can be reenabled for specific tests via:
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue