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>2022-10-18 06:10:30 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-18 06:10:30 +0300
commit14facaa466ed56cd0dfad8c0f821ea32f94f94a0 (patch)
tree16f08c5a5d8e1241871a5c4f7398a0e2f0aab445
parent90e7f31698f6d67da00ed3a68a7392127746ced2 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/access_tokens/index.js2
-rw-r--r--app/models/concerns/routable.rb3
-rw-r--r--config/initializers/1_settings.rb6
-rw-r--r--config/sidekiq_queues.yml4
-rw-r--r--db/post_migrate/20221010074914_migrate_security_findings_delete_queues.rb16
-rw-r--r--db/schema_migrations/202210100749141
-rw-r--r--doc/api/import.md4
-rw-r--r--doc/api/members.md9
-rw-r--r--doc/development/pipelines.md35
-rw-r--r--doc/user/project/import/github.md2
-rw-r--r--lib/api/events.rb2
-rw-r--r--lib/api/helpers.rb7
-rw-r--r--lib/api/helpers/events_helpers.rb2
-rw-r--r--qa/qa/resource/project_imported_from_github.rb9
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb6
-rw-r--r--spec/frontend/access_tokens/index_spec.js71
-rw-r--r--spec/lib/api/helpers_spec.rb21
-rw-r--r--spec/models/concerns/routable_spec.rb6
-rw-r--r--spec/models/user_spec.rb14
20 files changed, 141 insertions, 81 deletions
diff --git a/app/assets/javascripts/access_tokens/index.js b/app/assets/javascripts/access_tokens/index.js
index 5e8d95c2076..510f118bbb5 100644
--- a/app/assets/javascripts/access_tokens/index.js
+++ b/app/assets/javascripts/access_tokens/index.js
@@ -100,7 +100,7 @@ export const initNewAccessTokenApp = () => {
export const initTokensApp = () => {
const el = document.getElementById('js-tokens-app');
- if (!el) return false;
+ if (!el) return null;
const tokensData = convertObjectPropsToCamelCase(JSON.parse(el.dataset.tokensData), {
deep: true,
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index 5b759dedb26..262839a3fa6 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -17,6 +17,9 @@ module Routable
def self.find_by_full_path(path, follow_redirects: false, route_scope: Route, redirect_route_scope: RedirectRoute)
return unless path.present?
+ # Convert path to string to prevent DB error: function lower(integer) does not exist
+ path = path.to_s
+
# Case sensitive match first (it's cheaper and the usual case)
# If we didn't have an exact match, we perform a case insensitive search
#
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index a490ad74710..b07577a347c 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -781,9 +781,9 @@ Gitlab.ee do
Settings.cron_jobs['security_orchestration_policy_rule_schedule_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['security_orchestration_policy_rule_schedule_worker']['cron'] ||= '*/15 * * * *'
Settings.cron_jobs['security_orchestration_policy_rule_schedule_worker']['job_class'] = 'Security::OrchestrationPolicyRuleScheduleWorker'
- Settings.cron_jobs['security_findings_cleanup_worker'] ||= Settingslogic.new({})
- Settings.cron_jobs['security_findings_cleanup_worker']['cron'] ||= '0 */4 * * 6,0'
- Settings.cron_jobs['security_findings_cleanup_worker']['job_class'] = 'Security::Findings::CleanupWorker'
+ Settings.cron_jobs['security_scans_purge_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['security_scans_purge_worker']['cron'] ||= '0 */4 * * 6,0'
+ Settings.cron_jobs['security_scans_purge_worker']['job_class'] = 'Security::Scans::PurgeWorker'
Settings.cron_jobs['app_sec_dast_profile_schedule_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['app_sec_dast_profile_schedule_worker']['cron'] ||= '7-59/15 * * * *'
Settings.cron_jobs['app_sec_dast_profile_schedule_worker']['job_class'] = 'AppSec::Dast::ProfileScheduleWorker'
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 1f904338249..548e643c7fe 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -453,14 +453,14 @@
- 1
- - security_auto_fix
- 1
-- - security_findings_delete_by_job_id
- - 1
- - security_orchestration_policy_rule_schedule_namespace
- 1
- - security_process_scan_result_policy
- 1
- - security_scans
- 2
+- - security_scans_purge_by_job_id
+ - 1
- - security_sync_scan_policies
- 1
- - self_monitoring_project_create
diff --git a/db/post_migrate/20221010074914_migrate_security_findings_delete_queues.rb b/db/post_migrate/20221010074914_migrate_security_findings_delete_queues.rb
new file mode 100644
index 00000000000..ce593e19859
--- /dev/null
+++ b/db/post_migrate/20221010074914_migrate_security_findings_delete_queues.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class MigrateSecurityFindingsDeleteQueues < Gitlab::Database::Migration[2.0]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+ disable_ddl_transaction!
+
+ def up
+ sidekiq_queue_migrate 'security_findings_delete_by_job_id', to: 'security_scans_purge_by_job_id'
+ sidekiq_queue_migrate 'cronjob:security_findings_cleanup', to: 'cronjob:security_scans_purge'
+ end
+
+ def down
+ sidekiq_queue_migrate 'security_scans_purge_by_job_id', to: 'security_findings_delete_by_job_id'
+ sidekiq_queue_migrate 'cronjob:security_scans_purge', to: 'cronjob:security_findings_cleanup'
+ end
+end
diff --git a/db/schema_migrations/20221010074914 b/db/schema_migrations/20221010074914
new file mode 100644
index 00000000000..272a8d038cc
--- /dev/null
+++ b/db/schema_migrations/20221010074914
@@ -0,0 +1 @@
+c5ef65edf6e87495bc4dc16c636b2f2d8cbd63f3903cf5ed1364206b83411ba9 \ No newline at end of file
diff --git a/doc/api/import.md b/doc/api/import.md
index 2ef04dc597f..78b9beb1815 100644
--- a/doc/api/import.md
+++ b/doc/api/import.md
@@ -19,9 +19,9 @@ POST /import/github
| `personal_access_token` | string | yes | GitHub personal access token |
| `repo_id` | integer | yes | GitHub repository ID |
| `new_name` | string | no | New repository name |
-| `target_namespace` | string | yes | Namespace to import repository into. Supports subgroups like `/namespace/subgroup`. |
+| `target_namespace` | string | yes | Namespace to import repository into. Supports subgroups like `/namespace/subgroup` |
| `github_hostname` | string | no | Custom GitHub Enterprise hostname. Do not set for GitHub.com. |
-| `optional_stages` | object | no | [Additional items to import](../user/project/import/github.md#select-additional-items-to-import)|
+| `optional_stages` | object | no | [Additional items to import](../user/project/import/github.md#select-additional-items-to-import). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/373705) in GitLab 15.5 |
```shell
curl --request POST \
diff --git a/doc/api/members.md b/doc/api/members.md
index 43a746c6194..52bc3f6f468 100644
--- a/doc/api/members.md
+++ b/doc/api/members.md
@@ -365,7 +365,8 @@ Example response:
"last_activity_on": "2021-01-27",
"membership_type": "group_member",
"removable": true,
- "created_at": "2021-01-03T12:16:02.000Z"
+ "created_at": "2021-01-03T12:16:02.000Z",
+ "last_login_at": "2022-10-09T01:33:06.000Z"
},
{
"id": 2,
@@ -378,7 +379,8 @@ Example response:
"last_activity_on": "2021-01-25",
"membership_type": "group_member",
"removable": true,
- "created_at": "2021-01-04T18:46:42.000Z"
+ "created_at": "2021-01-04T18:46:42.000Z",
+ "last_login_at": "2022-09-29T22:18:46.000Z"
},
{
"id": 3,
@@ -390,7 +392,8 @@ Example response:
"last_activity_on": "2021-01-20",
"membership_type": "group_invite",
"removable": false,
- "created_at": "2021-01-09T07:12:31.000Z"
+ "created_at": "2021-01-09T07:12:31.000Z",
+ "last_login_at": "2022-10-10T07:28:56.000Z"
}
]
```
diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md
index debb33a2854..5289f1aa3c3 100644
--- a/doc/development/pipelines.md
+++ b/doc/development/pipelines.md
@@ -823,19 +823,38 @@ needed in the GitLab test suite (under `app/assets/javascripts/locale/**/app.js`
and `public/assets`).
- If the package URL returns a 404:
- 1. It runs `bin/rake gitlab:assets:compile`, so that the GitLab assets are compiled.
- 1. It then creates an archive which contains the assets and upload it [as a generic package](https://gitlab.com/gitlab-org/gitlab/-/packages/).
+ 1. It runs `bin/rake gitlab:assets:compile`, so that the GitLab assets are compiled.
+ 1. It then creates an archive which contains the assets and uploads it [as a generic package](https://gitlab.com/gitlab-org/gitlab/-/packages/).
+ The package version is set to the assets folders' hash sum.
- Otherwise, if the package already exists, it exits the job successfully.
+#### `compile-*-assets`
+
We also changed the `compile-test-assets`, `compile-test-assets as-if-foss`,
and `compile-production-assets` jobs to:
-1. First download the GitLab assets generic package build and uploaded by `cache-assets:*`.
-1. If the package is retrieved successfully, assets aren't compiled.
-1. If the package URL returns a 404, the behavior doesn't change compared to the current one: the GitLab assets are compiled as part of `bin/rake gitlab:assets:compile`.
-
-NOTE:
-The version of the package is the assets folders hash sum.
+1. First download the "native" cache assets, which contain:
+ - The [compiled assets](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/global.gitlab-ci.yml#L86-87).
+ - A [`cached-assets-hash.txt` file](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/global.gitlab-ci.yml#L85)
+ containing the `SHA256` hexdigest of all the source files on which the assets depend on.
+ This list of files is a pessimistic list and the assets might not depend on
+ some of these files. At worst we compile the assets more often, which is better than
+ using outdated assets.
+
+ The file is [created after assets are compiled](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L83).
+1. We then we compute the `SHA256` hexdigest of all the source files the assets depend on, **for the current checked out branch**. We [store the hexdigest in the `GITLAB_ASSETS_HASH` variable](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L27).
+1. If `$CACHE_ASSETS_AS_PACKAGE == "true"`, we download the generic package built and uploaded by [`cache-assets:*`](#cache-assets).
+ - If the cache is up-to-date for the checked out branch, we download the native cache
+ **and** the cache package. We could optimize that by not downloading
+ the genetic package but the native cache is actually very often outdated because it's
+ rebuilt only every 2 hours.
+1. We [run the `assets_compile_script` function](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L35),
+ which [itself runs](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/scripts/utils.sh#L76)
+ the [`assets:compile` Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/lib/tasks/gitlab/assets.rake#L80-109).
+
+ This task is responsible for deciding if assets need to be compiled or not.
+ It [compares the `HEAD` `SHA256` hexdigest from `$GITLAB_ASSETS_HASH` with the `master` hexdigest from `cached-assets-hash.txt`](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/lib/tasks/gitlab/assets.rake#L86).
+1. If the hashes are the same, we don't compile anything. If they're different, we compile the assets.
### Pre-clone step
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index bf70fb27264..03f6fd20b0a 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -120,6 +120,8 @@ your GitLab account and sign in again, or revoke the older personal access token
### Select additional items to import
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/373705) in GitLab 15.5.
+
To make imports as fast as possible, the following items aren't imported from GitHub by default:
- Issue and pull request events. For example, _opened_ or _closed_, _renamed_, and _labeled_ or _unlabeled_.
diff --git a/lib/api/events.rb b/lib/api/events.rb
index 0a0141484ef..521a9e6d351 100644
--- a/lib/api/events.rb
+++ b/lib/api/events.rb
@@ -20,6 +20,8 @@ module API
use :pagination
use :event_filter_params
use :sort_params
+ optional :scope, type: String, desc: 'Include all events across a user\'s projects',
+ documentation: { example: 'all' }
end
get do
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 2abe893e16a..bf1da849cf1 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -18,6 +18,7 @@ module API
API_TOKEN_ENV = 'gitlab.api.token'
API_EXCEPTION_ENV = 'gitlab.api.exception'
API_RESPONSE_STATUS_CODE = 'gitlab.api.response_status_code'
+ INTEGER_ID_REGEX = /^-?\d+$/.freeze
def declared_params(options = {})
options = { include_parent_namespaces: false }.merge(options)
@@ -139,7 +140,7 @@ module API
projects = Project.without_deleted.not_hidden
- if id.is_a?(Integer) || id =~ /^\d+$/
+ if id.is_a?(Integer) || id =~ INTEGER_ID_REGEX
projects.find_by(id: id)
elsif id.include?("/")
projects.find_by_full_path(id)
@@ -168,7 +169,7 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def find_group(id)
- if id.to_s =~ /^\d+$/
+ if id.to_s =~ INTEGER_ID_REGEX
Group.find_by(id: id)
else
Group.find_by_full_path(id)
@@ -203,7 +204,7 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def find_namespace(id)
- if id.to_s =~ /^\d+$/
+ if id.to_s =~ INTEGER_ID_REGEX
Namespace.without_project_namespaces.find_by(id: id)
else
find_namespace_by_path(id)
diff --git a/lib/api/helpers/events_helpers.rb b/lib/api/helpers/events_helpers.rb
index bf3b76bb92d..cef34ca8d05 100644
--- a/lib/api/helpers/events_helpers.rb
+++ b/lib/api/helpers/events_helpers.rb
@@ -6,7 +6,7 @@ module API
extend Grape::API::Helpers
params :event_filter_params do
- optional :action, type: String, values: Event.actions, desc: 'Event action to filter on'
+ optional :action, type: String, values: Event.actions.keys, desc: 'Event action to filter on'
optional :target_type, type: String, values: Event.target_types, desc: 'Event target type to filter on'
optional :before, type: Date, desc: 'Include only events created before this date'
optional :after, type: Date, desc: 'Include only events created after this date'
diff --git a/qa/qa/resource/project_imported_from_github.rb b/qa/qa/resource/project_imported_from_github.rb
index b9dbd2a6131..9ba9723f0cc 100644
--- a/qa/qa/resource/project_imported_from_github.rb
+++ b/qa/qa/resource/project_imported_from_github.rb
@@ -3,6 +3,8 @@
module QA
module Resource
class ProjectImportedFromGithub < Resource::Project
+ attr_accessor :issue_events_import, :full_notes_import, :attachments_import
+
attribute :github_repo_id do
github_client.repository(github_repository_path).id
end
@@ -51,7 +53,12 @@ module QA
new_name: name,
target_namespace: @personal_namespace || group.full_path,
personal_access_token: github_personal_access_token,
- ci_cd_only: false
+ ci_cd_only: false,
+ optional_stages: {
+ single_endpoint_issue_events_import: issue_events_import,
+ single_endpoint_notes_import: full_notes_import,
+ attachments_import: attachments_import
+ }
}
end
diff --git a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
index 85eb28e901c..c3e41e9298b 100644
--- a/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb
@@ -21,6 +21,8 @@ module QA
project.github_personal_access_token = Runtime::Env.github_access_token
project.github_repository_path = 'gitlab-qa-github/import-test'
project.api_client = Runtime::API::Client.new(user: user)
+ project.issue_events_import = true
+ project.full_notes_import = true
end
end
diff --git a/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb b/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb
index 9728eee3869..5acf15dd2b4 100644
--- a/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb
@@ -199,13 +199,11 @@ module QA
project.github_repository_path = github_repo
project.personal_namespace = user.username
project.api_client = Runtime::API::Client.new(user: user)
+ project.issue_events_import = true
+ project.full_notes_import = true
end
end
- before do
- Runtime::Feature.enable(:github_importer_single_endpoint_issue_events_import)
- end
-
after do |example|
next unless defined?(@import_time)
diff --git a/spec/frontend/access_tokens/index_spec.js b/spec/frontend/access_tokens/index_spec.js
index dba6e73f278..1157e44f41a 100644
--- a/spec/frontend/access_tokens/index_spec.js
+++ b/spec/frontend/access_tokens/index_spec.js
@@ -1,7 +1,4 @@
-/* eslint-disable vue/require-prop-types */
-/* eslint-disable vue/one-component-per-file */
import { createWrapper } from '@vue/test-utils';
-import Vue from 'vue';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import {
@@ -10,10 +7,11 @@ import {
initNewAccessTokenApp,
initTokensApp,
} from '~/access_tokens';
-import * as AccessTokenTableApp from '~/access_tokens/components/access_token_table_app.vue';
+import AccessTokenTableApp from '~/access_tokens/components/access_token_table_app.vue';
import ExpiresAtField from '~/access_tokens/components/expires_at_field.vue';
-import * as NewAccessTokenApp from '~/access_tokens/components/new_access_token_app.vue';
-import * as TokensApp from '~/access_tokens/components/tokens_app.vue';
+import NewAccessTokenApp from '~/access_tokens/components/new_access_token_app.vue';
+import TokensApp from '~/access_tokens/components/tokens_app.vue';
+import { FORM_SELECTOR } from '~/access_tokens/components/constants';
import { FEED_TOKEN, INCOMING_EMAIL_TOKEN, STATIC_OBJECT_TOKEN } from '~/access_tokens/constants';
import { __, sprintf } from '~/locale';
@@ -30,25 +28,6 @@ describe('access tokens', () => {
const accessTokenTypePlural = 'personal access tokens';
const initialActiveAccessTokens = [{ revoked_path: '1' }];
- const FakeAccessTokenTableApp = Vue.component('FakeComponent', {
- inject: [
- 'accessTokenType',
- 'accessTokenTypePlural',
- 'initialActiveAccessTokens',
- 'noActiveTokensMessage',
- 'showRole',
- ],
- props: [
- 'accessTokenType',
- 'accessTokenTypePlural',
- 'initialActiveAccessTokens',
- 'noActiveTokensMessage',
- 'showRole',
- ],
- render: () => null,
- });
- AccessTokenTableApp.default = FakeAccessTokenTableApp;
-
it('mounts the component and provides required values', () => {
setHTMLFixture(
`<div id="js-access-token-table-app"
@@ -60,19 +39,18 @@ describe('access tokens', () => {
);
const vueInstance = initAccessTokenTableApp();
-
wrapper = createWrapper(vueInstance);
- const component = wrapper.findComponent(FakeAccessTokenTableApp);
+ const component = wrapper.findComponent({ name: 'AccessTokenTableRoot' });
expect(component.exists()).toBe(true);
-
- expect(component.props()).toMatchObject({
+ expect(wrapper.findComponent(AccessTokenTableApp).vm).toMatchObject({
// Required value
accessTokenType,
accessTokenTypePlural,
initialActiveAccessTokens,
// Default values
+ information: undefined,
noActiveTokensMessage: sprintf(__('This user has no active %{accessTokenTypePlural}.'), {
accessTokenTypePlural,
}),
@@ -81,12 +59,14 @@ describe('access tokens', () => {
});
it('mounts the component and provides all values', () => {
+ const information = 'Additional information';
const noActiveTokensMessage = 'This group has no active access tokens.';
setHTMLFixture(
`<div id="js-access-token-table-app"
data-access-token-type="${accessTokenType}"
data-access-token-type-plural="${accessTokenTypePlural}"
data-initial-active-access-tokens=${JSON.stringify(initialActiveAccessTokens)}
+ data-information="${information}"
data-no-active-tokens-message="${noActiveTokensMessage}"
data-show-role
>
@@ -94,15 +74,15 @@ describe('access tokens', () => {
);
const vueInstance = initAccessTokenTableApp();
-
wrapper = createWrapper(vueInstance);
- const component = wrapper.findComponent(FakeAccessTokenTableApp);
+ const component = wrapper.findComponent({ name: 'AccessTokenTableRoot' });
expect(component.exists()).toBe(true);
- expect(component.props()).toMatchObject({
+ expect(component.findComponent(AccessTokenTableApp).vm).toMatchObject({
accessTokenType,
accessTokenTypePlural,
initialActiveAccessTokens,
+ information,
noActiveTokensMessage,
showRole: true,
});
@@ -157,23 +137,16 @@ describe('access tokens', () => {
it('mounts the component and sets `accessTokenType` prop', () => {
const accessTokenType = 'personal access token';
setHTMLFixture(
- `<div id="js-new-access-token-app" data-access-token-type="${accessTokenType}"></div>`,
+ `<div id="js-new-access-token-app" data-access-token-type="${accessTokenType}"></div>
+ <form id="${FORM_SELECTOR.slice(1)}"></form>`,
);
- const FakeNewAccessTokenApp = Vue.component('FakeComponent', {
- inject: ['accessTokenType'],
- props: ['accessTokenType'],
- render: () => null,
- });
- NewAccessTokenApp.default = FakeNewAccessTokenApp;
-
const vueInstance = initNewAccessTokenApp();
-
wrapper = createWrapper(vueInstance);
- const component = wrapper.findComponent(FakeNewAccessTokenApp);
+ const component = wrapper.findComponent({ name: 'NewAccessTokenRoot' });
expect(component.exists()).toBe(true);
- expect(component.props('accessTokenType')).toEqual(accessTokenType);
+ expect(component.findComponent(NewAccessTokenApp).vm).toMatchObject({ accessTokenType });
});
it('returns `null`', () => {
@@ -192,20 +165,12 @@ describe('access tokens', () => {
`<div id="js-tokens-app" data-tokens-data=${JSON.stringify(tokensData)}></div>`,
);
- const FakeTokensApp = Vue.component('FakeComponent', {
- inject: ['tokenTypes'],
- props: ['tokenTypes'],
- render: () => null,
- });
- TokensApp.default = FakeTokensApp;
-
const vueInstance = initTokensApp();
-
wrapper = createWrapper(vueInstance);
- const component = wrapper.findComponent(FakeTokensApp);
+ const component = wrapper.findComponent(TokensApp);
expect(component.exists()).toBe(true);
- expect(component.props('tokenTypes')).toEqual(tokensData);
+ expect(component.vm).toMatchObject({ tokenTypes: tokensData });
});
it('returns `null`', () => {
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index 3ea42c29ce2..11bbe825402 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -110,6 +110,13 @@ RSpec.describe API::Helpers do
end
end
+ context 'when ID is a negative number' do
+ let(:existing_id) { project.id }
+ let(:non_existing_id) { -1 }
+
+ it_behaves_like 'project finder'
+ end
+
context 'when project is pending delete' do
let(:project_pending_delete) { create(:project, pending_delete: true) }
@@ -325,6 +332,13 @@ RSpec.describe API::Helpers do
it_behaves_like 'group finder'
end
+
+ context 'when ID is a negative number' do
+ let(:existing_id) { group.id }
+ let(:non_existing_id) { -1 }
+
+ it_behaves_like 'group finder'
+ end
end
end
@@ -421,6 +435,13 @@ RSpec.describe API::Helpers do
it_behaves_like 'namespace finder'
end
+
+ context 'when ID is a negative number' do
+ let(:existing_id) { namespace.id }
+ let(:non_existing_id) { -1 }
+
+ it_behaves_like 'namespace finder'
+ end
end
shared_examples 'user namespace finder' do
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index cf66ba83e87..dc1002f3560 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -23,6 +23,12 @@ RSpec.shared_examples 'routable resource' do
end.not_to exceed_all_query_limit(control_count)
end
+ context 'when path is a negative number' do
+ it 'returns nil' do
+ expect(described_class.find_by_full_path(-1)).to be_nil
+ end
+ end
+
context 'with redirect routes' do
let_it_be(:redirect_route) { create(:redirect_route, source: record) }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index b08c85339d1..e6d4e9cc2f6 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1166,6 +1166,20 @@ RSpec.describe User do
'ORDER BY "users"."last_activity_on" ASC NULLS FIRST, "users"."id" DESC')
end
end
+
+ describe '.order_recent_sign_in' do
+ it 'sorts users by current_sign_in_at in descending order' do
+ expect(described_class.order_recent_sign_in.to_sql).to include(
+ 'ORDER BY "users"."current_sign_in_at" DESC NULLS LAST')
+ end
+ end
+
+ describe '.order_oldest_sign_in' do
+ it 'sorts users by current_sign_in_at in ascending order' do
+ expect(described_class.order_oldest_sign_in.to_sql).to include(
+ 'ORDER BY "users"."current_sign_in_at" ASC NULLS LAST')
+ end
+ end
end
context 'strip attributes' do