diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-10-18 06:10:30 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-10-18 06:10:30 +0300 |
commit | 14facaa466ed56cd0dfad8c0f821ea32f94f94a0 (patch) | |
tree | 16f08c5a5d8e1241871a5c4f7398a0e2f0aab445 | |
parent | 90e7f31698f6d67da00ed3a68a7392127746ced2 (diff) |
Add latest changes from gitlab-org/gitlab@master
-rw-r--r-- | app/assets/javascripts/access_tokens/index.js | 2 | ||||
-rw-r--r-- | app/models/concerns/routable.rb | 3 | ||||
-rw-r--r-- | config/initializers/1_settings.rb | 6 | ||||
-rw-r--r-- | config/sidekiq_queues.yml | 4 | ||||
-rw-r--r-- | db/post_migrate/20221010074914_migrate_security_findings_delete_queues.rb | 16 | ||||
-rw-r--r-- | db/schema_migrations/20221010074914 | 1 | ||||
-rw-r--r-- | doc/api/import.md | 4 | ||||
-rw-r--r-- | doc/api/members.md | 9 | ||||
-rw-r--r-- | doc/development/pipelines.md | 35 | ||||
-rw-r--r-- | doc/user/project/import/github.md | 2 | ||||
-rw-r--r-- | lib/api/events.rb | 2 | ||||
-rw-r--r-- | lib/api/helpers.rb | 7 | ||||
-rw-r--r-- | lib/api/helpers/events_helpers.rb | 2 | ||||
-rw-r--r-- | qa/qa/resource/project_imported_from_github.rb | 9 | ||||
-rw-r--r-- | qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb | 2 | ||||
-rw-r--r-- | qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb | 6 | ||||
-rw-r--r-- | spec/frontend/access_tokens/index_spec.js | 71 | ||||
-rw-r--r-- | spec/lib/api/helpers_spec.rb | 21 | ||||
-rw-r--r-- | spec/models/concerns/routable_spec.rb | 6 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 14 |
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 |