Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-08-06 06:10:16 +00:00
parent 02246c40b8
commit 8f5ebbe2c7
14 changed files with 246 additions and 21 deletions

View File

@ -27,7 +27,13 @@ export default {
},
computed: {
urlParams() {
const { authorUsername, labelName, assigneeUsername, search } = this.filterParams;
const {
authorUsername,
labelName,
assigneeUsername,
search,
milestoneTitle,
} = this.filterParams;
let notParams = {};
if (Object.prototype.hasOwnProperty.call(this.filterParams, 'not')) {
@ -36,6 +42,7 @@ export default {
'not[label_name][]': this.filterParams.not.labelName,
'not[author_username]': this.filterParams.not.authorUsername,
'not[assignee_username]': this.filterParams.not.assigneeUsername,
'not[milestone_title]': this.filterParams.not.milestoneTitle,
},
undefined,
);
@ -46,6 +53,7 @@ export default {
author_username: authorUsername,
'label_name[]': labelName,
assignee_username: assigneeUsername,
milestone_title: milestoneTitle,
search,
};
},
@ -64,7 +72,13 @@ export default {
this.performSearch();
},
getFilteredSearchValue() {
const { authorUsername, labelName, assigneeUsername, search } = this.filterParams;
const {
authorUsername,
labelName,
assigneeUsername,
search,
milestoneTitle,
} = this.filterParams;
const filteredSearchValue = [];
if (authorUsername) {
@ -90,6 +104,13 @@ export default {
);
}
if (milestoneTitle) {
filteredSearchValue.push({
type: 'milestone_title',
value: { data: milestoneTitle, operator: '=' },
});
}
if (this.filterParams['not[authorUsername]']) {
filteredSearchValue.push({
type: 'author_username',
@ -97,6 +118,13 @@ export default {
});
}
if (this.filterParams['not[milestoneTitle]']) {
filteredSearchValue.push({
type: 'milestone_title',
value: { data: this.filterParams['not[milestoneTitle]'], operator: '!=' },
});
}
if (this.filterParams['not[assigneeUsername]']) {
filteredSearchValue.push({
type: 'assignee_username',
@ -143,6 +171,9 @@ export default {
case 'label_name':
labels.push(filter.value.data);
break;
case 'milestone_title':
filterParams.milestoneTitle = filter.value.data;
break;
case 'filtered-search-term':
if (filter.value.data) plainText.push(filter.value.data);
break;

View File

@ -1,4 +1,5 @@
<script>
import { mapActions } from 'vuex';
import BoardFilteredSearch from '~/boards/components/board_filtered_search.vue';
import issueBoardFilters from '~/boards/issue_board_filters';
import { TYPE_USER } from '~/graphql_shared/constants';
@ -6,6 +7,7 @@ import { convertToGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
export default {
i18n: {
@ -13,6 +15,7 @@ export default {
label: __('Label'),
author: __('Author'),
assignee: __('Assignee'),
milestone: __('Milestone'),
is: __('is'),
isNot: __('is not'),
},
@ -29,7 +32,7 @@ export default {
},
computed: {
tokens() {
const { label, is, isNot, author, assignee } = this.$options.i18n;
const { label, is, isNot, author, assignee, milestone } = this.$options.i18n;
const { fetchAuthors, fetchLabels } = issueBoardFilters(
this.$apollo,
this.fullPath,
@ -77,10 +80,21 @@ export default {
fetchAuthors,
preloadedAuthors: this.preloadedAuthors(),
},
{
type: 'milestone_title',
title: milestone,
icon: 'clock',
symbol: '%',
token: MilestoneToken,
unique: true,
defaultMilestones: [], // todo: https://gitlab.com/gitlab-org/gitlab/-/issues/337044#note_640010094
fetchMilestones: this.fetchMilestones,
},
];
},
},
methods: {
...mapActions(['fetchMilestones']),
preloadedAuthors() {
return gon?.current_user_id
? [

View File

@ -0,0 +1,31 @@
<script>
import { GlAlert } from '@gitlab/ui';
import EditorStateObserver from './editor_state_observer.vue';
export default {
components: {
GlAlert,
EditorStateObserver,
},
data() {
return {
error: null,
};
},
methods: {
displayError({ error }) {
this.error = error;
},
dismissError() {
this.error = null;
},
},
};
</script>
<template>
<editor-state-observer @error="displayError">
<gl-alert v-if="error" class="gl-mb-6" variant="danger" @dismiss="dismissError">
{{ error }}
</gl-alert>
</editor-state-observer>
</template>

View File

@ -5,6 +5,9 @@ export const tiptapToComponentMap = {
update: 'docUpdate',
selectionUpdate: 'selectionUpdate',
transaction: 'transaction',
focus: 'focus',
blur: 'blur',
error: 'error',
};
const getComponentEventName = (tiptapEventName) => tiptapToComponentMap[tiptapEventName];

View File

@ -275,7 +275,6 @@ export default {
avatar_url: gon.current_user_avatar_url,
});
}
const tokens = [
{
type: TOKEN_TYPE_AUTHOR,

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddUniqueIndexToVulnerabilityFlagsTable < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
INDEX_NAME = 'index_vulnerability_flags_on_unique_columns'
disable_ddl_transaction!
def up
add_concurrent_index :vulnerability_flags, [:vulnerability_occurrence_id, :flag_type, :origin], name: INDEX_NAME, unique: true
end
def down
remove_concurrent_index_by_name :vulnerability_flags, INDEX_NAME
end
end

View File

@ -0,0 +1 @@
529cf86e09b5aa9015b604e73827cb21e92ced401f30dfb281115a506596bd4e

View File

@ -25450,6 +25450,8 @@ CREATE INDEX index_vulnerability_findings_remediations_on_remediation_id ON vuln
CREATE UNIQUE INDEX index_vulnerability_findings_remediations_on_unique_keys ON vulnerability_findings_remediations USING btree (vulnerability_occurrence_id, vulnerability_remediation_id);
CREATE UNIQUE INDEX index_vulnerability_flags_on_unique_columns ON vulnerability_flags USING btree (vulnerability_occurrence_id, flag_type, origin);
CREATE INDEX index_vulnerability_flags_on_vulnerability_occurrence_id ON vulnerability_flags USING btree (vulnerability_occurrence_id);
CREATE INDEX index_vulnerability_historical_statistics_on_date_and_id ON vulnerability_historical_statistics USING btree (date, id);

View File

@ -2,6 +2,42 @@
namespace :gitlab do
namespace :gitaly do
desc 'Installs gitaly for running tests within gitlab-development-kit'
task :test_install, [:dir, :storage_path, :repo] => :gitlab_environment do |t, args|
inside_gdk = Rails.env.test? && File.exist?(Rails.root.join('../GDK_ROOT'))
if ENV['FORCE_GITALY_INSTALL'] || !inside_gdk
Rake::Task["gitlab:gitaly:install"].invoke(*args)
next
end
gdk_gitaly_dir = ENV.fetch('GDK_GITALY', Rails.root.join('../gitaly'))
# Our test setup expects a git repo, so clone rather than copy
version = Gitlab::GitalyClient.expected_server_version
checkout_or_clone_version(version: version, repo: gdk_gitaly_dir, target_dir: args.dir, clone_opts: %w[--depth 1])
# We assume the GDK gitaly already compiled binaries
build_dir = File.join(gdk_gitaly_dir, '_build')
FileUtils.cp_r(build_dir, args.dir)
# We assume the GDK gitaly already ran bundle install
bundle_dir = File.join(gdk_gitaly_dir, 'ruby', '.bundle')
FileUtils.cp_r(bundle_dir, File.join(args.dir, 'ruby'))
# For completeness we copy this for gitaly's make target
ruby_bundle_file = File.join(gdk_gitaly_dir, '.ruby-bundle')
FileUtils.cp_r(ruby_bundle_file, args.dir)
gitaly_binary = File.join(build_dir, 'bin', 'gitaly')
warn_gitaly_out_of_date!(gitaly_binary, version)
rescue Errno::ENOENT => e
puts "Could not copy files, did you run `gdk update`? Error: #{e.message}"
raise
end
desc 'GitLab | Gitaly | Install or upgrade gitaly'
task :install, [:dir, :storage_path, :repo] => :gitlab_environment do |t, args|
warn_user_is_not_gitlab
@ -41,5 +77,24 @@ Usage: rake "gitlab:gitaly:install[/installation/dir,/storage/path]")
_, status = Gitlab::Popen.popen(%w[which gmake])
status == 0 ? 'gmake' : 'make'
end
def warn_gitaly_out_of_date!(gitaly_binary, expected_version)
binary_version, exit_status = Gitlab::Popen.popen(%W[#{gitaly_binary} -version])
raise "Failed to run `#{gitaly_binary} -version`" unless exit_status == 0
binary_version = binary_version.strip
# See help for `git describe` for format
git_describe_sha = /g([a-f0-9]{5,40})\z/
match = binary_version.match(git_describe_sha)
# Just skip if the version does not have a sha component
return unless match
return if expected_version.start_with?(match[1])
puts "WARNING: #{binary_version.strip} does not exactly match repository version #{expected_version}"
end
end
end

View File

@ -115,6 +115,7 @@ describe('BoardFilteredSearch', () => {
{ type: 'author_username', value: { data: 'root', operator: '=' } },
{ type: 'label_name', value: { data: 'label', operator: '=' } },
{ type: 'label_name', value: { data: 'label2', operator: '=' } },
{ type: 'milestone_title', value: { data: 'New Milestone', operator: '=' } },
];
jest.spyOn(urlUtility, 'updateHistory');
findFilteredSearch().vm.$emit('onFilter', mockFilters);
@ -122,7 +123,8 @@ describe('BoardFilteredSearch', () => {
expect(urlUtility.updateHistory).toHaveBeenCalledWith({
title: '',
replace: true,
url: 'http://test.host/?author_username=root&label_name[]=label&label_name[]=label2',
url:
'http://test.host/?author_username=root&label_name[]=label&label_name[]=label2&milestone_title=New+Milestone',
});
});
});

View File

@ -1,16 +1,16 @@
import { shallowMount } from '@vue/test-utils';
import BoardFilteredSearch from '~/boards/components/board_filtered_search.vue';
import IssueBoardFilteredSpec from '~/boards/components/issue_board_filtered_search.vue';
import { BoardType } from '~/boards/constants';
import issueBoardFilters from '~/boards/issue_board_filters';
import { mockTokens } from '../mock_data';
jest.mock('~/boards/issue_board_filters');
describe('IssueBoardFilter', () => {
let wrapper;
const createComponent = ({ initialFilterParams = {} } = {}) => {
const createComponent = () => {
wrapper = shallowMount(IssueBoardFilteredSpec, {
provide: { initialFilterParams },
props: { fullPath: '', boardType: '' },
});
};
@ -20,7 +20,17 @@ describe('IssueBoardFilter', () => {
});
describe('default', () => {
let fetchAuthorsSpy;
let fetchLabelsSpy;
beforeEach(() => {
fetchAuthorsSpy = jest.fn();
fetchLabelsSpy = jest.fn();
issueBoardFilters.mockReturnValue({
fetchAuthors: fetchAuthorsSpy,
fetchLabels: fetchLabelsSpy,
});
createComponent();
});
@ -28,17 +38,10 @@ describe('IssueBoardFilter', () => {
expect(wrapper.find(BoardFilteredSearch).exists()).toBe(true);
});
it.each([[BoardType.group], [BoardType.project]])(
'when boardType is %s we pass the correct tokens to BoardFilteredSearch',
(boardType) => {
const { fetchAuthors, fetchLabels } = issueBoardFilters({}, '', boardType);
it('passes the correct tokens to BoardFilteredSearch', () => {
const tokens = mockTokens(fetchLabelsSpy, fetchAuthorsSpy, wrapper.vm.fetchMilestones);
const tokens = mockTokens(fetchLabels, fetchAuthors);
expect(wrapper.find(BoardFilteredSearch).props('tokens').toString()).toBe(
tokens.toString(),
);
},
);
expect(wrapper.find(BoardFilteredSearch).props('tokens')).toEqual(tokens);
});
});
});

View File

@ -8,6 +8,7 @@ import boardsStore from '~/boards/stores/boards_store';
import { __ } from '~/locale';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue';
export const boardObj = {
id: 1,
@ -542,7 +543,7 @@ export const mockMoveData = {
...mockMoveIssueParams,
};
export const mockTokens = (fetchLabels, fetchAuthors) => [
export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones) => [
{
icon: 'labels',
title: __('Label'),
@ -568,6 +569,7 @@ export const mockTokens = (fetchLabels, fetchAuthors) => [
token: AuthorToken,
unique: true,
fetchAuthors,
preloadedAuthors: [],
},
{
icon: 'user',
@ -580,5 +582,16 @@ export const mockTokens = (fetchLabels, fetchAuthors) => [
token: AuthorToken,
unique: true,
fetchAuthors,
preloadedAuthors: [],
},
{
icon: 'clock',
title: __('Milestone'),
symbol: '%',
type: 'milestone_title',
token: MilestoneToken,
unique: true,
defaultMilestones: [],
fetchMilestones,
},
];

View File

@ -0,0 +1,54 @@
import { GlAlert } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ContentEditorError from '~/content_editor/components/content_editor_error.vue';
import EditorStateObserver from '~/content_editor/components/editor_state_observer.vue';
import { createTestEditor, emitEditorEvent } from '../test_utils';
describe('content_editor/components/content_editor_error', () => {
let wrapper;
let tiptapEditor;
const findErrorAlert = () => wrapper.findComponent(GlAlert);
const createWrapper = async () => {
tiptapEditor = createTestEditor();
wrapper = shallowMountExtended(ContentEditorError, {
provide: {
tiptapEditor,
},
stubs: {
EditorStateObserver,
},
});
};
afterEach(() => {
wrapper.destroy();
});
it('renders error when content editor emits an error event', async () => {
const error = 'error message';
createWrapper();
await emitEditorEvent({ tiptapEditor, event: 'error', params: { error } });
expect(findErrorAlert().text()).toBe(error);
});
it('allows dismissing the error', async () => {
const error = 'error message';
createWrapper();
await emitEditorEvent({ tiptapEditor, event: 'error', params: { error } });
findErrorAlert().vm.$emit('dismiss');
await nextTick();
expect(findErrorAlert().exists()).toBe(false);
});
});

View File

@ -158,7 +158,7 @@ module TestEnv
component_timed_setup('Gitaly',
install_dir: gitaly_dir,
version: Gitlab::GitalyClient.expected_server_version,
task: "gitlab:gitaly:install",
task: "gitlab:gitaly:test_install",
task_args: [gitaly_dir, repos_path, gitaly_url].compact) do
Gitlab::SetupHelper::Gitaly.create_configuration(
gitaly_dir,