Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-03-06 15:10:20 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-03-06 15:10:20 +0300
commit9ad806210531e19c851a69cbcdaf9ed8bd6cb478 (patch)
tree348438fb6eb4219841571786b0826736d1d3e016
parent4903f95b04db58edc1931ec917d2313c916a06b2 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/issues/list/utils.js36
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue2
-rw-r--r--app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue19
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js3
-rw-r--r--app/views/notify/unknown_sign_in_email.html.haml5
-rw-r--r--app/views/notify/unknown_sign_in_email.text.haml2
-rw-r--r--app/workers/gitlab_service_ping_worker.rb2
-rw-r--r--db/migrate/20230303144424_unique_index_on_catalog_resources_project.rb17
-rw-r--r--db/schema_migrations/202303031444241
-rw-r--r--db/structure.sql2
-rw-r--r--doc/security/user_file_uploads.md24
-rw-r--r--doc/user/clusters/agent/gitops/flux_tutorial.md2
-rw-r--r--lib/gitlab/analytics/cycle_analytics/request_params.rb10
-rw-r--r--lib/tasks/gitlab/db.rake1
-rw-r--r--locale/gitlab.pot6
-rw-r--r--qa/Gemfile2
-rw-r--r--qa/Gemfile.lock5
-rw-r--r--spec/frontend/contributors/component/contributors_spec.js5
-rw-r--r--spec/frontend/issues/new/components/title_suggestions_spec.js123
-rw-r--r--spec/frontend/issues/new/mock_data.js64
-rw-r--r--spec/frontend/monitoring/components/variables/dropdown_field_spec.js6
-rw-r--r--spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js22
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb5
-rw-r--r--spec/mailers/emails/profile_spec.rb7
-rw-r--r--spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb2
-rw-r--r--spec/tasks/gitlab/db_rake_spec.rb9
29 files changed, 246 insertions, 142 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index c9439b8889d..3970647ecc2 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-27c00fa0b260e976c5d6c0382ea850949cb51d63
+f99ae76f9fecec6c162dbd990845ba9c7c5727d6
diff --git a/app/assets/javascripts/issues/list/utils.js b/app/assets/javascripts/issues/list/utils.js
index bbd081843ca..281e48d9aa7 100644
--- a/app/assets/javascripts/issues/list/utils.js
+++ b/app/assets/javascripts/issues/list/utils.js
@@ -289,9 +289,9 @@ const formatData = (token) => {
};
export const convertToApiParams = (filterTokens) => {
- const params = {};
- const not = {};
- const or = {};
+ const params = new Map();
+ const not = new Map();
+ const or = new Map();
filterTokens
.filter((token) => token.type !== FILTERED_SEARCH_TERM)
@@ -307,32 +307,34 @@ export const convertToApiParams = (filterTokens) => {
obj = params;
}
const data = formatData(token);
- Object.assign(obj, {
- [apiField]: obj[apiField] ? [obj[apiField], data].flat() : data,
- });
+ obj.set(apiField, obj.has(apiField) ? [obj.get(apiField), data].flat() : data);
});
- if (Object.keys(not).length) {
- Object.assign(params, { not });
+ if (not.size) {
+ params.set('not', Object.fromEntries(not));
}
- if (Object.keys(or).length) {
- Object.assign(params, { or });
+ if (or.size) {
+ params.set('or', Object.fromEntries(or));
}
- return params;
+ return Object.fromEntries(params);
};
-export const convertToUrlParams = (filterTokens) =>
- filterTokens
+export const convertToUrlParams = (filterTokens) => {
+ const urlParamsMap = filterTokens
.filter((token) => token.type !== FILTERED_SEARCH_TERM)
.reduce((acc, token) => {
const filterType = getFilterType(token);
const urlParam = filters[token.type][URL_PARAM][token.value.operator]?.[filterType];
- return Object.assign(acc, {
- [urlParam]: acc[urlParam] ? [acc[urlParam], token.value.data].flat() : token.value.data,
- });
- }, {});
+ return acc.set(
+ urlParam,
+ acc.has(urlParam) ? [acc.get(urlParam), token.value.data].flat() : token.value.data,
+ );
+ }, new Map());
+
+ return Object.fromEntries(urlParamsMap);
+};
export const convertToSearchQuery = (filterTokens) =>
filterTokens
diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue
index 4af8cf1ded3..b289229af69 100644
--- a/app/assets/javascripts/notes/components/note_header.vue
+++ b/app/assets/javascripts/notes/components/note_header.vue
@@ -85,7 +85,7 @@ export default {
return this.expanded ? 'chevron-up' : 'chevron-down';
},
noteTimestampLink() {
- return this.noteId ? `#note_${this.noteId}` : undefined;
+ return this.noteId ? `#note_${getIdFromGraphQLId(this.noteId)}` : undefined;
},
hasAuthor() {
return this.author && Object.keys(this.author).length;
diff --git a/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue
index 1114a0942ec..53dad19028d 100644
--- a/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue
+++ b/app/assets/javascripts/repository/components/blob_viewers/notebook_viewer.vue
@@ -1,11 +1,15 @@
<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import notebookLoader from '~/blob/notebook';
import { stripPathTail } from '~/lib/utils/url_utility';
+import NotebookViewer from '~/blob/notebook/notebook_viewer.vue';
export default {
- components: {
- GlLoadingIcon,
+ components: { NotebookViewer },
+ provide() {
+ // `relativeRawPath` is injected in app/assets/javascripts/notebook/cells/markdown.vue
+ // It is needed for images in Markdown cells that reference local files to work.
+ // See the following MR for more context:
+ // https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69075
+ return { relativeRawPath: stripPathTail(this.url) };
},
props: {
blob: {
@@ -18,14 +22,9 @@ export default {
url: this.blob.rawPath,
};
},
- mounted() {
- notebookLoader({ el: this.$refs.viewer, relativeRawPath: stripPathTail(this.url) });
- },
};
</script>
<template>
- <div ref="viewer" :data-endpoint="url" data-testid="notebook">
- <gl-loading-icon class="gl-my-4" size="lg" />
- </div>
+ <notebook-viewer :endpoint="url" />
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue b/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue
index 917ed259dd0..f2ec8f589ce 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/action_buttons.vue
@@ -142,7 +142,7 @@ export default {
:title="setTooltip(btn)"
:href="btn.href"
:target="btn.target"
- :class="[{ 'gl-mr-3': index !== tertiaryButtons.length - 1 }, btn.class]"
+ :class="[{ 'gl-mr-1': index !== tertiaryButtons.length - 1 }, btn.class]"
:data-clipboard-text="btn.dataClipboardText"
:data-qa-selector="actionButtonQaSelector(btn)"
:data-method="btn.dataMethod"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
index c762922d890..b192ccfa379 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
@@ -31,7 +31,7 @@ export default {
};
</script>
<template>
- <h4 class="js-mr-widget-author">
+ <h4 class="js-mr-widget-author gl-flex-grow-1">
{{ actionText }}
<mr-widget-author :author="author" />
<span class="sr-only">{{ dateReadable }} ({{ dateTitle }})</span>
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 827080d9866..13009651550 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -294,6 +294,9 @@ export default class MergeRequestStore {
// Security reports
this.sastComparisonPath = data.sast_comparison_path;
this.secretDetectionComparisonPath = data.secret_detection_comparison_path;
+
+ this.sastComparisonPathV2 = data.new_sast_comparison_path;
+ this.secretDetectionComparisonPathV2 = data.new_secret_detection_comparison_path;
}
get isNothingToMergeState() {
diff --git a/app/views/notify/unknown_sign_in_email.html.haml b/app/views/notify/unknown_sign_in_email.html.haml
index f8a0ae1352c..e252af78060 100644
--- a/app/views/notify/unknown_sign_in_email.html.haml
+++ b/app/views/notify/unknown_sign_in_email.html.haml
@@ -24,6 +24,11 @@
= Gitlab.config.gitlab.host
%tr
%td{ style: "#{default_style}border-top:1px solid #ededed;" }
+ = _('User')
+ %td{ style: "#{default_style}color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" }
+ #{sanitize_name(@user.name)} (#{@user.username})
+ %tr
+ %td{ style: "#{default_style}border-top:1px solid #ededed;" }
= _('IP Address')
%td{ style: "#{default_style}color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" }
%span.muted{ style: "color:#333333;text-decoration:none;" }
diff --git a/app/views/notify/unknown_sign_in_email.text.haml b/app/views/notify/unknown_sign_in_email.text.haml
index f3e318f0d15..fbe35c502da 100644
--- a/app/views/notify/unknown_sign_in_email.text.haml
+++ b/app/views/notify/unknown_sign_in_email.text.haml
@@ -1,4 +1,4 @@
-= _('Hi %{username}!') % { username: sanitize_name(@user.name) }
+= _('Hi %{user_name} (%{user_username})!') % { user_name: sanitize_name(@user.name), user_username: @user.username }
= _('A sign-in to your account has been made from the following IP address: %{ip}') % { ip: @ip }
diff --git a/app/workers/gitlab_service_ping_worker.rb b/app/workers/gitlab_service_ping_worker.rb
index b02e7318585..53a4361fb48 100644
--- a/app/workers/gitlab_service_ping_worker.rb
+++ b/app/workers/gitlab_service_ping_worker.rb
@@ -52,3 +52,5 @@ class GitlabServicePingWorker # rubocop:disable Scalability/IdempotentWorker
nil
end
end
+
+GitlabServicePingWorker.prepend_mod
diff --git a/db/migrate/20230303144424_unique_index_on_catalog_resources_project.rb b/db/migrate/20230303144424_unique_index_on_catalog_resources_project.rb
new file mode 100644
index 00000000000..6ac2e72616a
--- /dev/null
+++ b/db/migrate/20230303144424_unique_index_on_catalog_resources_project.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class UniqueIndexOnCatalogResourcesProject < Gitlab::Database::Migration[2.1]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_catalog_resources_on_project_id'
+
+ def up
+ remove_concurrent_index :catalog_resources, :project_id, name: INDEX_NAME
+ add_concurrent_index :catalog_resources, :project_id, unique: true, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index :catalog_resources, :project_id, name: INDEX_NAME
+ add_concurrent_index :catalog_resources, :project_id, name: INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20230303144424 b/db/schema_migrations/20230303144424
new file mode 100644
index 00000000000..f0684710508
--- /dev/null
+++ b/db/schema_migrations/20230303144424
@@ -0,0 +1 @@
+c8ea35db8903fb627b3ed68b9d9a1e78c34ab40a5aed6fe19e329d13e371f652 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index ceddf2a82a5..64beb9476f9 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -29397,7 +29397,7 @@ CREATE INDEX index_bulk_import_failures_on_correlation_id_value ON bulk_import_f
CREATE INDEX index_bulk_imports_on_user_id ON bulk_imports USING btree (user_id);
-CREATE INDEX index_catalog_resources_on_project_id ON catalog_resources USING btree (project_id);
+CREATE UNIQUE INDEX index_catalog_resources_on_project_id ON catalog_resources USING btree (project_id);
CREATE INDEX index_chat_names_on_team_id_and_chat_id ON chat_names USING btree (team_id, chat_id);
diff --git a/doc/security/user_file_uploads.md b/doc/security/user_file_uploads.md
index db2948a8bd5..80f4b1a8a2a 100644
--- a/doc/security/user_file_uploads.md
+++ b/doc/security/user_file_uploads.md
@@ -45,6 +45,30 @@ To configure authentication settings for all media files:
1. Scroll to **Project visibility** and select **Require authentication to view media files**.
You cannot select this option for projects with **Public** visibility.
+## Delete uploaded files
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92791) in GitLab 15.3.
+
+You should delete an uploaded file when that file contains sensitive or confidential information. When you have deleted that file, users cannot access the file and the direct URL returns a 404 error.
+
+Project Owners and Maintainers can use the [interactive GraphiQL explorer](../api/graphql/index.md#graphiql) to access a [GraphQL endpoint](../api/graphql/reference/index.md#mutationuploaddelete) and delete an uploaded file.
+
+For example:
+
+```graphql
+mutation{
+ uploadDelete(input: { projectPath: "<path/to/project>", secret: "<32-character-id>" , filename: "<filename>" }) {
+ upload {
+ id
+ size
+ path
+ }
+ errors
+ }
+}
+```
+
+Project members that do not have the Owner or Maintainer role cannot access this GraphQL endpoint.
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/clusters/agent/gitops/flux_tutorial.md b/doc/user/clusters/agent/gitops/flux_tutorial.md
index b3d71e66dea..3c30e466110 100644
--- a/doc/user/clusters/agent/gitops/flux_tutorial.md
+++ b/doc/user/clusters/agent/gitops/flux_tutorial.md
@@ -112,7 +112,7 @@ spec:
Congratulations! You now have a manifest repository, a deploy token, and a secret generated directly on your cluster.
-### Configure Flux to sync your manifests
+## Configure Flux to sync your manifests
Next, tell `flux-config` to sync with the `web-app-manifests` repository.
diff --git a/lib/gitlab/analytics/cycle_analytics/request_params.rb b/lib/gitlab/analytics/cycle_analytics/request_params.rb
index 6452739afd3..3e70d64fea6 100644
--- a/lib/gitlab/analytics/cycle_analytics/request_params.rb
+++ b/lib/gitlab/analytics/cycle_analytics/request_params.rb
@@ -92,7 +92,7 @@ module Gitlab
attrs[:direction] = direction if direction.present?
attrs[:stage] = stage_data_attributes.to_json if stage_id.present?
attrs[:namespace] = namespace_attributes
- attrs[:enable_tasks_by_type_chart] = false
+ attrs[:enable_tasks_by_type_chart] = 'false'
attrs[:default_stages] = Gitlab::Analytics::CycleAnalytics::DefaultStages.all.map do |stage_params|
::Analytics::CycleAnalytics::StagePresenter.new(stage_params)
end.to_json
@@ -141,13 +141,11 @@ module Gitlab
end
def namespace_attributes
- container = project || namespace
- return {} unless container
+ return {} unless project
{
- name: container.name,
- full_path: container.full_path,
- avatar_url: container.avatar_url
+ name: project.name,
+ full_path: project.full_path
}
end
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index 5a67e6cfa8c..375005c678d 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -476,6 +476,7 @@ namespace :gitlab do
.reject(&:abstract_class)
.reject { |c| c.name =~ /^(?:EE::)?Gitlab::(?:BackgroundMigration|DatabaseImporters)::/ }
.reject { |c| c.name =~ /^HABTM_/ }
+ .reject { |c| c < Gitlab::Database::Migration[1.0]::MigrationRecord }
.each { |c| classes[c.table_name] << c.name if classes.has_key?(c.table_name) }
sources.each do |source_name|
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index b25f604a78f..bd2521d60c4 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -20923,6 +20923,9 @@ msgstr ""
msgid "Helps reduce request volume for protected paths."
msgstr ""
+msgid "Hi %{user_name} (%{user_username})!"
+msgstr ""
+
msgid "Hi %{username}!"
msgstr ""
@@ -32873,6 +32876,9 @@ msgstr ""
msgid "ProductAnalytics|Viewport"
msgstr ""
+msgid "ProductAnalytics|Visualization Designer"
+msgstr ""
+
msgid "ProductAnalytics|Visualization Type"
msgstr ""
diff --git a/qa/Gemfile b/qa/Gemfile
index 3201d6d1b17..28eb54c8160 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -2,7 +2,7 @@
source 'https://rubygems.org'
-gem 'gitlab-qa', '~> 9', '>= 9.1.0', require: 'gitlab/qa'
+gem 'gitlab-qa', '~> 9', '>= 9.1.1', require: 'gitlab/qa'
gem 'activesupport', '~> 6.1.7.2' # This should stay in sync with the root's Gemfile
gem 'allure-rspec', '~> 2.20.0'
gem 'capybara', '~> 3.38.0'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 52ac2d75708..a5d8b1b0f35 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -102,11 +102,12 @@ GEM
gitlab (4.18.0)
httparty (~> 0.18)
terminal-table (>= 1.5.1)
- gitlab-qa (9.1.0)
+ gitlab-qa (9.1.1)
activesupport (~> 6.1)
gitlab (~> 4.18.0)
http (~> 5.0)
nokogiri (~> 1.10)
+ parallel (>= 1, < 2)
rainbow (>= 3, < 4)
table_print (= 1.5.7)
zeitwerk (>= 2, < 3)
@@ -317,7 +318,7 @@ DEPENDENCIES
faraday-retry (~> 2.1)
fog-core (= 2.1.0)
fog-google (~> 1.19)
- gitlab-qa (~> 9, >= 9.1.0)
+ gitlab-qa (~> 9, >= 9.1.1)
influxdb-client (~> 2.9)
knapsack (~> 4.0)
nokogiri (~> 1.14, >= 1.14.2)
diff --git a/spec/frontend/contributors/component/contributors_spec.js b/spec/frontend/contributors/component/contributors_spec.js
index 03b1e977548..9f5c7e11644 100644
--- a/spec/frontend/contributors/component/contributors_spec.js
+++ b/spec/frontend/contributors/component/contributors_spec.js
@@ -1,5 +1,5 @@
import MockAdapter from 'axios-mock-adapter';
-import Vue, { nextTick } from 'vue';
+import { nextTick } from 'vue';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import ContributorsCharts from '~/contributors/components/contributors.vue';
import { createStore } from '~/contributors/stores';
@@ -16,7 +16,6 @@ jest.mock('~/lib/utils/url_utility', () => ({
let wrapper;
let mock;
let store;
-const Component = Vue.extend(ContributorsCharts);
const endpoint = 'contributors/-/graphs';
const branch = 'main';
const chartData = [
@@ -32,7 +31,7 @@ function factory() {
mock.onGet().reply(HTTP_STATUS_OK, chartData);
store = createStore();
- wrapper = mountExtended(Component, {
+ wrapper = mountExtended(ContributorsCharts, {
propsData: {
endpoint,
branch,
diff --git a/spec/frontend/issues/new/components/title_suggestions_spec.js b/spec/frontend/issues/new/components/title_suggestions_spec.js
index 1cd6576967a..343bdbba301 100644
--- a/spec/frontend/issues/new/components/title_suggestions_spec.js
+++ b/spec/frontend/issues/new/components/title_suggestions_spec.js
@@ -1,106 +1,95 @@
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import TitleSuggestions from '~/issues/new/components/title_suggestions.vue';
import TitleSuggestionsItem from '~/issues/new/components/title_suggestions_item.vue';
+import getIssueSuggestionsQuery from '~/issues/new/queries/issues.query.graphql';
+import { mockIssueSuggestionResponse } from '../mock_data';
+
+Vue.use(VueApollo);
+
+const MOCK_PROJECT_PATH = 'project';
+const MOCK_ISSUES_COUNT = mockIssueSuggestionResponse.data.project.issues.edges.length;
describe('Issue title suggestions component', () => {
let wrapper;
+ let mockApollo;
+
+ function createComponent({
+ search = 'search',
+ queryResponse = jest.fn().mockResolvedValue(mockIssueSuggestionResponse),
+ } = {}) {
+ mockApollo = createMockApollo([[getIssueSuggestionsQuery, queryResponse]]);
- function createComponent(search = 'search') {
wrapper = shallowMount(TitleSuggestions, {
propsData: {
search,
- projectPath: 'project',
+ projectPath: MOCK_PROJECT_PATH,
},
+ apolloProvider: mockApollo,
});
}
- beforeEach(() => {
- createComponent();
- });
+ const waitForDebounce = () => {
+ jest.runOnlyPendingTimers();
+ return waitForPromises();
+ };
afterEach(() => {
- wrapper.destroy();
+ mockApollo = null;
});
it('does not render with empty search', async () => {
- wrapper.setProps({ search: '' });
+ createComponent({ search: '' });
+ await waitForDebounce();
- await nextTick();
expect(wrapper.isVisible()).toBe(false);
});
- describe('with data', () => {
- let data;
-
- beforeEach(() => {
- data = { issues: [{ id: 1 }, { id: 2 }] };
- });
-
- it('renders component', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
-
- await nextTick();
- expect(wrapper.findAll('li').length).toBe(data.issues.length);
- });
+ it('does not render when loading', () => {
+ createComponent();
+ expect(wrapper.isVisible()).toBe(false);
+ });
- it('does not render with empty search', async () => {
- wrapper.setProps({ search: '' });
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
+ it('does not render with empty issues data', async () => {
+ const emptyIssuesResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/1',
+ issues: {
+ edges: [],
+ },
+ },
+ },
+ };
- await nextTick();
- expect(wrapper.isVisible()).toBe(false);
- });
+ createComponent({ queryResponse: jest.fn().mockResolvedValue(emptyIssuesResponse) });
+ await waitForDebounce();
- it('does not render when loading', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- ...data,
- loading: 1,
- });
+ expect(wrapper.isVisible()).toBe(false);
+ });
- await nextTick();
- expect(wrapper.isVisible()).toBe(false);
+ describe('with data', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForDebounce();
});
- it('does not render with empty issues data', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ issues: [] });
-
- await nextTick();
- expect(wrapper.isVisible()).toBe(false);
+ it('renders component', () => {
+ expect(wrapper.findAll('li').length).toBe(MOCK_ISSUES_COUNT);
});
- it('renders list of issues', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
-
- await nextTick();
- expect(wrapper.findAllComponents(TitleSuggestionsItem).length).toBe(2);
+ it('renders list of issues', () => {
+ expect(wrapper.findAllComponents(TitleSuggestionsItem).length).toBe(MOCK_ISSUES_COUNT);
});
- it('adds margin class to first item', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
-
- await nextTick();
+ it('adds margin class to first item', () => {
expect(wrapper.findAll('li').at(0).classes()).toContain('gl-mb-3');
});
- it('does not add margin class to last item', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData(data);
-
- await nextTick();
+ it('does not add margin class to last item', () => {
expect(wrapper.findAll('li').at(1).classes()).not.toContain('gl-mb-3');
});
});
diff --git a/spec/frontend/issues/new/mock_data.js b/spec/frontend/issues/new/mock_data.js
index 74b569d9833..0d2a388cd86 100644
--- a/spec/frontend/issues/new/mock_data.js
+++ b/spec/frontend/issues/new/mock_data.js
@@ -26,3 +26,67 @@ export default () => ({
webUrl: `${TEST_HOST}/author`,
},
});
+
+export const mockIssueSuggestionResponse = {
+ data: {
+ project: {
+ id: 'gid://gitlab/Project/278964',
+ issues: {
+ edges: [
+ {
+ node: {
+ id: 'gid://gitlab/Issue/123725957',
+ iid: '696',
+ title: 'Remove unused MR widget extension expand success, failed, warning events',
+ confidential: false,
+ userNotesCount: 16,
+ upvotes: 0,
+ webUrl: 'https://gitlab.com/gitlab-org/gitlab/-/issues/696',
+ state: 'opened',
+ closedAt: null,
+ createdAt: '2023-02-15T12:29:59Z',
+ updatedAt: '2023-03-01T19:38:22Z',
+ author: {
+ id: 'gid://gitlab/User/325',
+ name: 'User Name',
+ username: 'user-name',
+ avatarUrl: '/uploads/-/system/user/avatar/325/avatar.png',
+ webUrl: 'https://gitlab.com/user-name',
+ __typename: 'UserCore',
+ },
+ __typename: 'Issue',
+ },
+ __typename: 'IssueEdge',
+ },
+ {
+ node: {
+ id: 'gid://gitlab/Issue/123',
+ iid: '391',
+ title: 'Remove unused MR widget extension expand success, failed, warning events',
+ confidential: false,
+ userNotesCount: 16,
+ upvotes: 0,
+ webUrl: 'https://gitlab.com/gitlab-org/gitlab/-/issues/391',
+ state: 'opened',
+ closedAt: null,
+ createdAt: '2023-02-15T12:29:59Z',
+ updatedAt: '2023-03-01T19:38:22Z',
+ author: {
+ id: 'gid://gitlab/User/2080',
+ name: 'User Name',
+ username: 'user-name',
+ avatarUrl: '/uploads/-/system/user/avatar/2080/avatar.png',
+ webUrl: 'https://gitlab.com/user-name',
+ __typename: 'UserCore',
+ },
+ __typename: 'Issue',
+ },
+ __typename: 'IssueEdge',
+ },
+ ],
+ __typename: 'IssueConnection',
+ },
+ __typename: 'Project',
+ },
+ },
+};
diff --git a/spec/frontend/monitoring/components/variables/dropdown_field_spec.js b/spec/frontend/monitoring/components/variables/dropdown_field_spec.js
index 012e2e9c3e2..96b228fd3b2 100644
--- a/spec/frontend/monitoring/components/variables/dropdown_field_spec.js
+++ b/spec/frontend/monitoring/components/variables/dropdown_field_spec.js
@@ -1,6 +1,5 @@
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
import DropdownField from '~/monitoring/components/variables/dropdown_field.vue';
describe('Custom variable component', () => {
@@ -56,11 +55,8 @@ describe('Custom variable component', () => {
it('changing dropdown items triggers update', async () => {
createShallowWrapper();
- jest.spyOn(wrapper.vm, '$emit');
-
findDropdownItems().at(1).vm.$emit('click');
- await nextTick();
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('input', 'canary');
+ expect(wrapper.emitted('input')).toEqual([['canary']]);
});
});
diff --git a/spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js b/spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js
index 51f3d31ec72..5d37692bf90 100644
--- a/spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_viewers/notebook_viewer_spec.js
@@ -1,7 +1,6 @@
-import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import NotebookViewer from '~/repository/components/blob_viewers/notebook_viewer.vue';
-import notebookLoader from '~/blob/notebook';
+import Notebook from '~/blob/notebook/notebook_viewer.vue';
jest.mock('~/blob/notebook');
@@ -17,24 +16,11 @@ describe('Notebook Viewer', () => {
});
};
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findNotebookWrapper = () => wrapper.findByTestId('notebook');
+ const findNotebook = () => wrapper.findComponent(Notebook);
beforeEach(() => createComponent());
- it('calls the notebook loader', () => {
- expect(notebookLoader).toHaveBeenCalledWith({
- el: wrapper.vm.$refs.viewer,
- relativeRawPath: ROOT_RELATIVE_PATH,
- });
- });
-
- it('renders a loading icon component', () => {
- expect(findLoadingIcon().props('size')).toBe('lg');
- });
-
- it('renders the notebook wrapper', () => {
- expect(findNotebookWrapper().exists()).toBe(true);
- expect(findNotebookWrapper().attributes('data-endpoint')).toBe(DEFAULT_BLOB_DATA.rawPath);
+ it('renders a Notebook component', () => {
+ expect(findNotebook().props('endpoint')).toBe(DEFAULT_BLOB_DATA.rawPath);
});
});
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb
index 6f2f1cd9124..3c171d684d6 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::RequestParams, feature_categor
it_behaves_like 'unlicensed cycle analytics request params' do
let_it_be(:user) { create(:user) }
let_it_be(:root_group) { create(:group) }
- let_it_be(:project) { create(:project, group: root_group) }
+ let_it_be_with_refind(:project) { create(:project, group: root_group) }
let(:namespace) { project.project_namespace }
@@ -17,8 +17,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::RequestParams, feature_categor
expect(attributes).to match(hash_including({
namespace: {
name: project.name,
- full_path: project.full_path,
- avatar_url: project.avatar_url
+ full_path: project.full_path
}
}))
end
diff --git a/spec/mailers/emails/profile_spec.rb b/spec/mailers/emails/profile_spec.rb
index 32df477fdfc..c796801fdf9 100644
--- a/spec/mailers/emails/profile_spec.rb
+++ b/spec/mailers/emails/profile_spec.rb
@@ -429,11 +429,16 @@ RSpec.describe Emails::Profile do
is_expected.to have_subject "#{Gitlab.config.gitlab.host} sign-in from new location"
end
+ it 'mentions the username' do
+ is_expected.to have_body_text user.name
+ is_expected.to have_body_text user.username
+ end
+
it 'mentions the new sign-in IP' do
is_expected.to have_body_text ip
end
- it 'mentioned the time' do
+ it 'mentions the time' do
is_expected.to have_body_text current_time.strftime('%Y-%m-%d %H:%M:%S %Z')
end
diff --git a/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb b/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb
index 9f6031af444..f1ffddf6507 100644
--- a/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb
+++ b/spec/support/shared_examples/analytics/cycle_analytics/request_params_examples.rb
@@ -122,6 +122,6 @@ RSpec.shared_examples 'unlicensed cycle analytics request params' do
describe 'enable_tasks_by_type_chart data attribute' do
subject(:value) { described_class.new(params).to_data_attributes[:enable_tasks_by_type_chart] }
- it { is_expected.to eq(false) }
+ it { is_expected.to eq('false') }
end
end
diff --git a/spec/tasks/gitlab/db_rake_spec.rb b/spec/tasks/gitlab/db_rake_spec.rb
index f43106959b0..0f13840ae01 100644
--- a/spec/tasks/gitlab/db_rake_spec.rb
+++ b/spec/tasks/gitlab/db_rake_spec.rb
@@ -402,6 +402,12 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
end
end
+ let(:migration_table_class) do
+ Class.new(Gitlab::Database::Migration[1.0]::MigrationRecord) do
+ self.table_name = 'table1'
+ end
+ end
+
let(:view_class) do
Class.new(ApplicationRecord) do
self.table_name = 'view1'
@@ -427,12 +433,13 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout, feature_categor
before do
stub_const('TableClass1', table_class)
+ stub_const('MIgrationTableClass1', migration_table_class)
stub_const('ViewClass1', view_class)
File.write(table_file_path, table_metadata.to_yaml)
File.write(view_file_path, view_metadata.to_yaml)
- allow(model).to receive(:descendants).and_return([table_class, view_class])
+ allow(model).to receive(:descendants).and_return([table_class, migration_table_class, view_class])
end
it 'appends new classes to the dictionary' do