diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 0890fe473c6..a69085090c5 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1275,5 +1275,3 @@ FactoryBot/InlineAssociation:
- 'spec/factories/packages.rb'
- 'spec/factories/packages/package_file.rb'
- 'spec/factories/sent_notifications.rb'
- - 'spec/factories/uploads.rb'
- - 'spec/factories/wiki_pages.rb'
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index cfc730712d5..5e57fb89558 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.28.0
+1.29.0
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/issuable_move_dropdown.vue b/app/assets/javascripts/vue_shared/components/sidebar/issuable_move_dropdown.vue
new file mode 100644
index 00000000000..1d3bd312b09
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/issuable_move_dropdown.vue
@@ -0,0 +1,211 @@
+
+
+
+
+
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 7a87a968489..00d32b75628 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -921,6 +921,25 @@
}
}
+/*
+ * Following overrides are done to prevent
+ * legacy dropdown styles from influencing
+ * GitLab UI components used within GlDropdown
+ */
+.issuable-move-dropdown {
+ .b-dropdown-form {
+ @include gl-p-0;
+ }
+
+ .gl-search-box-by-type button.gl-clear-icon-button:hover {
+ @include gl-bg-transparent;
+ }
+
+ .issuable-move-button:not(.disabled):hover {
+ @include gl-text-white;
+ }
+}
+
.right-sidebar-collapsed {
.sidebar-grouped-item {
.sidebar-collapsed-icon {
diff --git a/app/services/projects/container_repository/delete_tags_service.rb b/app/services/projects/container_repository/delete_tags_service.rb
index 9fc3ec0aafb..505ddaf50e3 100644
--- a/app/services/projects/container_repository/delete_tags_service.rb
+++ b/app/services/projects/container_repository/delete_tags_service.rb
@@ -36,11 +36,11 @@ module Projects
def log_response(response)
log_data = LOG_DATA_BASE.merge(
container_repository_id: @container_repository.id,
- message: 'deleted tags'
- )
+ message: 'deleted tags',
+ deleted_tags_count: response[:deleted]&.size
+ ).compact
if response[:status] == :success
- log_data[:deleted_tags_count] = response[:deleted].size
log_info(log_data)
else
log_data[:message] = response[:message]
diff --git a/app/services/projects/container_repository/gitlab/delete_tags_service.rb b/app/services/projects/container_repository/gitlab/delete_tags_service.rb
index cee94b994a3..e4e22dd9543 100644
--- a/app/services/projects/container_repository/gitlab/delete_tags_service.rb
+++ b/app/services/projects/container_repository/gitlab/delete_tags_service.rb
@@ -14,6 +14,7 @@ module Projects
def initialize(container_repository, tag_names)
@container_repository = container_repository
@tag_names = tag_names
+ @deleted_tags = []
end
# Delete tags by name with a single DELETE request. This is only supported
@@ -25,7 +26,7 @@ module Projects
delete_tags
rescue TimeoutError => e
::Gitlab::ErrorTracking.track_exception(e, tags_count: @tag_names&.size, container_repository_id: @container_repository&.id)
- error('timeout while deleting tags')
+ error('timeout while deleting tags', nil, pass_back: { deleted: @deleted_tags })
end
private
@@ -33,13 +34,15 @@ module Projects
def delete_tags
start_time = Time.zone.now
- deleted_tags = @tag_names.select do |name|
+ @tag_names.each do |name|
raise TimeoutError if timeout?(start_time)
- @container_repository.delete_tag_by_name(name)
+ if @container_repository.delete_tag_by_name(name)
+ @deleted_tags.append(name)
+ end
end
- deleted_tags.any? ? success(deleted: deleted_tags) : error('could not delete tags')
+ @deleted_tags.any? ? success(deleted: @deleted_tags) : error('could not delete tags')
end
def timeout?(start_time)
diff --git a/changelogs/unreleased/delete_tags_service_logging_enhancement.yml b/changelogs/unreleased/delete_tags_service_logging_enhancement.yml
new file mode 100644
index 00000000000..c248634ae42
--- /dev/null
+++ b/changelogs/unreleased/delete_tags_service_logging_enhancement.yml
@@ -0,0 +1,6 @@
+---
+title: Improving Container Registry Delete Tags Service to log number of successfully
+ deleted tags even if deletion process was interrupted by a timeout
+merge_request: 46079
+author: Maksim Stankevic, @maksimstankevic
+type: changed
diff --git a/changelogs/unreleased/kerrizor-increase-default-diff_max_patch_bytes.yml b/changelogs/unreleased/kerrizor-increase-default-diff_max_patch_bytes.yml
new file mode 100644
index 00000000000..0eeaf26ba1e
--- /dev/null
+++ b/changelogs/unreleased/kerrizor-increase-default-diff_max_patch_bytes.yml
@@ -0,0 +1,5 @@
+---
+title: Update diff_max_patch_bytes from 100kb -> 200kb
+merge_request: 46276
+author:
+type: changed
diff --git a/changelogs/unreleased/upgrade-pages-1-29-0.yml b/changelogs/unreleased/upgrade-pages-1-29-0.yml
new file mode 100644
index 00000000000..06a630f87f7
--- /dev/null
+++ b/changelogs/unreleased/upgrade-pages-1-29-0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade GitLab Pages to 1.29.0
+merge_request: 46665
+author:
+type: added
diff --git a/db/migrate/20201027211138_increase_default_diff_max_patch_bytes.rb b/db/migrate/20201027211138_increase_default_diff_max_patch_bytes.rb
new file mode 100644
index 00000000000..92d9025706f
--- /dev/null
+++ b/db/migrate/20201027211138_increase_default_diff_max_patch_bytes.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class IncreaseDefaultDiffMaxPatchBytes < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ change_column_default(:application_settings, :diff_max_patch_bytes, from: 102400, to: 204800)
+ end
+end
diff --git a/db/migrate/20201028204306_migrate_default_diff_max_patch_bytes_to_minimum_200kb.rb b/db/migrate/20201028204306_migrate_default_diff_max_patch_bytes_to_minimum_200kb.rb
new file mode 100644
index 00000000000..11d47904e67
--- /dev/null
+++ b/db/migrate/20201028204306_migrate_default_diff_max_patch_bytes_to_minimum_200kb.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class MigrateDefaultDiffMaxPatchBytesToMinimum200kb < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+ MAX_SIZE = 200.kilobytes
+
+ class ApplicationSetting < ActiveRecord::Base
+ self.table_name = 'application_settings'
+ end
+
+ def up
+ table = ApplicationSetting.arel_table
+ ApplicationSetting.where(table[:diff_max_patch_bytes].lt(MAX_SIZE)).update_all(diff_max_patch_bytes: MAX_SIZE)
+ end
+
+ def down
+ table = ApplicationSetting.arel_table
+ ApplicationSetting.where(table[:diff_max_patch_bytes].eq(MAX_SIZE)).update_all(diff_max_patch_bytes: 100.kilobytes)
+ end
+end
diff --git a/db/schema_migrations/20201027211138 b/db/schema_migrations/20201027211138
new file mode 100644
index 00000000000..5e36445702b
--- /dev/null
+++ b/db/schema_migrations/20201027211138
@@ -0,0 +1 @@
+402e9a6e92802888ba01ee216850ab5b0fe9997a84415c9ffe8d5d37a9823220
\ No newline at end of file
diff --git a/db/schema_migrations/20201028204306 b/db/schema_migrations/20201028204306
new file mode 100644
index 00000000000..03b68c9a0d1
--- /dev/null
+++ b/db/schema_migrations/20201028204306
@@ -0,0 +1 @@
+ec5bab20a1b591b77b48b85dc0b871e88a41891d256201b7d8eb86195ef1c4ad
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index dbb20221d96..71a66997b20 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -9207,7 +9207,7 @@ CREATE TABLE application_settings (
custom_project_templates_group_id integer,
usage_stats_set_by_user_id integer,
receive_max_input_size integer,
- diff_max_patch_bytes integer DEFAULT 102400 NOT NULL,
+ diff_max_patch_bytes integer DEFAULT 204800 NOT NULL,
archive_builds_in_seconds integer,
commit_email_hostname character varying,
protected_ci_variables boolean DEFAULT true NOT NULL,
@@ -12749,10 +12749,10 @@ CREATE TABLE group_wiki_repositories (
CREATE TABLE historical_data (
id integer NOT NULL,
+ date date,
active_user_count integer,
created_at timestamp without time zone,
updated_at timestamp without time zone,
- date date,
recorded_at timestamp with time zone,
CONSTRAINT check_640e8cf66c CHECK ((recorded_at IS NOT NULL))
);
diff --git a/lib/gitlab/git/diff.rb b/lib/gitlab/git/diff.rb
index 78c47023c08..209917073c7 100644
--- a/lib/gitlab/git/diff.rb
+++ b/lib/gitlab/git/diff.rb
@@ -25,7 +25,7 @@ module Gitlab
#
# If this value ever changes, make sure to create a migration to update
# current records, and default of `ApplicationSettings#diff_max_patch_bytes`.
- DEFAULT_MAX_PATCH_BYTES = 100.kilobytes
+ DEFAULT_MAX_PATCH_BYTES = 200.kilobytes
# This is a limitation applied on the source (Gitaly), therefore we don't allow
# persisting limits over that.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 5dae947d5e6..383500ebcd3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -11139,6 +11139,9 @@ msgstr ""
msgid "Failed to load milestones. Please try again."
msgstr ""
+msgid "Failed to load projects"
+msgstr ""
+
msgid "Failed to load related branches"
msgstr ""
diff --git a/package.json b/package.json
index a9cb06b6487..225b77b3241 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,7 @@
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.5",
"@gitlab/svgs": "1.174.0",
- "@gitlab/ui": "21.41.0",
+ "@gitlab/ui": "21.42.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-3",
"@rails/ujs": "^6.0.3-2",
diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb
index b19af277cc3..85237e2d791 100644
--- a/spec/factories/uploads.rb
+++ b/spec/factories/uploads.rb
@@ -2,7 +2,7 @@
FactoryBot.define do
factory :upload do
- model { create(:project) }
+ model { association(:project) }
size { 100.kilobytes }
uploader { "AvatarUploader" }
mount_point { :avatar }
@@ -20,7 +20,7 @@ FactoryBot.define do
end
trait :personal_snippet_upload do
- model { create(:personal_snippet) }
+ model { association(:personal_snippet) }
path { File.join(secret, filename) }
uploader { "PersonalFileUploader" }
secret { SecureRandom.hex }
@@ -46,7 +46,7 @@ FactoryBot.define do
end
trait :namespace_upload do
- model { create(:group) }
+ model { association(:group) }
path { File.join(secret, filename) }
uploader { "NamespaceFileUploader" }
secret { SecureRandom.hex }
@@ -54,7 +54,7 @@ FactoryBot.define do
end
trait :favicon_upload do
- model { create(:appearance) }
+ model { association(:appearance) }
uploader { "FaviconUploader" }
secret { SecureRandom.hex }
mount_point { :favicon }
@@ -62,13 +62,13 @@ FactoryBot.define do
trait :attachment_upload do
mount_point { :attachment }
- model { create(:note) }
+ model { association(:note) }
uploader { "AttachmentUploader" }
end
trait :design_action_image_v432x230_upload do
mount_point { :image_v432x230 }
- model { create(:design_action) }
+ model { association(:design_action) }
uploader { ::DesignManagement::DesignV432x230Uploader.name }
end
end
diff --git a/spec/factories/wiki_pages.rb b/spec/factories/wiki_pages.rb
index 3397277839e..6f912a183e8 100644
--- a/spec/factories/wiki_pages.rb
+++ b/spec/factories/wiki_pages.rb
@@ -39,14 +39,14 @@ FactoryBot.define do
factory :wiki_page_meta, class: 'WikiPage::Meta' do
title { generate(:wiki_page_title) }
- project { create(:project) }
+ project { association(:project) }
trait :for_wiki_page do
transient do
- wiki_page { create(:wiki_page, container: project) }
+ wiki_page { association(:wiki_page, container: project) }
end
- project { @overrides[:wiki_page]&.container || create(:project) }
+ project { @overrides[:wiki_page]&.container || association(:project) }
title { wiki_page.title }
initialize_with do
@@ -58,7 +58,7 @@ FactoryBot.define do
end
factory :wiki_page_slug, class: 'WikiPage::Slug' do
- wiki_page_meta { create(:wiki_page_meta) }
+ wiki_page_meta { association(:wiki_page_meta) }
slug { generate(:sluggified_title) }
canonical { false }
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index 49343cc7a57..0912df22924 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe 'Expand and collapse diffs', :js do
before do
stub_feature_flags(increased_diff_limits: false)
+ allow(Gitlab::CurrentSettings).to receive(:diff_max_patch_bytes).and_return(100.kilobytes)
+
sign_in(create(:admin))
# Ensure that undiffable.md is in .gitattributes
diff --git a/spec/features/merge_request/user_expands_diff_spec.rb b/spec/features/merge_request/user_expands_diff_spec.rb
index 08a92d5bc21..09c5897f102 100644
--- a/spec/features/merge_request/user_expands_diff_spec.rb
+++ b/spec/features/merge_request/user_expands_diff_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe 'User expands diff', :js do
before do
stub_feature_flags(increased_diff_limits: false)
+ allow(Gitlab::CurrentSettings).to receive(:diff_max_patch_bytes).and_return(100.kilobytes)
+
visit(diffs_project_merge_request_path(project, merge_request))
wait_for_requests
diff --git a/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap b/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap
index eaa7460ae15..a91ce43cda1 100644
--- a/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap
+++ b/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap
@@ -44,7 +44,7 @@ exports[`Design management upload button component renders loading icon 1`] = `
diff --git a/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap b/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
index 3d6c2561ff6..03ae77d4977 100644
--- a/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
@@ -136,7 +136,7 @@ exports[`Design management design index page sets loading state 1`] = `
>
diff --git a/spec/frontend/sidebar/__snapshots__/todo_spec.js.snap b/spec/frontend/sidebar/__snapshots__/todo_spec.js.snap
index 42012841f0b..6640c0844e2 100644
--- a/spec/frontend/sidebar/__snapshots__/todo_spec.js.snap
+++ b/spec/frontend/sidebar/__snapshots__/todo_spec.js.snap
@@ -27,7 +27,7 @@ exports[`SidebarTodo template renders component container element with proper da
+ shallowMount(IssuableMoveDropdown, {
+ propsData,
+ });
+
+describe('IssuableMoveDropdown', () => {
+ let mock;
+ let wrapper;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ wrapper = createComponent();
+ wrapper.vm.$refs.dropdown.hide = jest.fn();
+ wrapper.vm.$refs.searchInput.focusInput = jest.fn();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ mock.restore();
+ });
+
+ describe('watch', () => {
+ describe('searchKey', () => {
+ it('calls `fetchProjects` with value of the prop', async () => {
+ jest.spyOn(wrapper.vm, 'fetchProjects');
+ wrapper.setData({
+ searchKey: 'foo',
+ });
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.vm.fetchProjects).toHaveBeenCalledWith('foo');
+ });
+ });
+ });
+
+ describe('methods', () => {
+ describe('fetchProjects', () => {
+ it('sets projectsListLoading to true and projectsListLoadFailed to false', () => {
+ wrapper.vm.fetchProjects();
+
+ expect(wrapper.vm.projectsListLoading).toBe(true);
+ expect(wrapper.vm.projectsListLoadFailed).toBe(false);
+ });
+
+ it('calls `axios.get` with `projectsFetchPath` and query param `search`', () => {
+ jest.spyOn(axios, 'get').mockResolvedValue({
+ data: mockProjects,
+ });
+
+ wrapper.vm.fetchProjects('foo');
+
+ expect(axios.get).toHaveBeenCalledWith(
+ mockProps.projectsFetchPath,
+ expect.objectContaining({
+ params: {
+ search: 'foo',
+ },
+ }),
+ );
+ });
+
+ it('sets response to `projects` and focuses on searchInput when request is successful', async () => {
+ jest.spyOn(axios, 'get').mockResolvedValue({
+ data: mockProjects,
+ });
+
+ await wrapper.vm.fetchProjects('foo');
+
+ expect(wrapper.vm.projects).toBe(mockProjects);
+ expect(wrapper.vm.$refs.searchInput.focusInput).toHaveBeenCalled();
+ });
+
+ it('sets projectsListLoadFailed to true when request fails', async () => {
+ jest.spyOn(axios, 'get').mockRejectedValue({});
+
+ await wrapper.vm.fetchProjects('foo');
+
+ expect(wrapper.vm.projectsListLoadFailed).toBe(true);
+ });
+
+ it('sets projectsListLoading to false when request completes', async () => {
+ jest.spyOn(axios, 'get').mockResolvedValue({
+ data: mockProjects,
+ });
+
+ await wrapper.vm.fetchProjects('foo');
+
+ expect(wrapper.vm.projectsListLoading).toBe(false);
+ });
+ });
+
+ describe('isSelectedProject', () => {
+ it.each`
+ project | selectedProject | title | returnValue
+ ${mockProjects[0]} | ${mockProjects[0]} | ${'are same projects'} | ${true}
+ ${mockProjects[0]} | ${mockProjects[1]} | ${'are different projects'} | ${false}
+ `(
+ 'returns $returnValue when selectedProject and provided project param $title',
+ async ({ project, selectedProject, returnValue }) => {
+ wrapper.setData({
+ selectedProject,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.vm.isSelectedProject(project)).toBe(returnValue);
+ },
+ );
+
+ it('returns false when selectedProject is null', async () => {
+ wrapper.setData({
+ selectedProject: null,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.vm.isSelectedProject(mockProjects[0])).toBe(false);
+ });
+ });
+ });
+
+ describe('template', () => {
+ const findDropdownEl = () => wrapper.find(GlDropdown);
+
+ it('renders collapsed state element with icon', () => {
+ const collapsedEl = wrapper.find('[data-testid="move-collapsed"]');
+
+ expect(collapsedEl.exists()).toBe(true);
+ expect(collapsedEl.attributes('title')).toBe(mockProps.dropdownButtonTitle);
+ expect(collapsedEl.find(GlIcon).exists()).toBe(true);
+ expect(collapsedEl.find(GlIcon).props('name')).toBe('arrow-right');
+ });
+
+ describe('gl-dropdown component', () => {
+ it('renders component container element', () => {
+ expect(findDropdownEl().exists()).toBe(true);
+ expect(findDropdownEl().props('block')).toBe(true);
+ });
+
+ it('renders gl-dropdown-form component', () => {
+ expect(
+ findDropdownEl()
+ .find(GlDropdownForm)
+ .exists(),
+ ).toBe(true);
+ });
+
+ it('renders header element', () => {
+ const headerEl = findDropdownEl().find('[data-testid="header"]');
+
+ expect(headerEl.exists()).toBe(true);
+ expect(headerEl.find('span').text()).toBe(mockProps.dropdownHeaderTitle);
+ expect(headerEl.find(GlButton).props('icon')).toBe('close');
+ });
+
+ it('renders gl-search-box-by-type component', () => {
+ const searchEl = findDropdownEl().find(GlSearchBoxByType);
+
+ expect(searchEl.exists()).toBe(true);
+ expect(searchEl.attributes()).toMatchObject({
+ placeholder: 'Search project',
+ debounce: '300',
+ });
+ });
+
+ it('renders gl-loading-icon component when projectsListLoading prop is true', async () => {
+ wrapper.setData({
+ projectsListLoading: true,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ expect(
+ findDropdownEl()
+ .find(GlLoadingIcon)
+ .exists(),
+ ).toBe(true);
+ });
+
+ it('renders gl-dropdown-item components for available projects', async () => {
+ wrapper.setData({
+ projects: mockProjects,
+ selectedProject: mockProjects[0],
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const dropdownItems = wrapper.findAll(GlDropdownItem);
+
+ expect(dropdownItems).toHaveLength(mockProjects.length);
+ expect(dropdownItems.at(0).props()).toMatchObject({
+ isCheckItem: true,
+ isChecked: true,
+ });
+ expect(dropdownItems.at(0).text()).toBe(mockProjects[0].name_with_namespace);
+ });
+
+ it('renders string "No matching results" when search does not yield any matches', async () => {
+ wrapper.setData({
+ searchKey: 'foo',
+ });
+
+ // Wait for `searchKey` watcher to run.
+ await wrapper.vm.$nextTick();
+
+ wrapper.setData({
+ projects: [],
+ projectsListLoading: false,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const dropdownContentEl = wrapper.find('[data-testid="content"]');
+
+ expect(dropdownContentEl.text()).toContain('No matching results');
+ });
+
+ it('renders string "Failed to load projects" when loading projects list fails', async () => {
+ wrapper.setData({
+ projects: [],
+ projectsListLoading: false,
+ projectsListLoadFailed: true,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const dropdownContentEl = wrapper.find('[data-testid="content"]');
+
+ expect(dropdownContentEl.text()).toContain('Failed to load projects');
+ });
+
+ it('renders gl-button within footer', async () => {
+ const moveButtonEl = wrapper.find('[data-testid="footer"]').find(GlButton);
+
+ expect(moveButtonEl.text()).toBe('Move');
+ expect(moveButtonEl.attributes('disabled')).toBe('true');
+
+ wrapper.setData({
+ selectedProject: mockProjects[0],
+ });
+
+ await wrapper.vm.$nextTick();
+
+ expect(
+ wrapper
+ .find('[data-testid="footer"]')
+ .find(GlButton)
+ .attributes('disabled'),
+ ).not.toBeDefined();
+ });
+ });
+
+ describe('events', () => {
+ it('collapsed state element emits `toggle-collapse` event on component when clicked', () => {
+ wrapper.find('[data-testid="move-collapsed"]').trigger('click');
+
+ expect(wrapper.emitted('toggle-collapse')).toBeTruthy();
+ });
+
+ it('gl-dropdown component calls `fetchProjects` on `shown` event', () => {
+ jest.spyOn(axios, 'get').mockResolvedValue({
+ data: mockProjects,
+ });
+
+ findDropdownEl().vm.$emit('shown');
+
+ expect(axios.get).toHaveBeenCalled();
+ });
+
+ it('gl-dropdown component prevents dropdown body from closing on `hide` event when `projectItemClick` prop is true', async () => {
+ wrapper.setData({
+ projectItemClick: true,
+ });
+
+ findDropdownEl().vm.$emit('hide', mockEvent);
+
+ expect(mockEvent.preventDefault).toHaveBeenCalled();
+ expect(wrapper.vm.projectItemClick).toBe(false);
+ });
+
+ it('gl-dropdown component emits `dropdown-close` event on component from `hide` event', async () => {
+ findDropdownEl().vm.$emit('hide');
+
+ expect(wrapper.emitted('dropdown-close')).toBeTruthy();
+ });
+
+ it('close icon in dropdown header closes the dropdown when clicked', () => {
+ wrapper
+ .find('[data-testid="header"]')
+ .find(GlButton)
+ .vm.$emit('click', mockEvent);
+
+ expect(wrapper.vm.$refs.dropdown.hide).toHaveBeenCalled();
+ });
+
+ it('sets project for clicked gl-dropdown-item to selectedProject', async () => {
+ wrapper.setData({
+ projects: mockProjects,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ wrapper
+ .findAll(GlDropdownItem)
+ .at(0)
+ .vm.$emit('click', mockEvent);
+
+ expect(wrapper.vm.selectedProject).toBe(mockProjects[0]);
+ });
+
+ it('hides dropdown and emits `move-issuable` event when move button is clicked', async () => {
+ wrapper.setData({
+ selectedProject: mockProjects[0],
+ });
+
+ await wrapper.vm.$nextTick();
+
+ wrapper
+ .find('[data-testid="footer"]')
+ .find(GlButton)
+ .vm.$emit('click');
+
+ expect(wrapper.vm.$refs.dropdown.hide).toHaveBeenCalled();
+ expect(wrapper.emitted('move-issuable')).toBeTruthy();
+ expect(wrapper.emitted('move-issuable')[0]).toEqual([mockProjects[0]]);
+ });
+ });
+ });
+});
diff --git a/spec/frontend_integration/ide/__snapshots__/ide_integration_spec.js.snap b/spec/frontend_integration/ide/__snapshots__/ide_integration_spec.js.snap
index 6c120898f01..b84f12df4f6 100644
--- a/spec/frontend_integration/ide/__snapshots__/ide_integration_spec.js.snap
+++ b/spec/frontend_integration/ide/__snapshots__/ide_integration_spec.js.snap
@@ -114,7 +114,7 @@ exports[`WebIDE runs 1`] = `
>
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index f977fe1638f..b09bd9dff1b 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Gitlab::GitalyClient::CommitService do
safe_max_files: 100,
safe_max_lines: 5000,
safe_max_bytes: 512000,
- max_patch_bytes: 102400
+ max_patch_bytes: 204800
)
expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_diff).with(request, kind_of(Hash))
@@ -57,7 +57,7 @@ RSpec.describe Gitlab::GitalyClient::CommitService do
safe_max_files: 100,
safe_max_lines: 5000,
safe_max_bytes: 512000,
- max_patch_bytes: 102400
+ max_patch_bytes: 204800
)
expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_diff).with(request, kind_of(Hash))
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 8b5f74df8f8..e551db3552e 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -105,7 +105,7 @@ RSpec.describe API::Settings, 'Settings' do
enforce_terms: true,
terms: 'Hello world!',
performance_bar_allowed_group_path: group.full_path,
- diff_max_patch_bytes: 150_000,
+ diff_max_patch_bytes: 300_000,
default_branch_protection: ::Gitlab::Access::PROTECTION_DEV_CAN_MERGE,
local_markdown_version: 3,
allow_local_requests_from_web_hooks_and_services: true,
@@ -148,7 +148,7 @@ RSpec.describe API::Settings, 'Settings' do
expect(json_response['enforce_terms']).to be(true)
expect(json_response['terms']).to eq('Hello world!')
expect(json_response['performance_bar_allowed_group_id']).to eq(group.id)
- expect(json_response['diff_max_patch_bytes']).to eq(150_000)
+ expect(json_response['diff_max_patch_bytes']).to eq(300_000)
expect(json_response['default_branch_protection']).to eq(Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
expect(json_response['local_markdown_version']).to eq(3)
expect(json_response['allow_local_requests_from_web_hooks_and_services']).to eq(true)
diff --git a/spec/services/projects/container_repository/delete_tags_service_spec.rb b/spec/services/projects/container_repository/delete_tags_service_spec.rb
index c3ae26b1f05..a012ec29be5 100644
--- a/spec/services/projects/container_repository/delete_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/delete_tags_service_spec.rb
@@ -27,13 +27,17 @@ RSpec.describe Projects::ContainerRepository::DeleteTagsService do
end
end
- RSpec.shared_examples 'logging an error response' do |message: 'could not delete tags'|
+ RSpec.shared_examples 'logging an error response' do |message: 'could not delete tags', extra_log: {}|
it 'logs an error message' do
- expect(service).to receive(:log_error).with(
- service_class: 'Projects::ContainerRepository::DeleteTagsService',
- message: message,
- container_repository_id: repository.id
- )
+ log_data = {
+ service_class: 'Projects::ContainerRepository::DeleteTagsService',
+ message: message,
+ container_repository_id: repository.id
+ }
+
+ log_data.merge!(extra_log) if extra_log.any?
+
+ expect(service).to receive(:log_error).with(log_data)
subject
end
@@ -115,7 +119,7 @@ RSpec.describe Projects::ContainerRepository::DeleteTagsService do
it { is_expected.to include(status: :error, message: 'timeout while deleting tags') }
- it_behaves_like 'logging an error response', message: 'timeout while deleting tags'
+ it_behaves_like 'logging an error response', message: 'timeout while deleting tags', extra_log: { deleted_tags_count: 0 }
end
end
end
diff --git a/spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb b/spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb
index 3bbcec8775e..988971171fc 100644
--- a/spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/gitlab/delete_tags_service_spec.rb
@@ -67,7 +67,7 @@ RSpec.describe Projects::ContainerRepository::Gitlab::DeleteTagsService do
stub_delete_reference_requests('A' => 200)
end
- it { is_expected.to include(status: :error, message: 'timeout while deleting tags') }
+ it { is_expected.to eq(status: :error, message: 'timeout while deleting tags', deleted: ['A']) }
it 'tracks the exception' do
expect(::Gitlab::ErrorTracking)
diff --git a/spec/support/shared_examples/services/alert_management_shared_examples.rb b/spec/support/shared_examples/services/alert_management_shared_examples.rb
index 1ae74979b7a..003705ca21c 100644
--- a/spec/support/shared_examples/services/alert_management_shared_examples.rb
+++ b/spec/support/shared_examples/services/alert_management_shared_examples.rb
@@ -8,11 +8,11 @@ RSpec.shared_examples 'creates an alert management alert' do
end
it 'executes the alert service hooks' do
- slack_service = create(:service, type: 'SlackService', project: project, alert_events: true, active: true)
+ expect_next_instance_of(AlertManagement::Alert) do |alert|
+ expect(alert).to receive(:execute_services)
+ end
subject
-
- expect(ProjectServiceWorker).to have_received(:perform_async).with(slack_service.id, an_instance_of(Hash))
end
end
diff --git a/yarn.lock b/yarn.lock
index d2939cb94c0..1eafecb9c7e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -866,10 +866,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.174.0.tgz#954b4d908a6188a2fcc45f00f748beeb23f054b0"
integrity sha512-CgnZvO2miZkWxANhFdaK+2S4qRgkrMRE3vh3Xxwc+hIV9ki9KavlAAez9MNIs0Um/SJ1UpfmqKoM/dMyZX7K/w==
-"@gitlab/ui@21.41.0":
- version "21.41.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-21.41.0.tgz#185f5a534d6cd038f48588f432a25576d08c5780"
- integrity sha512-Jl0OcEMQ+GKB9wTnZH9rU6YmL3rVDMHkEZc7Sa5QvNvP6A1Se/UEKbzhLi9rdyAoKpvrm3++tYg3ZJklIRZIsg==
+"@gitlab/ui@21.42.0":
+ version "21.42.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-21.42.0.tgz#9cba612a6b0c8ee533865fa0c1e12243ced0c6e2"
+ integrity sha512-1q55KuGozOZ3iQPzE+GD7ChX+BCCe9eYGtaLMrFP6mjtyGDI1v9AHfYqHIqgS3+chaTKWCr8YpJ0PECPaLLM6A==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"