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
6b0f410e
Commit
6b0f410e
authored
Jul 29, 2021
by
Lee Tickett
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Expose timelogs in GraphQL query type
Changelog: added
parent
03903b0a
Changes
23
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
643 additions
and
117 deletions
+643
-117
app/graphql/resolvers/concerns/resolves_ids.rb
app/graphql/resolvers/concerns/resolves_ids.rb
+16
-0
app/graphql/resolvers/concerns/resolves_snippets.rb
app/graphql/resolvers/concerns/resolves_snippets.rb
+2
-12
app/graphql/resolvers/snippets_resolver.rb
app/graphql/resolvers/snippets_resolver.rb
+1
-0
app/graphql/resolvers/timelog_resolver.rb
app/graphql/resolvers/timelog_resolver.rb
+74
-27
app/graphql/types/project_type.rb
app/graphql/types/project_type.rb
+7
-0
app/graphql/types/query_type.rb
app/graphql/types/query_type.rb
+7
-0
app/graphql/types/user_interface.rb
app/graphql/types/user_interface.rb
+7
-0
app/models/group.rb
app/models/group.rb
+4
-0
app/models/timelog.rb
app/models/timelog.rb
+8
-0
app/models/user.rb
app/models/user.rb
+2
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+139
-4
doc/user/project/time_tracking.md
doc/user/project/time_tracking.md
+3
-0
ee/spec/graphql/ee/types/group_type_spec.rb
ee/spec/graphql/ee/types/group_type_spec.rb
+0
-11
spec/graphql/resolvers/concerns/resolves_ids_spec.rb
spec/graphql/resolvers/concerns/resolves_ids_spec.rb
+43
-0
spec/graphql/resolvers/timelog_resolver_spec.rb
spec/graphql/resolvers/timelog_resolver_spec.rb
+250
-59
spec/graphql/types/group_type_spec.rb
spec/graphql/types/group_type_spec.rb
+10
-1
spec/graphql/types/merge_requests/reviewer_type_spec.rb
spec/graphql/types/merge_requests/reviewer_type_spec.rb
+1
-0
spec/graphql/types/project_type_spec.rb
spec/graphql/types/project_type_spec.rb
+10
-1
spec/graphql/types/query_type_spec.rb
spec/graphql/types/query_type_spec.rb
+11
-0
spec/graphql/types/user_type_spec.rb
spec/graphql/types/user_type_spec.rb
+10
-0
spec/models/group_spec.rb
spec/models/group_spec.rb
+15
-0
spec/models/timelog_spec.rb
spec/models/timelog_spec.rb
+22
-2
spec/models/user_spec.rb
spec/models/user_spec.rb
+1
-0
No files found.
app/graphql/resolvers/concerns/resolves_ids.rb
0 → 100644
View file @
6b0f410e
# frozen_string_literal: true
module
ResolvesIds
extend
ActiveSupport
::
Concern
def
resolve_ids
(
ids
,
type
)
Array
.
wrap
(
ids
).
map
do
|
id
|
next
unless
id
.
present?
# TODO: remove this line when the compatibility layer is removed
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
id
=
type
.
coerce_isolated_input
(
id
)
id
.
model_id
end
.
compact
end
end
app/graphql/resolvers/concerns/resolves_snippets.rb
View file @
6b0f410e
...
...
@@ -2,6 +2,7 @@
module
ResolvesSnippets
extend
ActiveSupport
::
Concern
include
ResolvesIds
included
do
type
Types
::
SnippetType
.
connection_type
,
null:
true
...
...
@@ -27,22 +28,11 @@ module ResolvesSnippets
def
snippet_finder_params
(
args
)
{
ids:
resolve_ids
(
args
[
:ids
]),
ids:
resolve_ids
(
args
[
:ids
]
,
::
Types
::
GlobalIDType
[
::
Snippet
]
),
scope:
args
[
:visibility
]
}.
merge
(
options_by_type
(
args
[
:type
]))
end
def
resolve_ids
(
ids
,
type
=
::
Types
::
GlobalIDType
[
::
Snippet
])
Array
.
wrap
(
ids
).
map
do
|
id
|
next
unless
id
.
present?
# TODO: remove this line when the compatibility layer is removed
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
id
=
type
.
coerce_isolated_input
(
id
)
id
.
model_id
end
.
compact
end
def
options_by_type
(
type
)
case
type
when
'personal'
...
...
app/graphql/resolvers/snippets_resolver.rb
View file @
6b0f410e
...
...
@@ -3,6 +3,7 @@
module
Resolvers
class
SnippetsResolver
<
BaseResolver
include
ResolvesIds
include
ResolvesSnippets
ERROR_MESSAGE
=
'Filtering by both an author and a project is not supported'
...
...
app/graphql/resolvers/timelog_resolver.rb
View file @
6b0f410e
...
...
@@ -3,33 +3,50 @@
module
Resolvers
class
TimelogResolver
<
BaseResolver
include
LooksAhead
include
ResolvesIds
type
::
Types
::
TimelogType
.
connection_type
,
null:
false
argument
:start_date
,
Types
::
TimeType
,
required:
false
,
description:
'List time
logs within a date range where the logged date is equal to or after startDate.'
description:
'List timelogs within a date range where the logged date is equal to or after startDate.'
argument
:end_date
,
Types
::
TimeType
,
required:
false
,
description:
'List time
logs within a date range where the logged date is equal to or before endDate.'
description:
'List timelogs within a date range where the logged date is equal to or before endDate.'
argument
:start_time
,
Types
::
TimeType
,
required:
false
,
description:
'List time
-
logs within a time range where the logged time is equal to or after startTime.'
description:
'List timelogs within a time range where the logged time is equal to or after startTime.'
argument
:end_time
,
Types
::
TimeType
,
required:
false
,
description:
'List time-logs within a time range where the logged time is equal to or before endTime.'
description:
'List timelogs within a time range where the logged time is equal to or before endTime.'
argument
:project_id
,
::
Types
::
GlobalIDType
[
::
Project
],
required:
false
,
description:
'List timelogs for a project.'
argument
:group_id
,
::
Types
::
GlobalIDType
[
::
Group
],
required:
false
,
description:
'List timelogs for a group.'
argument
:username
,
GraphQL
::
Types
::
String
,
required:
false
,
description:
'List timelogs for a user.'
def
resolve_with_lookahead
(
**
args
)
build_timelogs
validate_args!
(
object
,
args
)
timelogs
=
object
&
.
timelogs
||
Timelog
.
limit
(
GitlabSchema
.
default_max_page_size
)
if
args
.
any?
validate_args!
(
args
)
build_parsed_args
(
args
)
validate_time_difference!
apply_time_filter
args
=
parse_datetime_args
(
args
)
timelogs
=
apply_user_filter
(
timelogs
,
args
)
timelogs
=
apply_project_filter
(
timelogs
,
args
)
timelogs
=
apply_time_filter
(
timelogs
,
args
)
timelogs
=
apply_group_filter
(
timelogs
,
args
)
end
apply_lookahead
(
timelogs
)
...
...
@@ -37,30 +54,32 @@ module Resolvers
private
attr_reader
:parsed_args
,
:timelogs
def
preloads
{
note:
[
:note
]
}
end
def
validate_args!
(
args
)
if
args
[
:start_time
]
&&
args
[
:start_date
]
def
validate_args!
(
object
,
args
)
if
args
.
empty?
&&
object
.
nil?
raise_argument_error
(
'Provide at least one argument'
)
elsif
args
[
:start_time
]
&&
args
[
:start_date
]
raise_argument_error
(
'Provide either a start date or time, but not both'
)
elsif
args
[
:end_time
]
&&
args
[
:end_date
]
raise_argument_error
(
'Provide either an end date or time, but not both'
)
end
end
def
build_parsed
_args
(
args
)
def
parse_datetime
_args
(
args
)
if
times_provided?
(
args
)
@parsed_args
=
args
args
else
@
parsed_args
=
args
.
except
(
:start_date
,
:end_date
)
parsed_args
=
args
.
except
(
:start_date
,
:end_date
)
@parsed_args
[
:start_time
]
=
args
[
:start_date
].
beginning_of_day
if
args
[
:start_date
]
@parsed_args
[
:end_time
]
=
args
[
:end_date
].
end_of_day
if
args
[
:end_date
]
parsed_args
[
:start_time
]
=
args
[
:start_date
].
beginning_of_day
if
args
[
:start_date
]
parsed_args
[
:end_time
]
=
args
[
:end_date
].
end_of_day
if
args
[
:end_date
]
parsed_args
end
end
...
...
@@ -68,23 +87,51 @@ module Resolvers
args
[
:start_time
]
&&
args
[
:end_time
]
end
def
validate_time_difference!
return
unless
end_time_before_start_time?
def
validate_time_difference!
(
args
)
return
unless
end_time_before_start_time?
(
args
)
raise_argument_error
(
'Start argument must be before End argument'
)
end
def
end_time_before_start_time?
times_provided?
(
parsed_args
)
&&
parsed_args
[
:end_time
]
<
parsed_
args
[
:start_time
]
def
end_time_before_start_time?
(
args
)
times_provided?
(
args
)
&&
args
[
:end_time
]
<
args
[
:start_time
]
end
def
build_timelogs
@timelogs
=
Timelog
.
in_group
(
object
)
def
apply_project_filter
(
timelogs
,
args
)
return
timelogs
unless
args
[
:project_id
]
project
=
resolve_ids
(
args
[
:project_id
],
::
Types
::
GlobalIDType
[
::
Project
])
timelogs
.
in_project
(
project
)
end
def
apply_time_filter
@timelogs
=
timelogs
.
at_or_after
(
parsed_args
[
:start_time
])
if
parsed_args
[
:start_time
]
@timelogs
=
timelogs
.
at_or_before
(
parsed_args
[
:end_time
])
if
parsed_args
[
:end_time
]
def
apply_group_filter
(
timelogs
,
args
)
return
timelogs
unless
args
[
:group_id
]
group
=
Group
.
find_by_id
(
resolve_ids
(
args
[
:group_id
],
::
Types
::
GlobalIDType
[
::
Group
]))
timelogs
.
in_group
(
group
)
end
def
apply_user_filter
(
timelogs
,
args
)
return
timelogs
unless
args
[
:username
]
user
=
UserFinder
.
new
(
args
[
:username
]).
find_by_username!
timelogs
.
for_user
(
user
)
end
def
apply_time_filter
(
timelogs
,
args
)
return
timelogs
unless
args
[
:start_time
]
||
args
[
:end_time
]
validate_time_difference!
(
args
)
if
args
[
:start_time
]
timelogs
=
timelogs
.
at_or_after
(
args
[
:start_time
])
end
if
args
[
:end_time
]
timelogs
=
timelogs
.
at_or_before
(
args
[
:end_time
])
end
timelogs
end
def
raise_argument_error
(
message
)
...
...
app/graphql/types/project_type.rb
View file @
6b0f410e
...
...
@@ -354,6 +354,13 @@ module Types
description:
'The CI Job Tokens scope of access.'
,
resolver:
Resolvers
::
Ci
::
JobTokenScopeResolver
field
:timelogs
,
Types
::
TimelogType
.
connection_type
,
null:
true
,
description:
'Time logged on issues and merge requests in the project.'
,
extras:
[
:lookahead
],
complexity:
5
,
resolver:
::
Resolvers
::
TimelogResolver
def
label
(
title
:)
BatchLoader
::
GraphQL
.
for
(
title
).
batch
(
key:
project
)
do
|
titles
,
loader
,
args
|
LabelsFinder
...
...
app/graphql/types/query_type.rb
View file @
6b0f410e
...
...
@@ -131,6 +131,13 @@ module Types
field
:ci_config
,
resolver:
Resolvers
::
Ci
::
ConfigResolver
,
complexity:
126
# AUTHENTICATED_MAX_COMPLEXITY / 2 + 1
field
:timelogs
,
Types
::
TimelogType
.
connection_type
,
null:
true
,
description:
'Find timelogs visible to the current user.'
,
extras:
[
:lookahead
],
complexity:
5
,
resolver:
::
Resolvers
::
TimelogResolver
def
design_management
DesignManagementObject
.
new
(
nil
)
end
...
...
app/graphql/types/user_interface.rb
View file @
6b0f410e
...
...
@@ -104,6 +104,13 @@ module Types
Types
::
UserCalloutType
.
connection_type
,
null:
true
,
description:
'User callouts that belong to the user.'
field
:timelogs
,
Types
::
TimelogType
.
connection_type
,
null:
true
,
description:
'Time logged by the user.'
,
extras:
[
:lookahead
],
complexity:
5
,
resolver:
::
Resolvers
::
TimelogResolver
definition_methods
do
def
resolve_type
(
object
,
context
)
...
...
app/models/group.rb
View file @
6b0f410e
...
...
@@ -730,6 +730,10 @@ class Group < Namespace
end
# rubocop: enable CodeReuse/ServiceClass
def
timelogs
Timelog
.
in_group
(
self
)
end
private
def
max_member_access
(
user_ids
)
...
...
app/models/timelog.rb
View file @
6b0f410e
...
...
@@ -19,6 +19,14 @@ class Timelog < ApplicationRecord
joins
(
:project
).
where
(
projects:
{
namespace:
group
.
self_and_descendants
})
end
scope
:in_project
,
->
(
project
)
do
where
(
project:
project
)
end
scope
:for_user
,
->
(
user
)
do
where
(
user:
user
)
end
scope
:at_or_after
,
->
(
start_time
)
do
where
(
'spent_at >= ?'
,
start_time
)
end
...
...
app/models/user.rb
View file @
6b0f410e
...
...
@@ -211,6 +211,8 @@ class User < ApplicationRecord
has_many
:in_product_marketing_emails
,
class_name:
'::Users::InProductMarketingEmail'
has_many
:timelogs
#
# Validations
#
...
...
doc/api/graphql/reference/index.md
View file @
6b0f410e
This diff is collapsed.
Click to expand it.
doc/user/project/time_tracking.md
View file @
6b0f410e
...
...
@@ -130,4 +130,7 @@ With this option enabled, `75h` is displayed instead of `1w 4d 3h`.
-
[
Connection
](
../../api/graphql/reference/index.md#timelogconnection
)
-
[
Edge
](
../../api/graphql/reference/index.md#timelogedge
)
-
[
Fields
](
../../api/graphql/reference/index.md#timelog
)
-
[
Timelogs
](
../../api/graphql/reference/index.md#querytimelogs
)
-
[
Group timelogs
](
../../api/graphql/reference/index.md#grouptimelogs
)
-
[
Project Timelogs
](
../../api/graphql/reference/index.md#projecttimelogs
)
-
[
User Timelogs
](
../../api/graphql/reference/index.md#usertimelogs
)
ee/spec/graphql/ee/types/group_type_spec.rb
View file @
6b0f410e
...
...
@@ -13,7 +13,6 @@ RSpec.describe GitlabSchema.types['Group'] do
it
{
expect
(
described_class
).
to
have_graphql_field
(
:iterations
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:iteration_cadences
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:timelogs
,
complexity:
5
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:vulnerabilities
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:vulnerability_scanners
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:vulnerabilities_count_by_day
)
}
...
...
@@ -22,16 +21,6 @@ RSpec.describe GitlabSchema.types['Group'] do
it
{
expect
(
described_class
).
to
have_graphql_field
(
:stats
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:billable_members_count
)
}
describe
'timelogs field'
do
subject
{
described_class
.
fields
[
'timelogs'
]
}
it
'finds timelogs between start time and end time'
do
is_expected
.
to
have_graphql_arguments
(
:start_time
,
:end_time
,
:start_date
,
:end_date
,
:after
,
:before
,
:first
,
:last
)
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
TimelogResolver
)
is_expected
.
to
have_non_null_graphql_type
(
Types
::
TimelogType
.
connection_type
)
end
end
describe
'vulnerabilities'
do
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:project
)
{
create
(
:project
,
namespace:
group
)
}
...
...
spec/graphql/resolvers/concerns/resolves_ids_spec.rb
0 → 100644
View file @
6b0f410e
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
ResolvesIds
do
# gid://gitlab/Project/6
# gid://gitlab/Issue/6
# gid://gitlab/Project/6 gid://gitlab/Issue/6
context
'with a single project'
do
let
(
:ids
)
{
'gid://gitlab/Project/6'
}
let
(
:type
)
{
::
Types
::
GlobalIDType
[
::
Project
]
}
it
'returns the correct array'
do
expect
(
resolve_ids
).
to
match_array
([
'6'
])
end
end
context
'with a single issue'
do
let
(
:ids
)
{
'gid://gitlab/Issue/9'
}
let
(
:type
)
{
::
Types
::
GlobalIDType
[
::
Issue
]
}
it
'returns the correct array'
do
expect
(
resolve_ids
).
to
match_array
([
'9'
])
end
end
context
'with multiple users'
do
let
(
:ids
)
{
[
'gid://gitlab/User/7'
,
'gid://gitlab/User/13'
,
'gid://gitlab/User/21'
]
}
let
(
:type
)
{
::
Types
::
GlobalIDType
[
::
User
]
}
it
'returns the correct array'
do
expect
(
resolve_ids
).
to
match_array
(
%w[7 13 21]
)
end
end
def
mock_resolver
Class
.
new
(
GraphQL
::
Schema
::
Resolver
)
{
extend
ResolvesIds
}
end
def
resolve_ids
mock_resolver
.
resolve_ids
(
ids
,
type
)
end
end
spec/graphql/resolvers/timelog_resolver_spec.rb
View file @
6b0f410e
This diff is collapsed.
Click to expand it.
spec/graphql/types/group_type_spec.rb
View file @
6b0f410e
...
...
@@ -18,7 +18,7 @@ RSpec.describe GitlabSchema.types['Group'] do
two_factor_grace_period auto_devops_enabled emails_disabled
mentions_disabled parent boards milestones group_members
merge_requests container_repositories container_repositories_count
packages shared_runners_setting
packages shared_runners_setting
timelogs
]
expect
(
described_class
).
to
include_graphql_fields
(
*
expected_fields
)
...
...
@@ -39,6 +39,15 @@ RSpec.describe GitlabSchema.types['Group'] do
it
{
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
GroupMembersResolver
)
}
end
describe
'timelogs field'
do
subject
{
described_class
.
fields
[
'timelogs'
]
}
it
'finds timelogs between start time and end time'
do
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
TimelogResolver
)
is_expected
.
to
have_non_null_graphql_type
(
Types
::
TimelogType
.
connection_type
)
end
end
it_behaves_like
'a GraphQL type with labels'
do
let
(
:labels_resolver_arguments
)
{
[
:search_term
,
:includeAncestorGroups
,
:includeDescendantGroups
,
:onlyGroupLabels
]
}
end
...
...
spec/graphql/types/merge_requests/reviewer_type_spec.rb
View file @
6b0f410e
...
...
@@ -32,6 +32,7 @@ RSpec.describe GitlabSchema.types['MergeRequestReviewer'] do
callouts
merge_request_interaction
namespace
timelogs
]
expect
(
described_class
).
to
have_graphql_fields
(
*
expected_fields
)
...
...
spec/graphql/types/project_type_spec.rb
View file @
6b0f410e
...
...
@@ -33,7 +33,7 @@ RSpec.describe GitlabSchema.types['Project'] do
issue_status_counts terraform_states alert_management_integrations
container_repositories container_repositories_count
pipeline_analytics squash_read_only sast_ci_configuration
ci_template
ci_template
timelogs
]
expect
(
described_class
).
to
include_graphql_fields
(
*
expected_fields
)
...
...
@@ -392,6 +392,15 @@ RSpec.describe GitlabSchema.types['Project'] do
it
{
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
Terraform
::
StatesResolver
)
}
end
describe
'timelogs field'
do
subject
{
described_class
.
fields
[
'timelogs'
]
}
it
'finds timelogs for project'
do
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
TimelogResolver
)
is_expected
.
to
have_graphql_type
(
Types
::
TimelogType
.
connection_type
)
end
end
it_behaves_like
'a GraphQL type with labels'
do
let
(
:labels_resolver_arguments
)
{
[
:search_term
,
:includeAncestorGroups
]
}
end
...
...
spec/graphql/types/query_type_spec.rb
View file @
6b0f410e
...
...
@@ -26,6 +26,7 @@ RSpec.describe GitlabSchema.types['Query'] do
runner_platforms
runner
runners
timelogs
]
expect
(
described_class
).
to
have_graphql_fields
(
*
expected_fields
).
at_least
...
...
@@ -125,4 +126,14 @@ RSpec.describe GitlabSchema.types['Query'] do
it
{
is_expected
.
to
have_graphql_type
(
Types
::
Packages
::
PackageDetailsType
)
}
end
describe
'timelogs field'
do
subject
{
described_class
.
fields
[
'timelogs'
]
}
it
'returns timelogs'
do
is_expected
.
to
have_graphql_arguments
(
:startDate
,
:endDate
,
:startTime
,
:endTime
,
:username
,
:projectId
,
:groupId
,
:after
,
:before
,
:first
,
:last
)
is_expected
.
to
have_graphql_type
(
Types
::
TimelogType
.
connection_type
)
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
TimelogResolver
)
end
end
end
spec/graphql/types/user_type_spec.rb
View file @
6b0f410e
...
...
@@ -37,6 +37,7 @@ RSpec.describe GitlabSchema.types['User'] do
starredProjects
callouts
namespace
timelogs
]
expect
(
described_class
).
to
have_graphql_fields
(
*
expected_fields
)
...
...
@@ -58,4 +59,13 @@ RSpec.describe GitlabSchema.types['User'] do
is_expected
.
to
have_graphql_type
(
Types
::
UserCalloutType
.
connection_type
)
end
end
describe
'timelogs field'
do
subject
{
described_class
.
fields
[
'timelogs'
]
}
it
'returns user timelogs'
do
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
TimelogResolver
)
is_expected
.
to
have_graphql_type
(
Types
::
TimelogType
.
connection_type
)
end
end
end
spec/models/group_spec.rb
View file @
6b0f410e
...
...
@@ -2598,6 +2598,21 @@ RSpec.describe Group do
it
{
is_expected
.
to
eq
(
Set
.
new
([
child_1
.
id
]))
}
end
describe
'.timelogs'
do
let
(
:project
)
{
create
(
:project
,
namespace:
group
)
}
let
(
:issue
)
{
create
(
:issue
,
project:
project
)
}
let
(
:other_project
)
{
create
(
:project
,
namespace:
create
(
:group
))
}
let
(
:other_issue
)
{
create
(
:issue
,
project:
other_project
)
}
let!
(
:timelog1
)
{
create
(
:timelog
,
issue:
issue
)
}
let!
(
:timelog2
)
{
create
(
:timelog
,
issue:
other_issue
)
}
let!
(
:timelog3
)
{
create
(
:timelog
,
issue:
issue
)
}
it
'returns timelogs belonging to the group'
do
expect
(
group
.
timelogs
).
to
contain_exactly
(
timelog1
,
timelog3
)
end
end
describe
'#to_ability_name'
do
it
'returns group'
do
group
=
build
(
:group
)
...
...
spec/models/timelog_spec.rb
View file @
6b0f410e
...
...
@@ -70,8 +70,9 @@ RSpec.describe Timelog do
let_it_be
(
:medium_time_ago
)
{
15
.
days
.
ago
}
let_it_be
(
:long_time_ago
)
{
65
.
days
.
ago
}
let_it_be
(
:timelog
)
{
create
(
:issue_timelog
,
spent_at:
long_time_ago
)
}
let_it_be
(
:timelog1
)
{
create
(
:issue_timelog
,
spent_at:
medium_time_ago
,
issue:
group_issue
)
}
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:timelog
)
{
create
(
:issue_timelog
,
spent_at:
long_time_ago
,
user:
user
)
}
let_it_be
(
:timelog1
)
{
create
(
:issue_timelog
,
spent_at:
medium_time_ago
,
issue:
group_issue
,
user:
user
)
}
let_it_be
(
:timelog2
)
{
create
(
:issue_timelog
,
spent_at:
short_time_ago
,
issue:
subgroup_issue
)
}
let_it_be
(
:timelog3
)
{
create
(
:merge_request_timelog
,
spent_at:
long_time_ago
)
}
let_it_be
(
:timelog4
)
{
create
(
:merge_request_timelog
,
spent_at:
medium_time_ago
,
merge_request:
group_merge_request
)
}
...
...
@@ -83,6 +84,25 @@ RSpec.describe Timelog do
end
end
describe
'.for_user'
do
it
'return timelogs created by user'
do
expect
(
described_class
.
for_user
(
user
)).
to
contain_exactly
(
timelog
,
timelog1
)
end
end
describe
'.in_project'
do
it
'returns timelogs created for project issues and merge requests'
do
project
=
create
(
:project
,
:empty_repo
)
create
(
:issue_timelog
)
create
(
:merge_request_timelog
)
timelog1
=
create
(
:issue_timelog
,
issue:
create
(
:issue
,
project:
project
))
timelog2
=
create
(
:merge_request_timelog
,
merge_request:
create
(
:merge_request
,
source_project:
project
))
expect
(
described_class
.
in_project
(
project
.
id
)).
to
contain_exactly
(
timelog1
,
timelog2
)
end
end
describe
'.at_or_after'
do
it
'returns timelogs at the time limit'
do
timelogs
=
described_class
.
at_or_after
(
short_time_ago
)
...
...
spec/models/user_spec.rb
View file @
6b0f410e
...
...
@@ -124,6 +124,7 @@ RSpec.describe User do
it
{
is_expected
.
to
have_many
(
:merge_request_reviewers
).
inverse_of
(
:reviewer
)
}
it
{
is_expected
.
to
have_many
(
:created_custom_emoji
).
inverse_of
(
:creator
)
}
it
{
is_expected
.
to
have_many
(
:in_product_marketing_emails
)
}
it
{
is_expected
.
to
have_many
(
:timelogs
)
}
describe
"#user_detail"
do
it
'does not persist `user_detail` by default'
do
...
...
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