Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-03-27 09:12:50 +00:00
parent 18a5cc115e
commit b7c55d3637
16 changed files with 256 additions and 40 deletions

View File

@ -424,7 +424,7 @@
.es8-services:
services:
- !reference [.zoekt-services, services]
- name: elasticsearch:8.11.4
- name: elasticsearch:8.17.4
.es8-variables:
variables:

View File

@ -723,8 +723,8 @@
{"name":"state_machines","version":"0.5.0","platform":"ruby","checksum":"23e6249d374a920b528dccade403518b4abbd83841a3e2c9ef13e6f1a009b102"},
{"name":"state_machines-activemodel","version":"0.8.0","platform":"ruby","checksum":"e932dab190d4be044fb5f9cab01a3ea0b092c5f113d4676c6c0a0d49bf738d2c"},
{"name":"state_machines-activerecord","version":"0.8.0","platform":"ruby","checksum":"072fb701b8ab03de0608297f6c55dc34ed096e556fa8f77e556f3c461c71aab6"},
{"name":"stringio","version":"3.1.5","platform":"java","checksum":"d1e136540e41c833ba39c0468b212f33755b438517b45bebf5868eec2c9422a7"},
{"name":"stringio","version":"3.1.5","platform":"ruby","checksum":"bca92461515a131535743bc81d5559fa1de7d80cff9a654d6c0af6f9f27e35c8"},
{"name":"stringio","version":"3.1.6","platform":"java","checksum":"dbdb1ee4e6d75782bbc7e8cc7d84cd05e592df50494f363011cc7cd48153bbf7"},
{"name":"stringio","version":"3.1.6","platform":"ruby","checksum":"292c495d1657adfcdf0a32eecf12a60e6691317a500c3112ad3b2e31068274f5"},
{"name":"strings","version":"0.2.1","platform":"ruby","checksum":"933293b3c95cf85b81eb44b3cf673e3087661ba739bbadfeadf442083158d6fb"},
{"name":"strings-ansi","version":"0.2.0","platform":"ruby","checksum":"90262d760ea4a94cc2ae8d58205277a343409c288cbe7c29416b1826bd511c88"},
{"name":"swd","version":"2.0.3","platform":"ruby","checksum":"4cdbe2a4246c19f093fce22e967ec3ebdd4657d37673672e621bf0c7eb770655"},

View File

@ -1857,7 +1857,7 @@ GEM
state_machines-activerecord (0.8.0)
activerecord (>= 5.1)
state_machines-activemodel (>= 0.8.0)
stringio (3.1.5)
stringio (3.1.6)
strings (0.2.1)
strings-ansi (~> 0.2)
unicode-display_width (>= 1.5, < 3.0)

View File

@ -28,6 +28,12 @@ import {
getNextPageParams,
getPreviousPageParams,
} from '~/packages_and_registries/shared/utils';
import PageSizeSelector from '~/vue_shared/components/page_size_selector.vue';
import { getStorageValue, saveStorageValue } from '~/lib/utils/local_storage';
import { mergeUrlParams, updateHistory } from '~/lib/utils/url_utility';
import { smoothScrollTop } from '~/behaviors/smooth_scroll';
const PAGE_SIZE_KEY = 'packages_page_size';
export default {
components: {
@ -41,6 +47,7 @@ export default {
PackageSearch,
PersistedPagination,
DeletePackages,
PageSizeSelector,
},
directives: {
GlTooltip: GlTooltipDirective,
@ -53,6 +60,7 @@ export default {
filters: {},
isDeleteInProgress: false,
pageParams: {},
pageSize: GRAPHQL_PAGE_SIZE,
groupSettings: {},
};
},
@ -101,7 +109,7 @@ export default {
fullPath: this.fullPath,
sort: this.isGroupPage ? undefined : this.sort,
groupSort: this.isGroupPage ? this.sort : undefined,
first: GRAPHQL_PAGE_SIZE,
first: this.pageSize,
...this.packageParams,
...this.pageParams,
};
@ -160,6 +168,14 @@ export default {
];
},
},
created() {
const localStoragePageSize = getStorageValue(PAGE_SIZE_KEY);
if (localStoragePageSize.exists) {
this.pageSize = localStoragePageSize.value;
} else {
this.savePageSizeToLocalStorage(this.pageSize);
}
},
mounted() {
this.checkDeleteAlert();
},
@ -173,16 +189,35 @@ export default {
historyReplaceState(cleanUrl);
}
},
handlePageSizeChange(value) {
this.pageSize = value;
this.savePageSizeToLocalStorage(value);
this.pageParams = {
after: undefined,
before: undefined,
};
const url = mergeUrlParams(this.pageParams, window.location.search, { spreadArrays: true });
updateHistory({
url,
});
smoothScrollTop();
},
handleSearchUpdate({ sort, filters, pageInfo }) {
this.pageParams = getPageParams(pageInfo, GRAPHQL_PAGE_SIZE);
this.pageParams = getPageParams(pageInfo, this.pageSize);
this.sort = sort;
this.filters = { ...filters };
},
fetchNextPage() {
this.pageParams = getNextPageParams(this.pageInfo.endCursor, GRAPHQL_PAGE_SIZE);
this.pageParams = getNextPageParams(this.pageInfo.endCursor, this.pageSize);
smoothScrollTop();
},
fetchPreviousPage() {
this.pageParams = getPreviousPageParams(this.pageInfo.startCursor, GRAPHQL_PAGE_SIZE);
this.pageParams = getPreviousPageParams(this.pageInfo.startCursor, this.pageSize);
smoothScrollTop();
},
savePageSizeToLocalStorage(value) {
saveStorageValue(PAGE_SIZE_KEY, value);
},
},
i18n: {
@ -259,6 +294,12 @@ export default {
@prev="fetchPreviousPage"
@next="fetchNextPage"
/>
<page-size-selector
v-if="packagesCount"
:value="pageSize"
class="gl-relative gl-right-0 md:gl-absolute"
@input="handlePageSizeChange"
/>
</div>
</div>
</template>

View File

@ -117,7 +117,7 @@ export const ACTION_TYPES = [
},
{
id: '2',
value: TODO_ACTION_TYPE_MENTIONED,
value: `${TODO_ACTION_TYPE_MENTIONED};${TODO_ACTION_TYPE_DIRECTLY_ADDRESSED}`,
title: s__('Todos|Mentioned'),
},
{
@ -140,11 +140,6 @@ export const ACTION_TYPES = [
value: TODO_ACTION_TYPE_UNMERGEABLE,
title: s__('Todos|Unmergeable'),
},
{
id: '7',
value: TODO_ACTION_TYPE_DIRECTLY_ADDRESSED,
title: s__('Todos|Directly addressed'),
},
{
id: '8',
value: TODO_ACTION_TYPE_MERGE_TRAIN_REMOVED,
@ -242,7 +237,11 @@ const FILTERS = [
return value;
},
toUrlValueResolver: (value) => {
const { id } = ACTION_TYPES.find((option) => option.value === value);
const { id } = ACTION_TYPES.find((option) => {
// For combined values like "mentioned;directly_addressed" use their first value's id for the URL
const optionMainValue = option.value.split(';')[0];
return optionMainValue === value;
});
return id;
},
},
@ -341,7 +340,7 @@ export default {
return Object.fromEntries(
FILTERS.map(({ apiParam, tokenType }) => {
const selectedValue = this.filterTokens.find((token) => token.type === tokenType);
return [apiParam, selectedValue ? [selectedValue.value.data] : []];
return [apiParam, selectedValue ? selectedValue.value.data.split(';') : []];
}),
);
},

View File

@ -8,14 +8,6 @@ description: Join table between Findings and Identifiers
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6896
milestone: '11.4'
gitlab_schema: gitlab_sec
desired_sharding_key:
project_id:
references: projects
backfill_via:
parent:
foreign_key: occurrence_id
table: vulnerability_occurrences
sharding_key: project_id
belongs_to: finding
desired_sharding_key_migration_job_name: BackfillVulnerabilityOccurrenceIdentifiersProjectId
sharding_key:
project_id: projects
table_size: small

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddVulnerabilityOccurrenceIdentifiersProjectIdIndex < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.11'
INDEX_NAME = 'index_vulnerability_occurrence_identifiers_on_project_id'
def up
add_concurrent_index :vulnerability_occurrence_identifiers, :project_id, name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :vulnerability_occurrence_identifiers, INDEX_NAME
end
end

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
class AddVulnerabilityOccurrenceIdentifiersProjectIdNotNull < Gitlab::Database::Migration[2.2]
milestone '17.11'
disable_ddl_transaction!
def up
add_not_null_constraint :vulnerability_occurrence_identifiers, :project_id
end
def down
remove_not_null_constraint :vulnerability_occurrence_identifiers, :project_id
end
end

View File

@ -0,0 +1 @@
e2701c135af52f28a94c794bd2c21f0100ff6f25590a9a7eba7b99185a5578e5

View File

@ -0,0 +1 @@
1f339cff03af736fb77b4953f27e9c00d898eb789a483e30fbe0dbc73c17e7f5

View File

@ -24918,7 +24918,8 @@ CREATE TABLE vulnerability_occurrence_identifiers (
updated_at timestamp with time zone NOT NULL,
occurrence_id bigint NOT NULL,
identifier_id bigint NOT NULL,
project_id bigint
project_id bigint,
CONSTRAINT check_67fe772bae CHECK ((project_id IS NOT NULL))
);
CREATE SEQUENCE vulnerability_occurrence_identifiers_id_seq
@ -37514,6 +37515,8 @@ CREATE INDEX index_vulnerability_merge_request_links_on_project_id ON vulnerabil
CREATE INDEX index_vulnerability_occurrence_identifiers_on_identifier_id ON vulnerability_occurrence_identifiers USING btree (identifier_id);
CREATE INDEX index_vulnerability_occurrence_identifiers_on_project_id ON vulnerability_occurrence_identifiers USING btree (project_id);
CREATE UNIQUE INDEX index_vulnerability_occurrence_identifiers_on_unique_keys ON vulnerability_occurrence_identifiers USING btree (occurrence_id, identifier_id);
CREATE INDEX index_vulnerability_occurrences_for_override_uuids_logic ON vulnerability_occurrences USING btree (project_id, report_type, location_fingerprint);

View File

@ -72,13 +72,39 @@ Prerequisites:
- You must have administrator access to the instance.
Indexing performance depends on the CPU and memory limits on the Zoekt indexer nodes.
To check indexing status, in the Rails console, run the following command:
To check indexing status:
```ruby
Search::Zoekt::Index.group(:state).count
Search::Zoekt::Repository.group(:state).count
Search::Zoekt::Task.group(:state).count
```
{{< tabs >}}
{{< tab title="GitLab 17.10 and later" >}}
Run this Rake task:
```shell
gitlab-rake gitlab:zoekt:info
```
To have the data refresh automatically every 10 seconds, run this task instead:
```shell
gitlab-rake "gitlab:zoekt:info[10]"
```
{{< /tab >}}
{{< tab title="GitLab 17.9 and earlier" >}}
In a [Rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session), run these commands:
```ruby
Search::Zoekt::Index.group(:state).count
Search::Zoekt::Repository.group(:state).count
Search::Zoekt::Task.group(:state).count
```
{{< /tab >}}
{{< /tabs >}}
## Delete offline nodes automatically
@ -225,7 +251,7 @@ To resolve this issue, ensure Silent Mode is disabled.
In `application_json.log`, you might get the following error:
```plaintext
connections to all backends failing; last error: UNKNOWN: ipv4:1.2.3.4:5678: Trying to connect an http1.x server
connections to all backends failing; last error: UNKNOWN: ipv4:1.2.3.4:5678: Trying to connect an http1.x server
```
To resolve this issue, check if you're using any proxies.

View File

@ -61489,9 +61489,6 @@ msgstr ""
msgid "Todos|Design"
msgstr ""
msgid "Todos|Directly addressed"
msgstr ""
msgid "Todos|Done"
msgstr ""

View File

@ -6,7 +6,11 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import setWindowLocation from 'helpers/set_window_location_helper';
import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants';
import * as urlUtility from '~/lib/utils/url_utility';
import { smoothScrollTop } from '~/behaviors/smooth_scroll';
import ListPage from '~/packages_and_registries/package_registry/pages/list.vue';
import PackageTitle from '~/packages_and_registries/package_registry/components/list/package_title.vue';
import PackageSearch from '~/packages_and_registries/package_registry/components/list/package_search.vue';
@ -19,6 +23,7 @@ import {
PACKAGE_HELP_URL,
} from '~/packages_and_registries/package_registry/constants';
import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue';
import PageSizeSelector from '~/vue_shared/components/page_size_selector.vue';
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
import getGroupPackageSettings from '~/packages_and_registries/package_registry/graphql/queries/get_group_package_settings.query.graphql';
import destroyPackagesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql';
@ -31,8 +36,10 @@ import {
} from '../mock_data';
jest.mock('~/alert');
jest.mock('~/behaviors/smooth_scroll');
describe('PackagesListApp', () => {
useLocalStorageSpy();
let wrapper;
let apolloProvider;
@ -69,6 +76,7 @@ describe('PackagesListApp', () => {
const findDeletePackages = () => wrapper.findComponent(DeletePackages);
const findSettingsLink = () => wrapper.findComponent(GlButton);
const findPagination = () => wrapper.findComponent(PersistedPagination);
const findPageSizeSelector = () => wrapper.findComponent(PageSizeSelector);
const mountComponent = ({
resolver = jest.fn().mockResolvedValue(packagesListQuery()),
@ -118,14 +126,96 @@ describe('PackagesListApp', () => {
});
it('has persisted pagination', async () => {
const resolver = jest.fn().mockResolvedValue(packagesListQuery());
mountComponent({ resolver });
mountComponent();
await waitForFirstRequest();
expect(findPagination().props('pagination')).toEqual(pagination());
});
describe('page size', () => {
const resolver = jest.fn().mockResolvedValue(packagesListQuery());
describe('when local storage value is not set', () => {
beforeEach(async () => {
mountComponent({ resolver });
await waitForFirstRequest();
});
it('page size selector prop is set to default value', () => {
expect(findPageSizeSelector().props('value')).toBe(GRAPHQL_PAGE_SIZE);
});
it('sets local storage value', () => {
expect(localStorage.getItem('packages_page_size')).toBe(String(GRAPHQL_PAGE_SIZE));
});
it('calls the resolver with default page size', () => {
expect(resolver).toHaveBeenCalledWith({
first: 20,
fullPath: 'gitlab-org',
groupSort: 'NAME_DESC',
isGroupPage: true,
});
});
});
describe('when localstorage value is set', () => {
beforeEach(async () => {
localStorage.setItem('packages_page_size', '50');
mountComponent({ resolver });
await waitForFirstRequest();
});
it('page size selector prop is set to value from local storage', () => {
expect(findPageSizeSelector().props('value')).toBe(50);
});
it('calls the resolver with page size value from local storage', () => {
expect(resolver).toHaveBeenCalledWith({
first: 50,
fullPath: 'gitlab-org',
groupSort: 'NAME_DESC',
isGroupPage: true,
});
});
});
describe('is changed', () => {
beforeEach(async () => {
setWindowLocation('?before=123&name=test');
jest.spyOn(urlUtility, 'updateHistory');
mountComponent({ resolver });
await waitForFirstRequest();
await findPageSizeSelector().vm.$emit('input', 100);
});
it('sets local storage value', () => {
expect(localStorage.getItem('packages_page_size')).toBe(String(100));
});
it('calls the resolver with default page size', () => {
expect(resolver).toHaveBeenLastCalledWith({
first: 100,
fullPath: 'gitlab-org',
groupSort: 'NAME_DESC',
isGroupPage: true,
});
});
it('updates query params', () => {
expect(urlUtility.updateHistory).toHaveBeenCalledWith({
url: '?name=test',
});
});
it('scrolls to top of page', () => {
expect(smoothScrollTop).toHaveBeenCalledTimes(1);
});
});
});
it('has a package title', async () => {
mountComponent();
@ -257,6 +347,7 @@ describe('PackagesListApp', () => {
expect(resolver).toHaveBeenCalledWith(
expect.objectContaining({ after: pagination().endCursor, first: GRAPHQL_PAGE_SIZE }),
);
expect(smoothScrollTop).toHaveBeenCalledTimes(1);
});
it('when pagination emits prev event fetches the prev set of records', async () => {
@ -270,6 +361,7 @@ describe('PackagesListApp', () => {
last: GRAPHQL_PAGE_SIZE,
}),
);
expect(smoothScrollTop).toHaveBeenCalledTimes(1);
});
});
@ -400,6 +492,10 @@ describe('PackagesListApp', () => {
it('does not request for group package settings', () => {
expect(groupPackageSettingsResolver).not.toHaveBeenCalled();
});
it('does not render page size selector', () => {
expect(findPageSizeSelector().exists()).toBe(false);
});
});
describe('filter without results', () => {

View File

@ -245,6 +245,25 @@ describe('TodosFilterBar', () => {
expect(trackingSpy).toHaveBeenCalledTimes(2);
});
it('handles combined action types with semicolon delimiter', () => {
createComponent();
const combinedActionValue = `mentioned;directly_addressed`;
findGlFilteredSearch().vm.$emit(
'input',
generateFilterTokens({
action: combinedActionValue,
}),
);
findGlFilteredSearch().vm.$emit('submit');
expect(wrapper.emitted('filters-changed')[0][0].action).toEqual([
'mentioned',
'directly_addressed',
]);
expect(window.location.search).toBe('?action_id=2');
});
it('shows a warning message when trying to text-search and only submits the supported filter tokens', async () => {
createComponent();
expect(findGlAlert().exists()).toBe(false);
@ -404,5 +423,15 @@ describe('TodosFilterBar', () => {
expect(wrapper.emitted('filters-changed')).toBeUndefined();
});
it('resolves URL action_id to the first value in combined actions', () => {
setWindowLocation('?action_id=2');
createComponent();
expect(wrapper.emitted('filters-changed')[0][0].action).toEqual([
'mentioned',
'directly_addressed',
]);
});
});
});

View File

@ -100,6 +100,7 @@ RSpec.describe 'new tables missing sharding_key', feature_category: :cell do
'dast_profiles_pipelines.project_id', # LFK already present on dast_profiles and will cascade delete
'dast_scanner_profiles_builds.project_id', # LFK already present on dast_scanner_profiles and will cascade delete
'vulnerability_finding_links.project_id', # LFK already present on vulnerability_occurrence with cascade delete
'vulnerability_occurrence_identifiers.project_id', # LFK present on vulnerability_occurrence with cascade delete
'secret_detection_token_statuses.project_id',
# LFK already present on vulnerability_occurrence with cascade delete.
'ldap_group_links.group_id',