Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
fa29f13c
Commit
fa29f13c
authored
Sep 28, 2021
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab master
parents
ad1824fc
2b719bdf
Changes
52
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
52 changed files
with
391 additions
and
230 deletions
+391
-230
app/assets/javascripts/blob/components/blob_content.vue
app/assets/javascripts/blob/components/blob_content.vue
+6
-0
app/assets/javascripts/repository/components/blob_content_viewer.vue
...javascripts/repository/components/blob_content_viewer.vue
+27
-9
app/assets/javascripts/repository/components/blob_viewers/index.js
...s/javascripts/repository/components/blob_viewers/index.js
+3
-1
app/assets/javascripts/vue_shared/components/blob_viewers/mixins.js
.../javascripts/vue_shared/components/blob_viewers/mixins.js
+5
-0
app/assets/javascripts/vue_shared/components/blob_viewers/simple_viewer.vue
...ipts/vue_shared/components/blob_viewers/simple_viewer.vue
+2
-13
app/controllers/projects/blob_controller.rb
app/controllers/projects/blob_controller.rb
+1
-0
app/controllers/projects_controller.rb
app/controllers/projects_controller.rb
+1
-0
app/models/member.rb
app/models/member.rb
+9
-3
app/models/members/group_member.rb
app/models/members/group_member.rb
+3
-3
app/models/members/project_member.rb
app/models/members/project_member.rb
+9
-5
app/models/user.rb
app/models/user.rb
+1
-0
app/models/user_detail.rb
app/models/user_detail.rb
+5
-0
app/workers/all_queues.yml
app/workers/all_queues.yml
+9
-0
app/workers/authorized_project_update/project_recalculate_per_user_worker.rb
...zed_project_update/project_recalculate_per_user_worker.rb
+25
-0
app/workers/authorized_project_update/project_recalculate_worker.rb
...s/authorized_project_update/project_recalculate_worker.rb
+3
-1
config/feature_flags/development/refactor_text_viewer.yml
config/feature_flags/development/refactor_text_viewer.yml
+8
-0
config/feature_flags/ops/member_destroy_async_auth_refresh.yml
...g/feature_flags/ops/member_destroy_async_auth_refresh.yml
+8
-0
db/migrate/20210917224419_add_registration_objective_to_user_detail.rb
...210917224419_add_registration_objective_to_user_detail.rb
+7
-0
db/schema_migrations/20210917224419
db/schema_migrations/20210917224419
+1
-0
db/structure.sql
db/structure.sql
+1
-0
ee/app/assets/javascripts/registrations/welcome/jobs_to_be_done.js
...sets/javascripts/registrations/welcome/jobs_to_be_done.js
+1
-1
ee/app/controllers/ee/registrations/welcome_controller.rb
ee/app/controllers/ee/registrations/welcome_controller.rb
+1
-1
ee/app/helpers/ee/registrations_helper.rb
ee/app/helpers/ee/registrations_helper.rb
+8
-11
ee/app/views/registrations/welcome/_jobs_to_be_done.html.haml
...pp/views/registrations/welcome/_jobs_to_be_done.html.haml
+2
-4
ee/spec/controllers/registrations/welcome_controller_spec.rb
ee/spec/controllers/registrations/welcome_controller_spec.rb
+10
-1
ee/spec/features/registrations/welcome_spec.rb
ee/spec/features/registrations/welcome_spec.rb
+1
-1
ee/spec/helpers/ee/registrations_helper_spec.rb
ee/spec/helpers/ee/registrations_helper_spec.rb
+6
-14
ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb
ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb
+1
-1
ee/spec/models/approval_state_spec.rb
ee/spec/models/approval_state_spec.rb
+1
-1
ee/spec/services/todo_service_spec.rb
ee/spec/services/todo_service_spec.rb
+1
-1
ee/spec/views/registrations/welcome/show.html.haml_spec.rb
ee/spec/views/registrations/welcome/show.html.haml_spec.rb
+1
-1
spec/controllers/projects/branches_controller_spec.rb
spec/controllers/projects/branches_controller_spec.rb
+1
-1
spec/controllers/projects/compare_controller_spec.rb
spec/controllers/projects/compare_controller_spec.rb
+1
-1
spec/frontend/repository/components/blob_content_viewer_spec.js
...rontend/repository/components/blob_content_viewer_spec.js
+18
-11
spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js
.../vue_shared/components/blob_viewers/simple_viewer_spec.js
+1
-38
spec/graphql/types/project_type_spec.rb
spec/graphql/types/project_type_spec.rb
+5
-5
spec/lib/gitlab/middleware/go_spec.rb
spec/lib/gitlab/middleware/go_spec.rb
+1
-1
spec/lib/gitlab/slash_commands/issue_move_spec.rb
spec/lib/gitlab/slash_commands/issue_move_spec.rb
+1
-1
spec/models/member_spec.rb
spec/models/member_spec.rb
+27
-27
spec/models/members/project_member_spec.rb
spec/models/members/project_member_spec.rb
+25
-5
spec/models/namespace_setting_spec.rb
spec/models/namespace_setting_spec.rb
+2
-0
spec/models/user_detail_spec.rb
spec/models/user_detail_spec.rb
+1
-0
spec/models/user_spec.rb
spec/models/user_spec.rb
+63
-60
spec/requests/api/package_files_spec.rb
spec/requests/api/package_files_spec.rb
+1
-1
spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
...rializers/merge_request_poll_cached_widget_entity_spec.rb
+1
-1
spec/services/merge_requests/assign_issues_service_spec.rb
spec/services/merge_requests/assign_issues_service_spec.rb
+1
-1
spec/services/merge_requests/build_service_spec.rb
spec/services/merge_requests/build_service_spec.rb
+1
-1
spec/services/merge_requests/push_options_handler_service_spec.rb
...vices/merge_requests/push_options_handler_service_spec.rb
+1
-1
spec/services/notes/quick_actions_service_spec.rb
spec/services/notes/quick_actions_service_spec.rb
+1
-1
spec/services/notification_service_spec.rb
spec/services/notification_service_spec.rb
+1
-1
spec/services/projects/move_access_service_spec.rb
spec/services/projects/move_access_service_spec.rb
+1
-1
spec/workers/authorized_project_update/project_recalculate_per_user_worker_spec.rb
...roject_update/project_recalculate_per_user_worker_spec.rb
+70
-0
No files found.
app/assets/javascripts/blob/components/blob_content.vue
View file @
fa29f13c
...
...
@@ -41,6 +41,11 @@ export default {
type
:
Object
,
required
:
true
,
},
hideLineNumbers
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
computed
:
{
viewer
()
{
...
...
@@ -80,6 +85,7 @@ export default {
:is-raw-content=
"isRawContent"
:file-name=
"blob.name"
:type=
"activeViewer.fileType"
:hide-line-numbers=
"hideLineNumbers"
data-qa-selector=
"file_content"
/>
</
template
>
...
...
app/assets/javascripts/repository/components/blob_content_viewer.vue
View file @
fa29f13c
...
...
@@ -42,9 +42,6 @@ export default {
this
.
switchViewer
(
this
.
hasRichViewer
&&
!
window
.
location
.
hash
?
RICH_BLOB_VIEWER
:
SIMPLE_BLOB_VIEWER
,
);
if
(
this
.
hasRichViewer
&&
!
this
.
blobViewer
)
{
this
.
loadLegacyViewer
();
}
},
error
()
{
this
.
displayError
();
...
...
@@ -69,6 +66,7 @@ export default {
data
()
{
return
{
legacyRichViewer
:
null
,
legacySimpleViewer
:
null
,
isBinary
:
false
,
isLoadingLegacyViewer
:
false
,
activeViewerType
:
SIMPLE_BLOB_VIEWER
,
...
...
@@ -115,7 +113,7 @@ export default {
return
isLoggedIn
();
},
isLoading
()
{
return
this
.
$apollo
.
queries
.
project
.
loading
||
this
.
isLoadingLegacyViewer
;
return
this
.
$apollo
.
queries
.
project
.
loading
;
},
isBinaryFileType
()
{
return
this
.
isBinary
||
this
.
blobInfo
.
simpleViewer
?.
fileType
!==
'
text
'
;
...
...
@@ -153,22 +151,41 @@ export default {
},
},
methods
:
{
loadLegacyViewer
()
{
loadLegacyViewer
(
type
)
{
if
(
this
.
legacyViewerLoaded
(
type
))
{
return
;
}
this
.
isLoadingLegacyViewer
=
true
;
axios
.
get
(
`
${
this
.
blobInfo
.
webPath
}
?format=json&viewer=
rich
`
)
.
get
(
`
${
this
.
blobInfo
.
webPath
}
?format=json&viewer=
${
type
}
`
)
.
then
(({
data
:
{
html
,
binary
}
})
=>
{
this
.
legacyRichViewer
=
html
;
if
(
type
===
'
simple
'
)
{
this
.
legacySimpleViewer
=
html
;
}
else
{
this
.
legacyRichViewer
=
html
;
}
this
.
isBinary
=
binary
;
this
.
isLoadingLegacyViewer
=
false
;
})
.
catch
(()
=>
this
.
displayError
());
},
legacyViewerLoaded
(
type
)
{
return
(
(
type
===
SIMPLE_BLOB_VIEWER
&&
this
.
legacySimpleViewer
)
||
(
type
===
RICH_BLOB_VIEWER
&&
this
.
legacyRichViewer
)
);
},
displayError
()
{
createFlash
({
message
:
__
(
'
An error occurred while loading the file. Please try again.
'
)
});
},
switchViewer
(
newViewer
)
{
this
.
activeViewerType
=
newViewer
||
SIMPLE_BLOB_VIEWER
;
if
(
!
this
.
blobViewer
)
{
this
.
loadLegacyViewer
(
this
.
activeViewerType
);
}
},
},
};
...
...
@@ -210,10 +227,11 @@ export default {
v-if=
"!blobViewer"
:rich-viewer=
"legacyRichViewer"
:blob=
"blobInfo"
:content=
"
blobInfo.rawTextBlob
"
:content=
"
legacySimpleViewer
"
:is-raw-content=
"true"
:active-viewer=
"viewer"
:loading=
"false"
:hide-line-numbers=
"true"
:loading=
"isLoadingLegacyViewer"
/>
<component
:is=
"blobViewer"
v-else
v-bind=
"viewerProps"
class=
"blob-viewer"
/>
</div>
...
...
app/assets/javascripts/repository/components/blob_viewers/index.js
View file @
fa29f13c
...
...
@@ -3,7 +3,9 @@ export const loadViewer = (type) => {
case
'
empty
'
:
return
()
=>
import
(
/* webpackChunkName: 'blob_empty_viewer' */
'
./empty_viewer.vue
'
);
case
'
text
'
:
return
()
=>
import
(
/* webpackChunkName: 'blob_text_viewer' */
'
./text_viewer.vue
'
);
return
gon
.
features
.
refactorTextViewer
?
()
=>
import
(
/* webpackChunkName: 'blob_text_viewer' */
'
./text_viewer.vue
'
)
:
null
;
case
'
download
'
:
return
()
=>
import
(
/* webpackChunkName: 'blob_download_viewer' */
'
./download_viewer.vue
'
);
case
'
image
'
:
...
...
app/assets/javascripts/vue_shared/components/blob_viewers/mixins.js
View file @
fa29f13c
...
...
@@ -27,6 +27,11 @@ export default {
required
:
false
,
default
:
''
,
},
hideLineNumbers
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
mounted
()
{
eventHub
.
$emit
(
SNIPPET_MEASURE_BLOBS_CONTENT
);
...
...
app/assets/javascripts/vue_shared/components/blob_viewers/simple_viewer.vue
View file @
fa29f13c
...
...
@@ -8,8 +8,6 @@ export default {
name
:
'
SimpleViewer
'
,
components
:
{
GlIcon
,
SourceEditor
:
()
=>
import
(
/* webpackChunkName: 'SourceEditor' */
'
~/vue_shared/components/source_editor.vue
'
),
},
mixins
:
[
ViewerMixin
,
glFeatureFlagsMixin
()],
inject
:
[
'
blobHash
'
],
...
...
@@ -22,9 +20,6 @@ export default {
lineNumbers
()
{
return
this
.
content
.
split
(
'
\n
'
).
length
;
},
refactorBlobViewerEnabled
()
{
return
this
.
glFeatures
.
refactorBlobViewer
;
},
},
mounted
()
{
const
{
hash
}
=
window
.
location
;
...
...
@@ -52,14 +47,8 @@ export default {
</
script
>
<
template
>
<div>
<source-editor
v-if=
"isRawContent && refactorBlobViewerEnabled"
:value=
"content"
:file-name=
"fileName"
:editor-options=
"
{ readOnly: true }"
/>
<div
v-else
class=
"file-content code js-syntax-highlight"
:class=
"$options.userColorScheme"
>
<div
class=
"line-numbers"
>
<div
class=
"file-content code js-syntax-highlight"
:class=
"$options.userColorScheme"
>
<div
v-if=
"!hideLineNumbers"
class=
"line-numbers"
>
<a
v-for=
"line in lineNumbers"
:id=
"`L$
{line}`"
...
...
app/controllers/projects/blob_controller.rb
View file @
fa29f13c
...
...
@@ -43,6 +43,7 @@ class Projects::BlobController < Projects::ApplicationController
before_action
do
push_frontend_feature_flag
(
:refactor_blob_viewer
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:refactor_text_viewer
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:consolidated_edit_button
,
@project
,
default_enabled: :yaml
)
push_licensed_feature
(
:file_locks
)
if
@project
.
licensed_feature_available?
(
:file_locks
)
end
...
...
app/controllers/projects_controller.rb
View file @
fa29f13c
...
...
@@ -34,6 +34,7 @@ class ProjectsController < Projects::ApplicationController
before_action
do
push_frontend_feature_flag
(
:refactor_blob_viewer
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:refactor_text_viewer
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:increase_page_size_exponentially
,
@project
,
default_enabled: :yaml
)
push_frontend_feature_flag
(
:paginated_tree_graphql_query
,
@project
,
default_enabled: :yaml
)
end
...
...
app/models/member.rb
View file @
fa29f13c
...
...
@@ -178,7 +178,13 @@ class Member < ApplicationRecord
after_destroy
:post_destroy_hook
,
unless: :pending?
,
if: :hook_prerequisites_met?
after_save
:log_invitation_token_cleanup
after_commit
:refresh_member_authorized_projects
,
unless: :importing?
after_commit
on:
[
:create
,
:update
],
unless: :importing?
do
refresh_member_authorized_projects
(
blocking:
true
)
end
after_commit
on:
[
:destroy
],
unless: :importing?
do
refresh_member_authorized_projects
(
blocking:
Feature
.
disabled?
(
:member_destroy_async_auth_refresh
,
type: :ops
))
end
default_value_for
:notification_level
,
NotificationSetting
.
levels
[
:global
]
...
...
@@ -395,8 +401,8 @@ class Member < ApplicationRecord
# transaction has been committed, resulting in the job either throwing an
# error or not doing any meaningful work.
# rubocop: disable CodeReuse/ServiceClass
def
refresh_member_authorized_projects
UserProjectAccessChangedService
.
new
(
user_id
).
execute
def
refresh_member_authorized_projects
(
blocking
:)
UserProjectAccessChangedService
.
new
(
user_id
).
execute
(
blocking:
blocking
)
end
# rubocop: enable CodeReuse/ServiceClass
...
...
app/models/members/group_member.rb
View file @
fa29f13c
...
...
@@ -50,8 +50,10 @@ class GroupMember < Member
{
group:
group
}
end
private
override
:refresh_member_authorized_projects
def
refresh_member_authorized_projects
def
refresh_member_authorized_projects
(
blocking
:)
# Here, `destroyed_by_association` will be present if the
# GroupMember is being destroyed due to the `dependent: :destroy`
# callback on Group. In this case, there is no need to refresh the
...
...
@@ -63,8 +65,6 @@ class GroupMember < Member
super
end
private
def
access_level_inclusion
return
if
access_level
.
in?
(
Gitlab
::
Access
.
all_values
)
...
...
app/models/members/project_member.rb
View file @
fa29f13c
...
...
@@ -90,24 +90,28 @@ class ProjectMember < Member
{
project:
project
}
end
private
override
:refresh_member_authorized_projects
def
refresh_member_authorized_projects
def
refresh_member_authorized_projects
(
blocking
:)
return
super
unless
Feature
.
enabled?
(
:specialized_service_for_project_member_auth_refresh
)
return
unless
user
# rubocop:disable CodeReuse/ServiceClass
AuthorizedProjectUpdate
::
ProjectRecalculatePerUserService
.
new
(
project
,
user
).
execute
if
blocking
AuthorizedProjectUpdate
::
ProjectRecalculatePerUserService
.
new
(
project
,
user
).
execute
else
AuthorizedProjectUpdate
::
ProjectRecalculatePerUserWorker
.
perform_async
(
project
.
id
,
user
.
id
)
end
# Until we compare the inconsistency rates of the new, specialized service and
# the old approach, we still run AuthorizedProjectsWorker
# but with some delay and lower urgency as a safety net.
UserProjectAccessChangedService
.
new
(
user_id
)
.
execute
(
blocking:
false
,
priority:
UserProjectAccessChangedService
::
LOW_PRIORITY
)
.
execute
(
blocking:
false
,
priority:
UserProjectAccessChangedService
::
LOW_PRIORITY
)
# rubocop:enable CodeReuse/ServiceClass
end
private
def
send_invite
run_after_commit_or_now
{
notification_service
.
invite_project_member
(
self
,
@raw_invite_token
)
}
...
...
app/models/user.rb
View file @
fa29f13c
...
...
@@ -318,6 +318,7 @@ class User < ApplicationRecord
delegate
:webauthn_xid
,
:webauthn_xid
=
,
to: :user_detail
,
allow_nil:
true
delegate
:pronouns
,
:pronouns
=
,
to: :user_detail
,
allow_nil:
true
delegate
:pronunciation
,
:pronunciation
=
,
to: :user_detail
,
allow_nil:
true
delegate
:registration_objective
,
:registration_objective
=
,
to: :user_detail
,
allow_nil:
true
accepts_nested_attributes_for
:user_preference
,
update_only:
true
accepts_nested_attributes_for
:user_detail
,
update_only:
true
...
...
app/models/user_detail.rb
View file @
fa29f13c
...
...
@@ -3,8 +3,11 @@
class
UserDetail
<
ApplicationRecord
extend
::
Gitlab
::
Utils
::
Override
include
IgnorableColumns
ignore_columns
%i[bio_html cached_markdown_version]
,
remove_with:
'13.6'
,
remove_after:
'2021-10-22'
REGISTRATION_OBJECTIVE_PAIRS
=
{
basics:
0
,
move_repository:
1
,
code_storage:
2
,
exploring:
3
,
ci:
4
,
other:
5
,
joining_team:
6
}.
freeze
belongs_to
:user
validates
:pronouns
,
length:
{
maximum:
50
}
...
...
@@ -14,6 +17,8 @@ class UserDetail < ApplicationRecord
before_save
:prevent_nil_bio
enum
registration_objective:
REGISTRATION_OBJECTIVE_PAIRS
,
_suffix:
true
private
def
prevent_nil_bio
...
...
app/workers/all_queues.yml
View file @
fa29f13c
...
...
@@ -30,6 +30,15 @@
:weight:
1
:idempotent:
true
:tags: []
-
:name: authorized_project_update:authorized_project_update_project_recalculate_per_user
:worker_name: AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker
:feature_category: :authentication_and_authorization
:has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight:
1
:idempotent:
true
:tags: []
-
:name: authorized_project_update:authorized_project_update_user_refresh_from_replica
:worker_name: AuthorizedProjectUpdate::UserRefreshFromReplicaWorker
:feature_category: :authentication_and_authorization
...
...
app/workers/authorized_project_update/project_recalculate_per_user_worker.rb
0 → 100644
View file @
fa29f13c
# frozen_string_literal: true
module
AuthorizedProjectUpdate
class
ProjectRecalculatePerUserWorker
<
ProjectRecalculateWorker
data_consistency
:always
feature_category
:authentication_and_authorization
urgency
:high
queue_namespace
:authorized_project_update
deduplicate
:until_executing
,
including_scheduled:
true
idempotent!
def
perform
(
project_id
,
user_id
)
project
=
Project
.
find_by_id
(
project_id
)
user
=
User
.
find_by_id
(
user_id
)
return
unless
project
&&
user
in_lock
(
lock_key
(
project
),
ttl:
10
.
seconds
)
do
AuthorizedProjectUpdate
::
ProjectRecalculatePerUserService
.
new
(
project
,
user
).
execute
end
end
end
end
app/workers/authorized_project_update/project_recalculate_worker.rb
View file @
fa29f13c
...
...
@@ -26,7 +26,9 @@ module AuthorizedProjectUpdate
private
def
lock_key
(
project
)
"
#{
self
.
class
.
name
.
underscore
}
/projects/
#{
project
.
id
}
"
# The self.class.name.underscore value is hardcoded here as the prefix, so that the same
# lock_key for this superclass will be used by the ProjectRecalculatePerUserWorker subclass.
"authorized_project_update/project_recalculate_worker/projects/
#{
project
.
id
}
"
end
end
end
config/feature_flags/development/refactor_text_viewer.yml
0 → 100644
View file @
fa29f13c
---
name
:
refactor_text_viewer
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70909
rollout_issue_url
:
milestone
:
'
14.4'
type
:
development
group
:
'
group::source
code'
default_enabled
:
false
config/feature_flags/ops/member_destroy_async_auth_refresh.yml
0 → 100644
View file @
fa29f13c
---
name
:
member_destroy_async_auth_refresh
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66424
rollout_issue_url
:
milestone
:
'
14.4'
type
:
ops
group
:
group::access
default_enabled
:
false
db/migrate/20210917224419_add_registration_objective_to_user_detail.rb
0 → 100644
View file @
fa29f13c
# frozen_string_literal: true
class
AddRegistrationObjectiveToUserDetail
<
Gitlab
::
Database
::
Migration
[
1.0
]
def
change
add_column
:user_details
,
:registration_objective
,
:smallint
end
end
db/schema_migrations/20210917224419
0 → 100644
View file @
fa29f13c
9204c844b22ad0d3a938ed908377c8baacdda038725a5cf105e4b11841c1ae21
\ No newline at end of file
db/structure.sql
View file @
fa29f13c
...
...
@@ -19764,6 +19764,7 @@ CREATE TABLE user_details (
provisioned_by_group_id bigint,
pronouns text,
pronunciation text,
registration_objective smallint,
CONSTRAINT check_245664af82 CHECK ((char_length(webauthn_xid) <= 100)),
CONSTRAINT check_b132136b01 CHECK ((char_length(other_role) <= 100)),
CONSTRAINT check_eeeaf8d4f0 CHECK ((char_length(pronouns) <= 50)),
ee/app/assets/javascripts/registrations/welcome/jobs_to_be_done.js
View file @
fa29f13c
...
...
@@ -4,7 +4,7 @@ import Tracking from '~/tracking';
const
select
=
document
.
querySelector
(
'
.js-jobs-to-be-done-dropdown
'
);
if
(
select
)
{
Tracking
.
enableFormTracking
(
{
fields
:
{
allow
:
[
'
jobs_to_be_done
'
,
'
jobs_to_be_done
_other
'
]
}
},
{
fields
:
{
allow
:
[
'
jobs_to_be_done_other
'
]
}
},
getExperimentContexts
(
'
jobs_to_be_done
'
),
);
...
...
ee/app/controllers/ee/registrations/welcome_controller.rb
View file @
fa29f13c
...
...
@@ -44,7 +44,7 @@ module EE
override
:update_params
def
update_params
clean_params
=
super
.
merge
(
params
.
require
(
:user
).
permit
(
:email_opted_in
))
clean_params
=
super
.
merge
(
params
.
require
(
:user
).
permit
(
:email_opted_in
,
:registration_objective
))
return
clean_params
unless
::
Gitlab
.
dev_env_or_com?
...
...
ee/app/helpers/ee/registrations_helper.rb
View file @
fa29f13c
...
...
@@ -10,8 +10,10 @@ module EE
super
.
merge
(
api_path:
suggestion_path
)
end
def
shuffled_jobs_to_be_done_options
jobs_to_be_done_options
.
shuffle
.
append
([
_
(
'A different reason'
),
'other'
])
def
shuffled_registration_objective_options
options
=
registration_objective_options
other
=
options
.
extract!
(
:other
).
to_a
.
flatten
options
.
to_a
.
shuffle
.
append
(
other
).
map
{
|
option
|
option
.
reverse
}
end
private
...
...
@@ -23,15 +25,10 @@ module EE
end
end
def
jobs_to_be_done_options
[
_
(
'I want to learn the basics of Git'
),
_
(
'I want to move my repository to GitLab from somewhere else'
),
_
(
'I want to store my code'
),
_
(
'I want to explore GitLab to see if it’s worth switching to'
),
_
(
'I want to use GitLab CI with my existing repository'
),
_
(
'I’m joining my team who’s already on GitLab'
)
]
def
registration_objective_options
localized_jobs_to_be_done_choices
.
merge
(
joining_team:
_
(
'I’m joining my team who’s already on GitLab'
)
)
end
end
end
ee/app/views/registrations/welcome/_jobs_to_be_done.html.haml
View file @
fa29f13c
...
...
@@ -2,10 +2,8 @@
-
e
.
try
do
.row
.form-group.col-sm-12
=
label_tag
:jobs_to_be_done
,
_
(
"I'm signing up for GitLab because:"
)
=
select_tag
:jobs_to_be_done
,
options_for_select
(
shuffled_jobs_to_be_done_options
),
include_blank:
_
(
'Please select...'
),
class:
'form-control js-jobs-to-be-done-dropdown'
=
label_tag
:user_registration_objective
,
_
(
"I'm signing up for GitLab because:"
)
=
f
.
select
:registration_objective
,
shuffled_registration_objective_options
,
{
include_blank:
_
(
'Please select...'
)
},
class:
'form-control js-jobs-to-be-done-dropdown'
.row
.form-group.col-sm-12.js-jobs-to-be-done-other-group.hidden
=
label_tag
:jobs_to_be_done_other
,
_
(
'Why are you signing up? (Optional)'
)
...
...
ee/spec/controllers/registrations/welcome_controller_spec.rb
View file @
fa29f13c
...
...
@@ -135,7 +135,8 @@ RSpec.describe Registrations::WelcomeController do
user:
{
role:
'software_developer'
,
setup_for_company:
setup_for_company
,
email_opted_in:
email_opted_in
email_opted_in:
email_opted_in
,
registration_objective:
'code_storage'
}
}
end
...
...
@@ -179,6 +180,14 @@ RSpec.describe Registrations::WelcomeController do
allow
(
::
Gitlab
).
to
receive
(
:com?
).
and_return
(
true
)
end
context
'when registration_objective field is provided'
do
it
'sets the registration_objective'
do
subject
expect
(
controller
.
current_user
.
registration_objective
).
to
eq
(
'code_storage'
)
end
end
context
'when setup for company is false'
do
context
'when the user opted in'
do
let
(
:email_opted_in
)
{
'1'
}
...
...
ee/spec/features/registrations/welcome_spec.rb
View file @
fa29f13c
...
...
@@ -59,7 +59,7 @@ RSpec.describe 'Welcome screen', :js do
it
'allows specifying other for the jobs_to_be_done experiment'
,
:experiment
do
expect
(
page
).
not_to
have_content
(
'Why are you signing up? (Optional)'
)
select
'A different reason'
,
from:
'
jobs_to_be_don
e'
select
'A different reason'
,
from:
'
user_registration_objectiv
e'
expect
(
page
).
to
have_content
(
'Why are you signing up? (Optional)'
)
...
...
ee/spec/helpers/ee/registrations_helper_spec.rb
View file @
fa29f13c
...
...
@@ -9,25 +9,17 @@ RSpec.describe EE::RegistrationsHelper do
end
end
describe
'#shuffled_
jobs_to_be_don
e_options'
do
subject
{
helper
.
shuffled_jobs_to_be_don
e_options
}
describe
'#shuffled_
registration_objectiv
e_options'
do
subject
(
:shuffled_options
)
{
helper
.
shuffled_registration_objectiv
e_options
}
let
(
:array_double
)
{
double
(
:array
)
}
it
'has values that match all UserDetail registration objective keys'
do
shuffled_option_values
=
shuffled_options
.
map
{
|
item
|
item
.
last
}
it
'uses shuffle'
do
allow
(
helper
).
to
receive
(
:jobs_to_be_done_options
).
and_return
(
array_double
)
expect
(
array_double
).
to
receive
(
:shuffle
).
and_return
([])
subject
end
it
'has a number of options'
do
expect
(
subject
.
count
).
to
eq
(
7
)
expect
(
shuffled_option_values
).
to
contain_exactly
(
*
UserDetail
.
registration_objectives
.
keys
)
end
it
'"other" is always the last option'
do
expect
(
s
ubject
.
last
).
to
eq
([
'A different reason'
,
'other'
])
expect
(
s
huffled_options
.
last
).
to
eq
([
'A different reason'
,
'other'
])
end
end
end
ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb
View file @
fa29f13c
...
...
@@ -282,7 +282,7 @@ RSpec.describe EE::Gitlab::Auth::Ldap::Sync::Group do
.
to
eq
(
::
Gitlab
::
Access
::
OWNER
)
end
it
'updates projects authorizations'
do
it
'updates projects authorizations'
,
:sidekiq_inline
do
project
=
create
(
:project
,
namespace:
group
)
group
.
add_user
(
user
,
Gitlab
::
Access
::
MAINTAINER
)
...
...
ee/spec/models/approval_state_spec.rb
View file @
fa29f13c
...
...
@@ -1336,7 +1336,7 @@ RSpec.describe ApprovalState do
expect
(
subject
.
can_approve?
(
nil
)).
to
be_falsey
end
context
'when an approver does not have access to the merge request'
do
context
'when an approver does not have access to the merge request'
,
:sidekiq_inline
do
before
do
project
.
members
.
find_by
(
user_id:
developer
.
id
).
destroy!
end
...
...
ee/spec/services/todo_service_spec.rb
View file @
fa29f13c
...
...
@@ -324,7 +324,7 @@ RSpec.describe TodoService do
let
(
:project
)
{
create
(
:project
,
:private
,
:repository
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
project
,
author:
author
)
}
context
'an approver has lost access to the project'
do
context
'an approver has lost access to the project'
,
:sidekiq_inline
do
before
do
create
(
:approver
,
user:
non_member
,
target:
project
)
project
.
members
.
find_by
(
user_id:
non_member
.
id
).
destroy
...
...
ee/spec/views/registrations/welcome/show.html.haml_spec.rb
View file @
fa29f13c
...
...
@@ -66,7 +66,7 @@ RSpec.describe 'registrations/welcome/show' do
let_it_be
(
:stubbed_experiments
)
{
{
jobs_to_be_done: :candidate
}
}
it
'renders a select and text field for additional information'
do
is_expected
.
to
have_selector
(
'select[name="
jobs_to_be_done
"]'
)
is_expected
.
to
have_selector
(
'select[name="
user[registration_objective]
"]'
)
is_expected
.
to
have_selector
(
'input[name="jobs_to_be_done_other"]'
,
visible:
false
)
end
end
...
...
spec/controllers/projects/branches_controller_spec.rb
View file @
fa29f13c
...
...
@@ -239,7 +239,7 @@ RSpec.describe Projects::BranchesController do
end
end
context
'without issue feature access'
do
context
'without issue feature access'
,
:sidekiq_inline
do
before
do
project
.
update!
(
visibility_level:
Gitlab
::
VisibilityLevel
::
PUBLIC
)
project
.
project_feature
.
update!
(
issues_access_level:
ProjectFeature
::
PRIVATE
)
...
...
spec/controllers/projects/compare_controller_spec.rb
View file @
fa29f13c
...
...
@@ -409,7 +409,7 @@ RSpec.describe Projects::CompareController do
end
end
context
'when the user does not have access to the project'
do
context
'when the user does not have access to the project'
,
:sidekiq_inline
do
before
do
project
.
team
.
truncate
project
.
update!
(
visibility:
'private'
)
...
...
spec/frontend/repository/components/blob_content_viewer_spec.js
View file @
fa29f13c
...
...
@@ -159,8 +159,13 @@ describe('Blob content viewer component', () => {
const
findBlobContent
=
()
=>
wrapper
.
findComponent
(
BlobContent
);
const
findBlobButtonGroup
=
()
=>
wrapper
.
findComponent
(
BlobButtonGroup
);
beforeEach
(()
=>
{
gon
.
features
=
{
refactorTextViewer
:
true
};
});
afterEach
(()
=>
{
wrapper
.
destroy
();
mockAxios
.
reset
();
});
it
(
'
renders a GlLoadingIcon component
'
,
()
=>
{
...
...
@@ -183,7 +188,6 @@ describe('Blob content viewer component', () => {
it
(
'
renders a BlobContent component
'
,
()
=>
{
expect
(
findBlobContent
().
props
(
'
loading
'
)).
toEqual
(
false
);
expect
(
findBlobContent
().
props
(
'
content
'
)).
toEqual
(
'
raw content
'
);
expect
(
findBlobContent
().
props
(
'
isRawContent
'
)).
toBe
(
true
);
expect
(
findBlobContent
().
props
(
'
activeViewer
'
)).
toEqual
({
fileType
:
'
text
'
,
...
...
@@ -192,6 +196,16 @@ describe('Blob content viewer component', () => {
renderError
:
null
,
});
});
describe
(
'
legacy viewers
'
,
()
=>
{
it
(
'
loads a legacy viewer when a viewer component is not available
'
,
async
()
=>
{
createComponentWithApollo
({
blobs
:
{
...
simpleMockData
,
fileType
:
'
unknown
'
}
});
await
waitForPromises
();
expect
(
mockAxios
.
history
.
get
).
toHaveLength
(
1
);
expect
(
mockAxios
.
history
.
get
[
0
].
url
).
toEqual
(
'
some_file.js?format=json&viewer=simple
'
);
});
});
});
describe
(
'
rich viewer
'
,
()
=>
{
...
...
@@ -210,7 +224,6 @@ describe('Blob content viewer component', () => {
it
(
'
renders a BlobContent component
'
,
()
=>
{
expect
(
findBlobContent
().
props
(
'
loading
'
)).
toEqual
(
false
);
expect
(
findBlobContent
().
props
(
'
content
'
)).
toEqual
(
'
raw content
'
);
expect
(
findBlobContent
().
props
(
'
isRawContent
'
)).
toBe
(
true
);
expect
(
findBlobContent
().
props
(
'
activeViewer
'
)).
toEqual
({
fileType
:
'
markup
'
,
...
...
@@ -241,18 +254,12 @@ describe('Blob content viewer component', () => {
});
describe
(
'
legacy viewers
'
,
()
=>
{
it
(
'
does not load a legacy viewer when a rich viewer is not available
'
,
async
()
=>
{
createComponentWithApollo
({
blobs
:
simpleMockData
});
await
waitForPromises
();
expect
(
mockAxios
.
history
.
get
).
toHaveLength
(
0
);
});
it
(
'
loads a legacy viewer when a rich viewer is available
'
,
async
()
=>
{
createComponentWithApollo
({
blobs
:
richMockData
});
it
(
'
loads a legacy viewer when a viewer component is not available
'
,
async
()
=>
{
createComponentWithApollo
({
blobs
:
{
...
richMockData
,
fileType
:
'
unknown
'
}
});
await
waitForPromises
();
expect
(
mockAxios
.
history
.
get
).
toHaveLength
(
1
);
expect
(
mockAxios
.
history
.
get
[
0
].
url
).
toEqual
(
'
some_file.js?format=json&viewer=rich
'
);
});
});
...
...
spec/frontend/vue_shared/components/blob_viewers/simple_viewer_spec.js
View file @
fa29f13c
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
HIGHLIGHT_CLASS_NAME
}
from
'
~/vue_shared/components/blob_viewers/constants
'
;
import
SimpleViewer
from
'
~/vue_shared/components/blob_viewers/simple_viewer.vue
'
;
import
SourceEditor
from
'
~/vue_shared/components/source_editor.vue
'
;
describe
(
'
Blob Simple Viewer component
'
,
()
=>
{
let
wrapper
;
const
contentMock
=
`<span id="LC1">First</span>\n<span id="LC2">Second</span>\n<span id="LC3">Third</span>`
;
const
blobHash
=
'
foo-bar
'
;
function
createComponent
(
content
=
contentMock
,
isRawContent
=
false
,
isRefactorFlagEnabled
=
false
,
)
{
function
createComponent
(
content
=
contentMock
,
isRawContent
=
false
)
{
wrapper
=
shallowMount
(
SimpleViewer
,
{
provide
:
{
blobHash
,
glFeatures
:
{
refactorBlobViewer
:
isRefactorFlagEnabled
,
},
},
propsData
:
{
content
,
...
...
@@ -94,32 +85,4 @@ describe('Blob Simple Viewer component', () => {
});
});
});
describe
(
'
Vue refactoring to use Source Editor
'
,
()
=>
{
const
findSourceEditor
=
()
=>
wrapper
.
find
(
SourceEditor
);
it
.
each
`
doesRender | condition | isRawContent | isRefactorFlagEnabled
${
'
Does not
'
}
|
${
'
rawContent is not specified
'
}
|
${
false
}
|
${
true
}
${
'
Does not
'
}
|
${
'
feature flag is disabled is not specified
'
}
|
${
true
}
|
${
false
}
${
'
Does not
'
}
|
${
'
both, the FF and rawContent are not specified
'
}
|
${
false
}
|
${
false
}
${
'
Does
'
}
|
${
'
both, the FF and rawContent are specified
'
}
|
${
true
}
|
${
true
}
`
(
'
$doesRender render Source Editor component in readonly mode when $condition
'
,
async
({
isRawContent
,
isRefactorFlagEnabled
}
=
{})
=>
{
createComponent
(
'
raw content
'
,
isRawContent
,
isRefactorFlagEnabled
);
await
waitForPromises
();
if
(
isRawContent
&&
isRefactorFlagEnabled
)
{
expect
(
findSourceEditor
().
exists
()).
toBe
(
true
);
expect
(
findSourceEditor
().
props
(
'
value
'
)).
toBe
(
'
raw content
'
);
expect
(
findSourceEditor
().
props
(
'
fileName
'
)).
toBe
(
'
test.js
'
);
expect
(
findSourceEditor
().
props
(
'
editorOptions
'
)).
toEqual
({
readOnly
:
true
});
}
else
{
expect
(
findSourceEditor
().
exists
()).
toBe
(
false
);
}
},
);
});
});
spec/graphql/types/project_type_spec.rb
View file @
fa29f13c
...
...
@@ -187,7 +187,7 @@ RSpec.describe GitlabSchema.types['Project'] do
expect
(
analyzer
[
'enabled'
]).
to
eq
(
true
)
end
context
"with guest user"
do
context
'with guest user'
do
before
do
project
.
add_guest
(
user
)
end
...
...
@@ -195,7 +195,7 @@ RSpec.describe GitlabSchema.types['Project'] do
context
'when project is private'
do
let
(
:project
)
{
create
(
:project
,
:private
,
:repository
)
}
it
"returns no configuration"
do
it
'returns no configuration'
do
secure_analyzers_prefix
=
subject
.
dig
(
'data'
,
'project'
,
'sastCiConfiguration'
)
expect
(
secure_analyzers_prefix
).
to
be_nil
end
...
...
@@ -215,7 +215,7 @@ RSpec.describe GitlabSchema.types['Project'] do
end
end
context
"with non-member user"
do
context
'with non-member user'
,
:sidekiq_inline
do
before
do
project
.
team
.
truncate
end
...
...
@@ -223,7 +223,7 @@ RSpec.describe GitlabSchema.types['Project'] do
context
'when project is private'
do
let
(
:project
)
{
create
(
:project
,
:private
,
:repository
)
}
it
"returns no configuration"
do
it
'returns no configuration'
do
secure_analyzers_prefix
=
subject
.
dig
(
'data'
,
'project'
,
'sastCiConfiguration'
)
expect
(
secure_analyzers_prefix
).
to
be_nil
end
...
...
@@ -241,7 +241,7 @@ RSpec.describe GitlabSchema.types['Project'] do
end
context
'when repository is accessible only by team members'
do
it
"returns no configuration"
do
it
'returns no configuration'
do
project
.
project_feature
.
update!
(
merge_requests_access_level:
ProjectFeature
::
DISABLED
,
builds_access_level:
ProjectFeature
::
DISABLED
,
...
...
spec/lib/gitlab/middleware/go_spec.rb
View file @
fa29f13c
...
...
@@ -98,7 +98,7 @@ RSpec.describe Gitlab::Middleware::Go do
end
end
context
'without access to the project'
do
context
'without access to the project'
,
:sidekiq_inline
do
before
do
project
.
team
.
find_member
(
current_user
).
destroy
end
...
...
spec/lib/gitlab/slash_commands/issue_move_spec.rb
View file @
fa29f13c
...
...
@@ -95,7 +95,7 @@ RSpec.describe Gitlab::SlashCommands::IssueMove, service: true do
end
end
context
'when the user cannot see the target project'
do
context
'when the user cannot see the target project'
,
:sidekiq_inline
do
it
'returns not found'
do
message
=
"issue move
#{
issue
.
iid
}
#{
other_project
.
full_path
}
"
other_project
.
team
.
truncate
...
...
spec/models/member_spec.rb
View file @
fa29f13c
...
...
@@ -7,11 +7,11 @@ RSpec.describe Member do
using
RSpec
::
Parameterized
::
TableSyntax
describe
"Associations"
do
describe
'Associations'
do
it
{
is_expected
.
to
belong_to
(
:user
)
}
end
describe
"Validation"
do
describe
'Validation'
do
subject
{
described_class
.
new
(
access_level:
Member
::
GUEST
)
}
it
{
is_expected
.
to
validate_presence_of
(
:user
)
}
...
...
@@ -28,7 +28,7 @@ RSpec.describe Member do
subject
{
build
(
:project_member
)
}
end
context
"when an invite email is provided"
do
context
'when an invite email is provided'
do
let_it_be
(
:project
)
{
create
(
:project
)
}
let
(
:member
)
{
build
(
:project_member
,
source:
project
,
invite_email:
"user@example.com"
,
user:
nil
)
}
...
...
@@ -37,29 +37,29 @@ RSpec.describe Member do
expect
(
member
).
to
be_valid
end
it
"requires a valid invite email"
do
it
'requires a valid invite email'
do
member
.
invite_email
=
"nope"
expect
(
member
).
not_to
be_valid
end
it
"requires a unique invite email scoped to this source"
do
it
'requires a unique invite email scoped to this source'
do
create
(
:project_member
,
source:
member
.
source
,
invite_email:
member
.
invite_email
)
expect
(
member
).
not_to
be_valid
end
end
context
"when an invite email is not provided"
do
context
'when an invite email is not provided'
do
let
(
:member
)
{
build
(
:project_member
)
}
it
"requires a user"
do
it
'requires a user'
do
member
.
user
=
nil
expect
(
member
).
not_to
be_valid
end
it
"is valid otherwise"
do
it
'is valid otherwise'
do
expect
(
member
).
to
be_valid
end
end
...
...
@@ -107,13 +107,13 @@ RSpec.describe Member do
end
end
context
"when a child member inherits its access level"
do
context
'when a child member inherits its access level'
do
let
(
:user
)
{
create
(
:user
)
}
let
(
:member
)
{
create
(
:group_member
,
:developer
,
user:
user
)
}
let
(
:child_group
)
{
create
(
:group
,
parent:
member
.
group
)
}
let
(
:child_member
)
{
build
(
:group_member
,
group:
child_group
,
user:
user
)
}
it
"requires a higher level"
do
it
'requires a higher level'
do
child_member
.
access_level
=
GroupMember
::
REPORTER
child_member
.
validate
...
...
@@ -123,7 +123,7 @@ RSpec.describe Member do
# Membership in a subgroup confers certain access rights, such as being
# able to merge or push code to protected branches.
it
"is valid with an equal level"
do
it
'is valid with an equal level'
do
child_member
.
access_level
=
GroupMember
::
DEVELOPER
child_member
.
validate
...
...
@@ -131,7 +131,7 @@ RSpec.describe Member do
expect
(
child_member
).
to
be_valid
end
it
"is valid with a higher level"
do
it
'is valid with a higher level'
do
child_member
.
access_level
=
GroupMember
::
MAINTAINER
child_member
.
validate
...
...
@@ -538,7 +538,7 @@ RSpec.describe Member do
end
end
describe
"Delegate methods"
do
describe
'Delegate methods'
do
it
{
is_expected
.
to
respond_to
(
:user_name
)
}
it
{
is_expected
.
to
respond_to
(
:user_email
)
}
end
...
...
@@ -608,29 +608,29 @@ RSpec.describe Member do
end
end
describe
"#accept_invite!"
do
describe
'#accept_invite!'
do
let!
(
:member
)
{
create
(
:project_member
,
invite_email:
"user@example.com"
,
user:
nil
)
}
let
(
:user
)
{
create
(
:user
)
}
it
"resets the invite token"
do
it
'resets the invite token'
do
member
.
accept_invite!
(
user
)
expect
(
member
.
invite_token
).
to
be_nil
end
it
"sets the invite accepted timestamp"
do
it
'sets the invite accepted timestamp'
do
member
.
accept_invite!
(
user
)
expect
(
member
.
invite_accepted_at
).
not_to
be_nil
end
it
"sets the user"
do
it
'sets the user'
do
member
.
accept_invite!
(
user
)
expect
(
member
.
user
).
to
eq
(
user
)
end
it
"calls #after_accept_invite"
do
it
'calls #after_accept_invite'
do
expect
(
member
).
to
receive
(
:after_accept_invite
)
member
.
accept_invite!
(
user
)
...
...
@@ -657,26 +657,26 @@ RSpec.describe Member do
end
end
describe
"#decline_invite!"
do
describe
'#decline_invite!'
do
let!
(
:member
)
{
create
(
:project_member
,
invite_email:
"user@example.com"
,
user:
nil
)
}
it
"destroys the member"
do
it
'destroys the member'
do
member
.
decline_invite!
expect
(
member
).
to
be_destroyed
end
it
"calls #after_decline_invite"
do
it
'calls #after_decline_invite'
do
expect
(
member
).
to
receive
(
:after_decline_invite
)
member
.
decline_invite!
end
end
describe
"#generate_invite_token"
do
describe
'#generate_invite_token'
do
let!
(
:member
)
{
create
(
:project_member
,
invite_email:
"user@example.com"
,
user:
nil
)
}
it
"sets the invite token"
do
it
'sets the invite token'
do
expect
{
member
.
generate_invite_token
}.
to
change
{
member
.
invite_token
}
end
end
...
...
@@ -684,12 +684,12 @@ RSpec.describe Member do
describe
'generate invite token on create'
do
let!
(
:member
)
{
build
(
:project_member
,
invite_email:
"user@example.com"
)
}
it
"sets the invite token"
do
it
'sets the invite token'
do
expect
{
member
.
save!
}.
to
change
{
member
.
invite_token
}.
to
(
kind_of
(
String
))
end
context
'when invite was already accepted'
do
it
"does not set invite token"
do
it
'does not set invite token'
do
member
.
invite_accepted_at
=
1
.
day
.
ago
expect
{
member
.
save!
}.
not_to
change
{
member
.
invite_token
}.
from
(
nil
)
...
...
@@ -744,7 +744,7 @@ RSpec.describe Member do
end
end
describe
"#invite_to_unknown_user?"
do
describe
'#invite_to_unknown_user?'
do
subject
{
member
.
invite_to_unknown_user?
}
let
(
:member
)
{
create
(
:project_member
,
invite_email:
"user@example.com"
,
invite_token:
'1234'
,
user:
user
)
}
...
...
@@ -762,7 +762,7 @@ RSpec.describe Member do
end
end
describe
"destroying a record"
,
:delet
e
do
describe
'destroying a record'
,
:delete
,
:sidekiq_inlin
e
do
it
"refreshes user's authorized projects"
do
project
=
create
(
:project
,
:private
)
user
=
create
(
:user
)
...
...
spec/models/members/project_member_spec.rb
View file @
fa29f13c
...
...
@@ -244,12 +244,32 @@ RSpec.describe ProjectMember do
project
.
add_user
(
user
,
Gitlab
::
Access
::
GUEST
)
end
it
'changes access level'
do
expect
{
action
}.
to
change
{
user
.
can?
(
:guest_access
,
project
)
}.
from
(
true
).
to
(
false
)
context
'when :member_destroy_async_auth_refresh feature flag is enabled'
do
it
'changes access level'
,
:sidekiq_inline
do
expect
{
action
}.
to
change
{
user
.
can?
(
:guest_access
,
project
)
}.
from
(
true
).
to
(
false
)
end
it
'calls AuthorizedProjectUpdate::ProjectRecalculatePerUserWorker to recalculate authorizations'
do
expect
(
AuthorizedProjectUpdate
::
ProjectRecalculatePerUserWorker
).
to
receive
(
:perform_async
).
with
(
project
.
id
,
user
.
id
)
action
end
it_behaves_like
'calls AuthorizedProjectUpdate::UserRefreshFromReplicaWorker with a delay to update project authorizations'
end
it_behaves_like
'calls AuthorizedProjectUpdate::ProjectRecalculatePerUserService to recalculate authorizations'
it_behaves_like
'calls AuthorizedProjectUpdate::UserRefreshFromReplicaWorker with a delay to update project authorizations'
context
'when :member_destroy_async_auth_refresh feature flag is disabled'
do
before
do
stub_feature_flags
(
member_destroy_async_auth_refresh:
false
)
end
it
'changes access level'
do
expect
{
action
}.
to
change
{
user
.
can?
(
:guest_access
,
project
)
}.
from
(
true
).
to
(
false
)
end
it_behaves_like
'calls AuthorizedProjectUpdate::ProjectRecalculatePerUserService to recalculate authorizations'
it_behaves_like
'calls AuthorizedProjectUpdate::UserRefreshFromReplicaWorker with a delay to update project authorizations'
end
end
context
'when the feature flag `specialized_service_for_project_member_auth_refresh` is disabled'
do
...
...
@@ -298,7 +318,7 @@ RSpec.describe ProjectMember do
project
.
add_user
(
user
,
Gitlab
::
Access
::
GUEST
)
end
it
'changes access level'
do
it
'changes access level'
,
:sidekiq_inline
do
expect
{
action
}.
to
change
{
user
.
can?
(
:guest_access
,
project
)
}.
from
(
true
).
to
(
false
)
end
...
...
spec/models/namespace_setting_spec.rb
View file @
fa29f13c
...
...
@@ -11,6 +11,8 @@ RSpec.describe NamespaceSetting, type: :model do
it
{
is_expected
.
to
belong_to
(
:namespace
)
}
end
it
{
is_expected
.
to
define_enum_for
(
:jobs_to_be_done
).
with_values
([
:basics
,
:move_repository
,
:code_storage
,
:exploring
,
:ci
,
:other
]).
with_suffix
}
describe
"validations"
do
describe
"#default_branch_name_content"
do
let_it_be
(
:group
)
{
create
(
:group
)
}
...
...
spec/models/user_detail_spec.rb
View file @
fa29f13c
...
...
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec
.
describe
UserDetail
do
it
{
is_expected
.
to
belong_to
(
:user
)
}
it
{
is_expected
.
to
define_enum_for
(
:registration_objective
).
with_values
([
:basics
,
:move_repository
,
:code_storage
,
:exploring
,
:ci
,
:other
,
:joining_team
]).
with_suffix
}
describe
'validations'
do
describe
'#job_title'
do
...
...
spec/models/user_spec.rb
View file @
fa29f13c
This diff is collapsed.
Click to expand it.
spec/requests/api/package_files_spec.rb
View file @
fa29f13c
...
...
@@ -38,7 +38,7 @@ RSpec.describe API::PackageFiles do
expect
(
response
).
to
have_gitlab_http_status
(
:not_found
)
end
it
'returns 404 for a user without access to the project'
do
it
'returns 404 for a user without access to the project'
,
:sidekiq_inline
do
project
.
team
.
truncate
get
api
(
url
,
user
)
...
...
spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
View file @
fa29f13c
...
...
@@ -275,7 +275,7 @@ RSpec.describe MergeRequestPollCachedWidgetEntity do
expect
(
subject
[
:merge_pipeline
]).
to
be_nil
end
context
'when is merged'
do
context
'when is merged'
,
:sidekiq_inline
do
let
(
:resource
)
{
create
(
:merged_merge_request
,
source_project:
project
,
merge_commit_sha:
project
.
commit
.
id
)
}
let
(
:pipeline
)
{
create
(
:ci_empty_pipeline
,
project:
project
,
ref:
resource
.
target_branch
,
sha:
resource
.
merge_commit_sha
)
}
...
...
spec/services/merge_requests/assign_issues_service_spec.rb
View file @
fa29f13c
...
...
@@ -17,7 +17,7 @@ RSpec.describe MergeRequests::AssignIssuesService do
expect
(
service
.
assignable_issues
.
map
(
&
:id
)).
to
include
(
issue
.
id
)
end
it
'ignores issues the user cannot update assignee on'
do
it
'ignores issues the user cannot update assignee on'
,
:sidekiq_inline
do
project
.
team
.
truncate
expect
(
service
.
assignable_issues
).
to
be_empty
...
...
spec/services/merge_requests/build_service_spec.rb
View file @
fa29f13c
...
...
@@ -440,7 +440,7 @@ RSpec.describe MergeRequests::BuildService do
expect
(
merge_request
.
title
).
to
eq
(
'Closes #1234 Second commit'
)
end
it
'adds the remaining lines of the first multi-line commit message as the description'
do
it
'adds the remaining lines of the first multi-line commit message as the description'
,
:sidekiq_inline
do
expect
(
merge_request
.
description
).
to
eq
(
'Create the app'
)
end
end
...
...
spec/services/merge_requests/push_options_handler_service_spec.rb
View file @
fa29f13c
...
...
@@ -701,7 +701,7 @@ RSpec.describe MergeRequests::PushOptionsHandlerService do
let
(
:push_options
)
{
{
create:
true
}
}
let
(
:changes
)
{
new_branch_changes
}
it
'records an error'
do
it
'records an error'
,
:sidekiq_inline
do
Members
::
DestroyService
.
new
(
user1
).
execute
(
ProjectMember
.
find_by!
(
user_id:
user1
.
id
))
service
.
execute
...
...
spec/services/notes/quick_actions_service_spec.rb
View file @
fa29f13c
...
...
@@ -47,7 +47,7 @@ RSpec.describe Notes::QuickActionsService do
let
(
:note_text
)
{
"/relate
#{
other_issue
.
to_reference
}
"
}
let
(
:note
)
{
create
(
:note_on_issue
,
noteable:
issue
,
project:
project
,
note:
note_text
)
}
context
'user cannot relate issues'
do
context
'user cannot relate issues'
,
:sidekiq_inline
do
before
do
project
.
team
.
find_member
(
maintainer
.
id
).
destroy!
project
.
update!
(
visibility:
Gitlab
::
VisibilityLevel
::
PUBLIC
)
...
...
spec/services/notification_service_spec.rb
View file @
fa29f13c
...
...
@@ -3155,7 +3155,7 @@ RSpec.describe NotificationService, :mailer do
notification
.
pipeline_finished
(
pipeline
)
end
it
'does not send emails'
do
it
'does not send emails'
,
:sidekiq_inline
do
should_not_email_anyone
end
end
...
...
spec/services/projects/move_access_service_spec.rb
View file @
fa29f13c
...
...
@@ -26,7 +26,7 @@ RSpec.describe Projects::MoveAccessService do
describe
'#execute'
do
shared_examples
'move the accesses'
do
it
do
it
'moves the accesses'
,
:sidekiq_inline
do
expect
(
project_with_access
.
project_members
.
count
).
to
eq
4
expect
(
project_with_access
.
project_group_links
.
count
).
to
eq
3
expect
(
project_with_access
.
authorized_users
.
count
).
to
eq
4
...
...
spec/workers/authorized_project_update/project_recalculate_per_user_worker_spec.rb
0 → 100644
View file @
fa29f13c
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
AuthorizedProjectUpdate
::
ProjectRecalculatePerUserWorker
do
include
ExclusiveLeaseHelpers
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:user
)
{
create
(
:user
)
}
subject
(
:worker
)
{
described_class
.
new
}
include_examples
'an idempotent worker'
do
let
(
:job_args
)
{
[
project
.
id
,
user
.
id
]
}
it
'does not change authorizations when run twice'
do
project
.
add_developer
(
user
)
user
.
project_authorizations
.
delete_all
expect
{
worker
.
perform
(
project
.
id
,
user
.
id
)
}.
to
change
{
project
.
project_authorizations
.
reload
.
size
}.
by
(
1
)
expect
{
worker
.
perform
(
project
.
id
,
user
.
id
)
}.
not_to
change
{
project
.
project_authorizations
.
reload
.
size
}
end
end
describe
'#perform'
do
it
'does not fail if the project does not exist'
do
expect
do
worker
.
perform
(
non_existing_record_id
,
user
.
id
)
end
.
not_to
raise_error
end
it
'does not fail if the user does not exist'
do
expect
do
worker
.
perform
(
project
.
id
,
non_existing_record_id
)
end
.
not_to
raise_error
end
it
'calls AuthorizedProjectUpdate::ProjectRecalculatePerUserService'
do
expect_next_instance_of
(
AuthorizedProjectUpdate
::
ProjectRecalculatePerUserService
,
project
,
user
)
do
|
service
|
expect
(
service
).
to
receive
(
:execute
)
end
worker
.
perform
(
project
.
id
,
user
.
id
)
end
context
'exclusive lease'
do
let
(
:lock_key
)
{
"
#{
described_class
.
superclass
.
name
.
underscore
}
/projects/
#{
project
.
id
}
"
}
let
(
:timeout
)
{
10
.
seconds
}
context
'when exclusive lease has not been taken'
do
it
'obtains a new exclusive lease'
do
expect_to_obtain_exclusive_lease
(
lock_key
,
timeout:
timeout
)
worker
.
perform
(
project
.
id
,
user
.
id
)
end
end
context
'when exclusive lease has already been taken'
do
before
do
stub_exclusive_lease_taken
(
lock_key
,
timeout:
timeout
)
end
it
'raises an error'
do
expect
{
worker
.
perform
(
project
.
id
,
user
.
id
)
}.
to
raise_error
(
Gitlab
::
ExclusiveLeaseHelpers
::
FailedToObtainLockError
)
end
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment