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
0
Merge Requests
0
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
Léo-Paul Géneau
gitlab-ce
Commits
4f00a051
Commit
4f00a051
authored
Jan 10, 2018
by
Lin Jen-Shin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Introduce PredicateMemoization cop and fix offenses
with StrongMemoize
parent
3fde958f
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
192 additions
and
21 deletions
+192
-21
app/models/concerns/resolvable_discussion.rb
app/models/concerns/resolvable_discussion.rb
+14
-5
app/models/project.rb
app/models/project.rb
+8
-3
app/models/repository.rb
app/models/repository.rb
+6
-3
lib/gitlab/background_migration/prepare_untracked_uploads.rb
lib/gitlab/background_migration/prepare_untracked_uploads.rb
+7
-3
lib/gitlab/bare_repository_import/repository.rb
lib/gitlab/bare_repository_import/repository.rb
+8
-2
lib/gitlab/ci/pipeline/chain/skip.rb
lib/gitlab/ci/pipeline/chain/skip.rb
+5
-1
lib/gitlab/ci/stage/seed.rb
lib/gitlab/ci/stage/seed.rb
+5
-1
lib/gitlab/github_import/client.rb
lib/gitlab/github_import/client.rb
+5
-1
lib/gitlab/user_access.rb
lib/gitlab/user_access.rb
+8
-2
rubocop/cop/gitlab/predicate_memoization.rb
rubocop/cop/gitlab/predicate_memoization.rb
+39
-0
rubocop/rubocop.rb
rubocop/rubocop.rb
+1
-0
spec/rubocop/cop/gitlab/predicate_memoization_spec.rb
spec/rubocop/cop/gitlab/predicate_memoization_spec.rb
+86
-0
No files found.
app/models/concerns/resolvable_discussion.rb
View file @
4f00a051
module
ResolvableDiscussion
module
ResolvableDiscussion
extend
ActiveSupport
::
Concern
extend
ActiveSupport
::
Concern
include
::
Gitlab
::
Utils
::
StrongMemoize
included
do
included
do
# A number of properties of this `Discussion`, like `first_note` and `resolvable?`, are memoized.
# A number of properties of this `Discussion`, like `first_note` and `resolvable?`, are memoized.
...
@@ -31,27 +32,35 @@ module ResolvableDiscussion
...
@@ -31,27 +32,35 @@ module ResolvableDiscussion
end
end
def
resolvable?
def
resolvable?
@resolvable
||=
potentially_resolvable?
&&
notes
.
any?
(
&
:resolvable?
)
strong_memoize
(
:resolvable
)
do
potentially_resolvable?
&&
notes
.
any?
(
&
:resolvable?
)
end
end
end
def
resolved?
def
resolved?
@resolved
||=
resolvable?
&&
notes
.
none?
(
&
:to_be_resolved?
)
strong_memoize
(
:resolved
)
do
resolvable?
&&
notes
.
none?
(
&
:to_be_resolved?
)
end
end
end
def
first_note
def
first_note
@first_note
||=
notes
.
first
notes
.
first
end
end
def
first_note_to_resolve
def
first_note_to_resolve
return
unless
resolvable?
return
unless
resolvable?
@first_note_to_resolve
||=
notes
.
find
(
&
:to_be_resolved?
)
# rubocop:disable Gitlab/ModuleWithInstanceVariables
strong_memoize
(
:first_note_to_resolve
)
do
notes
.
find
(
&
:to_be_resolved?
)
end
end
end
def
last_resolved_note
def
last_resolved_note
return
unless
resolved?
return
unless
resolved?
@last_resolved_note
||=
resolved_notes
.
sort_by
(
&
:resolved_at
).
last
# rubocop:disable Gitlab/ModuleWithInstanceVariables
strong_memoize
(
:last_resolved_note
)
do
resolved_notes
.
sort_by
(
&
:resolved_at
).
last
end
end
end
def
resolved_notes
def
resolved_notes
...
...
app/models/project.rb
View file @
4f00a051
...
@@ -20,6 +20,7 @@ class Project < ActiveRecord::Base
...
@@ -20,6 +20,7 @@ class Project < ActiveRecord::Base
include
GroupDescendant
include
GroupDescendant
include
Gitlab
::
SQL
::
Pattern
include
Gitlab
::
SQL
::
Pattern
include
DeploymentPlatform
include
DeploymentPlatform
include
::
Gitlab
::
Utils
::
StrongMemoize
extend
Gitlab
::
ConfigHelper
extend
Gitlab
::
ConfigHelper
extend
Gitlab
::
CurrentSettings
extend
Gitlab
::
CurrentSettings
...
@@ -993,9 +994,13 @@ class Project < ActiveRecord::Base
...
@@ -993,9 +994,13 @@ class Project < ActiveRecord::Base
end
end
def
repo_exists?
def
repo_exists?
@repo_exists
||=
repository
.
exists?
strong_memoize
(
:repo_exists
)
do
rescue
begin
@repo_exists
=
false
repository
.
exists?
rescue
false
end
end
end
end
def
root_ref?
(
branch
)
def
root_ref?
(
branch
)
...
...
app/models/repository.rb
View file @
4f00a051
...
@@ -895,15 +895,18 @@ class Repository
...
@@ -895,15 +895,18 @@ class Repository
branch
=
Gitlab
::
Git
::
Branch
.
find
(
self
,
branch_or_name
)
branch
=
Gitlab
::
Git
::
Branch
.
find
(
self
,
branch_or_name
)
if
branch
if
branch
@root_ref_sha
||=
commit
(
root_ref
).
sha
same_head
=
branch
.
target
==
root_ref_sha
same_head
=
branch
.
target
==
@root_ref_sha
merged
=
ancestor?
(
branch
.
target
,
root_ref_sha
)
merged
=
ancestor?
(
branch
.
target
,
@root_ref_sha
)
!
same_head
&&
merged
!
same_head
&&
merged
else
else
nil
nil
end
end
end
end
def
root_ref_sha
@root_ref_sha
||=
commit
(
root_ref
).
sha
end
delegate
:merged_branch_names
,
to: :raw_repository
delegate
:merged_branch_names
,
to: :raw_repository
def
merge_base
(
first_commit_id
,
second_commit_id
)
def
merge_base
(
first_commit_id
,
second_commit_id
)
...
...
lib/gitlab/background_migration/prepare_untracked_uploads.rb
View file @
4f00a051
...
@@ -7,6 +7,7 @@ module Gitlab
...
@@ -7,6 +7,7 @@ module Gitlab
class
PrepareUntrackedUploads
# rubocop:disable Metrics/ClassLength
class
PrepareUntrackedUploads
# rubocop:disable Metrics/ClassLength
# For bulk_queue_background_migration_jobs_by_range
# For bulk_queue_background_migration_jobs_by_range
include
Database
::
MigrationHelpers
include
Database
::
MigrationHelpers
include
::
Gitlab
::
Utils
::
StrongMemoize
FIND_BATCH_SIZE
=
500
FIND_BATCH_SIZE
=
500
RELATIVE_UPLOAD_DIR
=
"uploads"
.
freeze
RELATIVE_UPLOAD_DIR
=
"uploads"
.
freeze
...
@@ -142,7 +143,9 @@ module Gitlab
...
@@ -142,7 +143,9 @@ module Gitlab
end
end
def
postgresql?
def
postgresql?
@postgresql
||=
Gitlab
::
Database
.
postgresql?
strong_memoize
(
:postgresql
)
do
Gitlab
::
Database
.
postgresql?
end
end
end
def
can_bulk_insert_and_ignore_duplicates?
def
can_bulk_insert_and_ignore_duplicates?
...
@@ -150,8 +153,9 @@ module Gitlab
...
@@ -150,8 +153,9 @@ module Gitlab
end
end
def
postgresql_pre_9_5?
def
postgresql_pre_9_5?
@postgresql_pre_9_5
||=
postgresql?
&&
strong_memoize
(
:postgresql_pre_9_5
)
do
Gitlab
::
Database
.
version
.
to_f
<
9.5
postgresql?
&&
Gitlab
::
Database
.
version
.
to_f
<
9.5
end
end
end
def
schedule_populate_untracked_uploads_jobs
def
schedule_populate_untracked_uploads_jobs
...
...
lib/gitlab/bare_repository_import/repository.rb
View file @
4f00a051
module
Gitlab
module
Gitlab
module
BareRepositoryImport
module
BareRepositoryImport
class
Repository
class
Repository
include
::
Gitlab
::
Utils
::
StrongMemoize
attr_reader
:group_path
,
:project_name
,
:repo_path
attr_reader
:group_path
,
:project_name
,
:repo_path
def
initialize
(
root_path
,
repo_path
)
def
initialize
(
root_path
,
repo_path
)
...
@@ -41,11 +43,15 @@ module Gitlab
...
@@ -41,11 +43,15 @@ module Gitlab
private
private
def
wiki?
def
wiki?
@wiki
||=
repo_path
.
end_with?
(
'.wiki.git'
)
strong_memoize
(
:wiki
)
do
repo_path
.
end_with?
(
'.wiki.git'
)
end
end
end
def
hashed?
def
hashed?
@hashed
||=
repo_relative_path
.
include?
(
'@hashed'
)
strong_memoize
(
:hashed
)
do
repo_relative_path
.
include?
(
'@hashed'
)
end
end
end
def
repo_relative_path
def
repo_relative_path
...
...
lib/gitlab/ci/pipeline/chain/skip.rb
View file @
4f00a051
...
@@ -3,6 +3,8 @@ module Gitlab
...
@@ -3,6 +3,8 @@ module Gitlab
module
Pipeline
module
Pipeline
module
Chain
module
Chain
class
Skip
<
Chain
::
Base
class
Skip
<
Chain
::
Base
include
::
Gitlab
::
Utils
::
StrongMemoize
SKIP_PATTERN
=
/\[(ci[ _-]skip|skip[ _-]ci)\]/i
SKIP_PATTERN
=
/\[(ci[ _-]skip|skip[ _-]ci)\]/i
def
perform!
def
perform!
...
@@ -24,7 +26,9 @@ module Gitlab
...
@@ -24,7 +26,9 @@ module Gitlab
def
commit_message_skips_ci?
def
commit_message_skips_ci?
return
false
unless
@pipeline
.
git_commit_message
return
false
unless
@pipeline
.
git_commit_message
@skipped
||=
!!
(
@pipeline
.
git_commit_message
=~
SKIP_PATTERN
)
strong_memoize
(
:commit_message_skips_ci
)
do
!!
(
@pipeline
.
git_commit_message
=~
SKIP_PATTERN
)
end
end
end
end
end
end
end
...
...
lib/gitlab/ci/stage/seed.rb
View file @
4f00a051
...
@@ -2,6 +2,8 @@ module Gitlab
...
@@ -2,6 +2,8 @@ module Gitlab
module
Ci
module
Ci
module
Stage
module
Stage
class
Seed
class
Seed
include
::
Gitlab
::
Utils
::
StrongMemoize
attr_reader
:pipeline
attr_reader
:pipeline
delegate
:project
,
to: :pipeline
delegate
:project
,
to: :pipeline
...
@@ -50,7 +52,9 @@ module Gitlab
...
@@ -50,7 +52,9 @@ module Gitlab
private
private
def
protected_ref?
def
protected_ref?
@protected_ref
||=
project
.
protected_for?
(
pipeline
.
ref
)
strong_memoize
(
:protected_ref
)
do
project
.
protected_for?
(
pipeline
.
ref
)
end
end
end
end
end
end
end
...
...
lib/gitlab/github_import/client.rb
View file @
4f00a051
...
@@ -14,6 +14,8 @@ module Gitlab
...
@@ -14,6 +14,8 @@ module Gitlab
# puts label.name
# puts label.name
# end
# end
class
Client
class
Client
include
::
Gitlab
::
Utils
::
StrongMemoize
attr_reader
:octokit
attr_reader
:octokit
# A single page of data and the corresponding page number.
# A single page of data and the corresponding page number.
...
@@ -173,7 +175,9 @@ module Gitlab
...
@@ -173,7 +175,9 @@ module Gitlab
end
end
def
rate_limiting_enabled?
def
rate_limiting_enabled?
@rate_limiting_enabled
||=
api_endpoint
.
include?
(
'.github.com'
)
strong_memoize
(
:rate_limiting_enabled
)
do
api_endpoint
.
include?
(
'.github.com'
)
end
end
end
def
api_endpoint
def
api_endpoint
...
...
lib/gitlab/user_access.rb
View file @
4f00a051
...
@@ -16,8 +16,10 @@ module Gitlab
...
@@ -16,8 +16,10 @@ module Gitlab
def
can_do_action?
(
action
)
def
can_do_action?
(
action
)
return
false
unless
can_access_git?
return
false
unless
can_access_git?
@permission_cache
||=
{}
permission_cache
[
action
]
=
@permission_cache
[
action
]
||=
user
.
can?
(
action
,
project
)
permission_cache
.
fetch
(
action
)
do
user
.
can?
(
action
,
project
)
end
end
end
def
cannot_do_action?
(
action
)
def
cannot_do_action?
(
action
)
...
@@ -88,6 +90,10 @@ module Gitlab
...
@@ -88,6 +90,10 @@ module Gitlab
private
private
def
permission_cache
@permission_cache
||=
{}
end
def
can_access_git?
def
can_access_git?
user
&&
user
.
can?
(
:access_git
)
user
&&
user
.
can?
(
:access_git
)
end
end
...
...
rubocop/cop/gitlab/predicate_memoization.rb
0 → 100644
View file @
4f00a051
module
RuboCop
module
Cop
module
Gitlab
class
PredicateMemoization
<
RuboCop
::
Cop
::
Cop
MSG
=
<<~
EOL
.
freeze
Avoid using `@value ||= query` inside predicate methods in order to
properly memoize `false` or `nil` values.
https://docs.gitlab.com/ee/development/utilities.html#strongmemoize
EOL
def
on_def
(
node
)
return
unless
predicate_method?
(
node
)
select_offenses
(
node
).
each
do
|
offense
|
add_offense
(
offense
,
location: :expression
)
end
end
private
def
predicate_method?
(
node
)
node
.
method_name
.
to_s
.
end_with?
(
'?'
)
end
def
or_ivar_assignment?
(
or_assignment
)
lhs
=
or_assignment
.
each_child_node
.
first
lhs
.
ivasgn_type?
end
def
select_offenses
(
node
)
node
.
each_descendant
(
:or_asgn
).
select
do
|
or_assignment
|
or_ivar_assignment?
(
or_assignment
)
end
end
end
end
end
end
rubocop/rubocop.rb
View file @
4f00a051
require_relative
'cop/gitlab/module_with_instance_variables'
require_relative
'cop/gitlab/module_with_instance_variables'
require_relative
'cop/gitlab/predicate_memoization'
require_relative
'cop/include_sidekiq_worker'
require_relative
'cop/include_sidekiq_worker'
require_relative
'cop/line_break_around_conditional_block'
require_relative
'cop/line_break_around_conditional_block'
require_relative
'cop/migration/add_column'
require_relative
'cop/migration/add_column'
...
...
spec/rubocop/cop/gitlab/predicate_memoization_spec.rb
0 → 100644
View file @
4f00a051
require
'spec_helper'
require
'rubocop'
require
'rubocop/rspec/support'
require_relative
'../../../../rubocop/cop/gitlab/predicate_memoization'
describe
RuboCop
::
Cop
::
Gitlab
::
PredicateMemoization
do
include
CopHelper
subject
(
:cop
)
{
described_class
.
new
}
shared_examples
(
'registering offense'
)
do
|
options
|
let
(
:offending_lines
)
{
options
[
:offending_lines
]
}
it
'registers an offense when a predicate method is memoizing via ivar'
do
inspect_source
(
source
)
aggregate_failures
do
expect
(
cop
.
offenses
.
size
).
to
eq
(
offending_lines
.
size
)
expect
(
cop
.
offenses
.
map
(
&
:line
)).
to
eq
(
offending_lines
)
end
end
end
shared_examples
(
'not registering offense'
)
do
it
'does not register offenses'
do
inspect_source
(
source
)
expect
(
cop
.
offenses
).
to
be_empty
end
end
context
'when source is a predicate method memoizing via ivar'
do
it_behaves_like
'registering offense'
,
offending_lines:
[
3
]
do
let
(
:source
)
do
<<~
RUBY
class C
def really?
@really ||= true
end
end
RUBY
end
end
it_behaves_like
'registering offense'
,
offending_lines:
[
4
]
do
let
(
:source
)
do
<<~
RUBY
class C
def really?
value = true
@really ||= value
end
end
RUBY
end
end
end
context
'when source is a predicate method using ivar with assignment'
do
it_behaves_like
'not registering offense'
do
let
(
:source
)
do
<<~
RUBY
class C
def really?
@really = true
end
end
RUBY
end
end
end
context
'when source is a regular method memoizing via ivar'
do
it_behaves_like
'not registering offense'
do
let
(
:source
)
do
<<~
RUBY
class C
def really
@really ||= true
end
end
RUBY
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