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
fb085280
Commit
fb085280
authored
Dec 06, 2019
by
Sean Arnold
Committed by
Jan Provaznik
Dec 06, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add graphql for Sentry error details
- Squashed commit containing GraphQL changes
parent
425c041e
Changes
18
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
1077 additions
and
6 deletions
+1077
-6
app/graphql/resolvers/error_tracking/sentry_detailed_error_resolver.rb
...esolvers/error_tracking/sentry_detailed_error_resolver.rb
+28
-0
app/graphql/types/error_tracking/sentry_detailed_error_type.rb
...raphql/types/error_tracking/sentry_detailed_error_type.rb
+93
-0
app/graphql/types/error_tracking/sentry_error_frequency_type.rb
...aphql/types/error_tracking/sentry_error_frequency_type.rb
+18
-0
app/graphql/types/error_tracking/sentry_error_status_enum.rb
app/graphql/types/error_tracking/sentry_error_status_enum.rb
+15
-0
app/graphql/types/project_type.rb
app/graphql/types/project_type.rb
+6
-0
app/policies/error_tracking/detailed_error_policy.rb
app/policies/error_tracking/detailed_error_policy.rb
+7
-0
app/presenters/sentry_detailed_error_presenter.rb
app/presenters/sentry_detailed_error_presenter.rb
+15
-0
changelogs/unreleased/34943-graphql-sentry-details.yml
changelogs/unreleased/34943-graphql-sentry-details.yml
+5
-0
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+154
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+490
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+34
-0
lib/gitlab/error_tracking/detailed_error.rb
lib/gitlab/error_tracking/detailed_error.rb
+6
-0
spec/factories/error_tracking/detailed_error.rb
spec/factories/error_tracking/detailed_error.rb
+8
-4
spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb
...ers/error_tracking/sentry_detailed_error_resolver_spec.rb
+62
-0
spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb
...l/types/error_tracking/sentry_detailed_error_type_spec.rb
+37
-0
spec/graphql/types/project_type_spec.rb
spec/graphql/types/project_type_spec.rb
+1
-2
spec/presenters/sentry_detailed_error_presenter_spec.rb
spec/presenters/sentry_detailed_error_presenter_spec.rb
+29
-0
spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
...ject/error_tracking/sentry_detailed_error_request_spec.rb
+69
-0
No files found.
app/graphql/resolvers/error_tracking/sentry_detailed_error_resolver.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
module
Resolvers
module
ErrorTracking
class
SentryDetailedErrorResolver
<
BaseResolver
argument
:id
,
GraphQL
::
ID_TYPE
,
required:
true
,
description:
'ID of the Sentry issue'
def
resolve
(
**
args
)
project
=
object
current_user
=
context
[
:current_user
]
issue_id
=
GlobalID
.
parse
(
args
[
:id
]).
model_id
# Get data from Sentry
response
=
::
ErrorTracking
::
IssueDetailsService
.
new
(
project
,
current_user
,
{
issue_id:
issue_id
}
).
execute
issue
=
response
[
:issue
]
issue
.
gitlab_project
=
project
if
issue
issue
end
end
end
end
app/graphql/types/error_tracking/sentry_detailed_error_type.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
module
Types
module
ErrorTracking
class
SentryDetailedErrorType
<
::
Types
::
BaseObject
graphql_name
'SentryDetailedError'
present_using
SentryDetailedErrorPresenter
authorize
:read_sentry_issue
field
:id
,
GraphQL
::
ID_TYPE
,
null:
false
,
description:
"ID (global ID) of the error"
field
:sentry_id
,
GraphQL
::
STRING_TYPE
,
method: :id
,
null:
false
,
description:
"ID (Sentry ID) of the error"
field
:title
,
GraphQL
::
STRING_TYPE
,
null:
false
,
description:
"Title of the error"
field
:type
,
GraphQL
::
STRING_TYPE
,
null:
false
,
description:
"Type of the error"
field
:user_count
,
GraphQL
::
INT_TYPE
,
null:
false
,
description:
"Count of users affected by the error"
field
:count
,
GraphQL
::
INT_TYPE
,
null:
false
,
description:
"Count of occurrences"
field
:first_seen
,
Types
::
TimeType
,
null:
false
,
description:
"Timestamp when the error was first seen"
field
:last_seen
,
Types
::
TimeType
,
null:
false
,
description:
"Timestamp when the error was last seen"
field
:message
,
GraphQL
::
STRING_TYPE
,
null:
true
,
description:
"Sentry metadata message of the error"
field
:culprit
,
GraphQL
::
STRING_TYPE
,
null:
false
,
description:
"Culprit of the error"
field
:external_url
,
GraphQL
::
STRING_TYPE
,
null:
false
,
description:
"External URL of the error"
field
:sentry_project_id
,
GraphQL
::
ID_TYPE
,
method: :project_id
,
null:
false
,
description:
"ID of the project (Sentry project)"
field
:sentry_project_name
,
GraphQL
::
STRING_TYPE
,
method: :project_name
,
null:
false
,
description:
"Name of the project affected by the error"
field
:sentry_project_slug
,
GraphQL
::
STRING_TYPE
,
method: :project_slug
,
null:
false
,
description:
"Slug of the project affected by the error"
field
:short_id
,
GraphQL
::
STRING_TYPE
,
null:
false
,
description:
"Short ID (Sentry ID) of the error"
field
:status
,
Types
::
ErrorTracking
::
SentryErrorStatusEnum
,
null:
false
,
description:
"Status of the error"
field
:frequency
,
[
Types
::
ErrorTracking
::
SentryErrorFrequencyType
],
null:
false
,
description:
"Last 24hr stats of the error"
field
:first_release_last_commit
,
GraphQL
::
STRING_TYPE
,
null:
true
,
description:
"Commit the error was first seen"
field
:last_release_last_commit
,
GraphQL
::
STRING_TYPE
,
null:
true
,
description:
"Commit the error was last seen"
field
:first_release_short_version
,
GraphQL
::
STRING_TYPE
,
null:
true
,
description:
"Release version the error was first seen"
field
:last_release_short_version
,
GraphQL
::
STRING_TYPE
,
null:
true
,
description:
"Release version the error was last seen"
def
first_seen
DateTime
.
parse
(
object
.
first_seen
)
end
def
last_seen
DateTime
.
parse
(
object
.
last_seen
)
end
def
project_id
Gitlab
::
GlobalId
.
build
(
model_name:
'Project'
,
id:
object
.
project_id
).
to_s
end
end
end
end
app/graphql/types/error_tracking/sentry_error_frequency_type.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
module
Types
module
ErrorTracking
# rubocop: disable Graphql/AuthorizeTypes
class
SentryErrorFrequencyType
<
::
Types
::
BaseObject
graphql_name
'SentryErrorFrequency'
field
:time
,
Types
::
TimeType
,
null:
false
,
description:
"Time the error frequency stats were recorded"
field
:count
,
GraphQL
::
INT_TYPE
,
null:
false
,
description:
"Count of errors received since the previously recorded time"
end
# rubocop: enable Graphql/AuthorizeTypes
end
end
app/graphql/types/error_tracking/sentry_error_status_enum.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
module
Types
module
ErrorTracking
class
SentryErrorStatusEnum
<
::
Types
::
BaseEnum
graphql_name
'SentryErrorStatus'
description
'State of a Sentry error'
value
'RESOLVED'
,
value:
'resolved'
,
description:
'Error has been resolved'
value
'RESOLVED_IN_NEXT_RELEASE'
,
value:
'resolvedInNextRelease'
,
description:
'Error has been ignored until next release'
value
'UNRESOLVED'
,
value:
'unresolved'
,
description:
'Error is unresolved'
value
'IGNORED'
,
value:
'ignored'
,
description:
'Error has been ignored'
end
end
end
app/graphql/types/project_type.rb
View file @
fb085280
...
...
@@ -145,5 +145,11 @@ module Types
null:
true
,
description:
'Build pipelines of the project'
,
resolver:
Resolvers
::
ProjectPipelinesResolver
field
:sentry_detailed_error
,
Types
::
ErrorTracking
::
SentryDetailedErrorType
,
null:
true
,
description:
'Detailed version of a Sentry error on the project'
,
resolver:
Resolvers
::
ErrorTracking
::
SentryDetailedErrorResolver
end
end
app/policies/error_tracking/detailed_error_policy.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
module
ErrorTracking
class
DetailedErrorPolicy
<
BasePolicy
delegate
{
@subject
.
gitlab_project
}
end
end
app/presenters/sentry_detailed_error_presenter.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
class
SentryDetailedErrorPresenter
<
Gitlab
::
View
::
Presenter
::
Delegated
presents
:error
FrequencyStruct
=
Struct
.
new
(
:time
,
:count
,
keyword_init:
true
)
def
frequency
utc_offset
=
Time
.
zone_offset
(
'UTC'
)
error
.
frequency
.
map
do
|
f
|
FrequencyStruct
.
new
(
time:
Time
.
at
(
f
[
0
],
in:
utc_offset
),
count:
f
[
1
])
end
end
end
changelogs/unreleased/34943-graphql-sentry-details.yml
0 → 100644
View file @
fb085280
---
title
:
GraphQL for Sentry rror details
merge_request
:
19733
author
:
type
:
added
doc/api/graphql/reference/gitlab_schema.graphql
View file @
fb085280
...
...
@@ -4400,6 +4400,16 @@ type Project {
"""
requestAccessEnabled
:
Boolean
"""
Detailed
version
of
a
Sentry
error
on
the
project
"""
sentryDetailedError
(
"""
ID
of
the
Sentry
issue
"""
id
:
ID
!
):
SentryDetailedError
"""
Indicates
if
shared
runners
are
enabled
on
the
project
"""
...
...
@@ -4886,6 +4896,150 @@ type RootStorageStatistics {
wikiSize
:
Int
!
}
type
SentryDetailedError
{
"""
Count
of
occurrences
"""
count
:
Int
!
"""
Culprit
of
the
error
"""
culprit
:
String
!
"""
External
URL
of
the
error
"""
externalUrl
:
String
!
"""
Commit
the
error
was
first
seen
"""
firstReleaseLastCommit
:
String
"""
Release
version
the
error
was
first
seen
"""
firstReleaseShortVersion
:
String
"""
Timestamp
when
the
error
was
first
seen
"""
firstSeen
:
Time
!
"""
Last
24
hr
stats
of
the
error
"""
frequency
:
[
SentryErrorFrequency
!]!
"""
ID
(
global
ID
)
of
the
error
"""
id
:
ID
!
"""
Commit
the
error
was
last
seen
"""
lastReleaseLastCommit
:
String
"""
Release
version
the
error
was
last
seen
"""
lastReleaseShortVersion
:
String
"""
Timestamp
when
the
error
was
last
seen
"""
lastSeen
:
Time
!
"""
Sentry
metadata
message
of
the
error
"""
message
:
String
"""
ID
(
Sentry
ID
)
of
the
error
"""
sentryId
:
String
!
"""
ID
of
the
project
(
Sentry
project
)
"""
sentryProjectId
:
ID
!
"""
Name
of
the
project
affected
by
the
error
"""
sentryProjectName
:
String
!
"""
Slug
of
the
project
affected
by
the
error
"""
sentryProjectSlug
:
String
!
"""
Short
ID
(
Sentry
ID
)
of
the
error
"""
shortId
:
String
!
"""
Status
of
the
error
"""
status
:
SentryErrorStatus
!
"""
Title
of
the
error
"""
title
:
String
!
"""
Type
of
the
error
"""
type
:
String
!
"""
Count
of
users
affected
by
the
error
"""
userCount
:
Int
!
}
type
SentryErrorFrequency
{
"""
Count
of
errors
received
since
the
previously
recorded
time
"""
count
:
Int
!
"""
Time
the
error
frequency
stats
were
recorded
"""
time
:
Time
!
}
"""
State of a Sentry error
"""
enum
SentryErrorStatus
{
"""
Error
has
been
ignored
"""
IGNORED
"""
Error
has
been
resolved
"""
RESOLVED
"""
Error
has
been
ignored
until
next
release
"""
RESOLVED_IN_NEXT_RELEASE
"""
Error
is
unresolved
"""
UNRESOLVED
}
type
Submodule
implements
Entry
{
flatPath
:
String
!
id
:
ID
!
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
fb085280
...
...
@@ -1166,6 +1166,33 @@
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"sentryDetailedError"
,
"description"
:
"Detailed version of a Sentry error on the project"
,
"args"
:
[
{
"name"
:
"id"
,
"description"
:
"ID of the Sentry issue"
,
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
}
},
"defaultValue"
:
null
}
],
"type"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"SentryDetailedError"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"sharedRunnersEnabled"
,
"description"
:
"Indicates if shared runners are enabled on the project"
,
...
...
@@ -13788,6 +13815,469 @@
],
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"SentryDetailedError"
,
"description"
:
null
,
"fields"
:
[
{
"name"
:
"count"
,
"description"
:
"Count of occurrences"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Int"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"culprit"
,
"description"
:
"Culprit of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"externalUrl"
,
"description"
:
"External URL of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"firstReleaseLastCommit"
,
"description"
:
"Commit the error was first seen"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"firstReleaseShortVersion"
,
"description"
:
"Release version the error was first seen"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"firstSeen"
,
"description"
:
"Timestamp when the error was first seen"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Time"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"frequency"
,
"description"
:
"Last 24hr stats of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"LIST"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"OBJECT"
,
"name"
:
"SentryErrorFrequency"
,
"ofType"
:
null
}
}
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"id"
,
"description"
:
"ID (global ID) of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"lastReleaseLastCommit"
,
"description"
:
"Commit the error was last seen"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"lastReleaseShortVersion"
,
"description"
:
"Release version the error was last seen"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"lastSeen"
,
"description"
:
"Timestamp when the error was last seen"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Time"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"message"
,
"description"
:
"Sentry metadata message of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"sentryId"
,
"description"
:
"ID (Sentry ID) of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"sentryProjectId"
,
"description"
:
"ID of the project (Sentry project)"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"ID"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"sentryProjectName"
,
"description"
:
"Name of the project affected by the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"sentryProjectSlug"
,
"description"
:
"Slug of the project affected by the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"shortId"
,
"description"
:
"Short ID (Sentry ID) of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"status"
,
"description"
:
"Status of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"ENUM"
,
"name"
:
"SentryErrorStatus"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"title"
,
"description"
:
"Title of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"type"
,
"description"
:
"Type of the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"String"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"userCount"
,
"description"
:
"Count of users affected by the error"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Int"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"ENUM"
,
"name"
:
"SentryErrorStatus"
,
"description"
:
"State of a Sentry error"
,
"fields"
:
null
,
"inputFields"
:
null
,
"interfaces"
:
null
,
"enumValues"
:
[
{
"name"
:
"RESOLVED"
,
"description"
:
"Error has been resolved"
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"RESOLVED_IN_NEXT_RELEASE"
,
"description"
:
"Error has been ignored until next release"
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"UNRESOLVED"
,
"description"
:
"Error is unresolved"
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"IGNORED"
,
"description"
:
"Error has been ignored"
,
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"SentryErrorFrequency"
,
"description"
:
null
,
"fields"
:
[
{
"name"
:
"count"
,
"description"
:
"Count of errors received since the previously recorded time"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Int"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
},
{
"name"
:
"time"
,
"description"
:
"Time the error frequency stats were recorded"
,
"args"
:
[
],
"type"
:
{
"kind"
:
"NON_NULL"
,
"name"
:
null
,
"ofType"
:
{
"kind"
:
"SCALAR"
,
"name"
:
"Time"
,
"ofType"
:
null
}
},
"isDeprecated"
:
false
,
"deprecationReason"
:
null
}
],
"inputFields"
:
null
,
"interfaces"
:
[
],
"enumValues"
:
null
,
"possibleTypes"
:
null
},
{
"kind"
:
"OBJECT"
,
"name"
:
"Metadata"
,
...
...
doc/api/graphql/reference/index.md
View file @
fb085280
...
...
@@ -664,6 +664,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
|
`repository`
| Repository | Git repository of the project |
|
`mergeRequest`
| MergeRequest | A single merge request of the project |
|
`issue`
| Issue | A single issue of the project |
|
`sentryDetailedError`
| SentryDetailedError | Detailed version of a Sentry error on the project |
### ProjectPermissions
...
...
@@ -751,6 +752,39 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
|
`packagesSize`
| Int! | The packages size in bytes |
|
`wikiSize`
| Int! | The wiki size in bytes |
### SentryDetailedError
| Name | Type | Description |
| --- | ---- | ---------- |
|
`id`
| ID! | ID (global ID) of the error |
|
`sentryId`
| String! | ID (Sentry ID) of the error |
|
`title`
| String! | Title of the error |
|
`type`
| String! | Type of the error |
|
`userCount`
| Int! | Count of users affected by the error |
|
`count`
| Int! | Count of occurrences |
|
`firstSeen`
| Time! | Timestamp when the error was first seen |
|
`lastSeen`
| Time! | Timestamp when the error was last seen |
|
`message`
| String | Sentry metadata message of the error |
|
`culprit`
| String! | Culprit of the error |
|
`externalUrl`
| String! | External URL of the error |
|
`sentryProjectId`
| ID! | ID of the project (Sentry project) |
|
`sentryProjectName`
| String! | Name of the project affected by the error |
|
`sentryProjectSlug`
| String! | Slug of the project affected by the error |
|
`shortId`
| String! | Short ID (Sentry ID) of the error |
|
`status`
| SentryErrorStatus! | Status of the error |
|
`frequency`
| SentryErrorFrequency! => Array | Last 24hr stats of the error |
|
`firstReleaseLastCommit`
| String | Commit the error was first seen |
|
`lastReleaseLastCommit`
| String | Commit the error was last seen |
|
`firstReleaseShortVersion`
| String | Release version the error was first seen |
|
`lastReleaseShortVersion`
| String | Release version the error was last seen |
### SentryErrorFrequency
| Name | Type | Description |
| --- | ---- | ---------- |
|
`time`
| Time! | Time the error frequency stats were recorded |
|
`count`
| Int! | Count of errors received since the previously recorded time |
### Submodule
| Name | Type | Description |
...
...
lib/gitlab/error_tracking/detailed_error.rb
View file @
fb085280
...
...
@@ -4,6 +4,7 @@ module Gitlab
module
ErrorTracking
class
DetailedError
include
ActiveModel
::
Model
include
GlobalID
::
Identification
attr_accessor
:count
,
:culprit
,
...
...
@@ -13,6 +14,7 @@ module Gitlab
:first_release_short_version
,
:first_seen
,
:frequency
,
:gitlab_project
,
:id
,
:last_release_last_commit
,
:last_release_short_version
,
...
...
@@ -26,6 +28,10 @@ module Gitlab
:title
,
:type
,
:user_count
def
self
.
declarative_policy_class
'ErrorTracking::DetailedErrorPolicy'
end
end
end
end
spec/factories/error_tracking/detailed_error.rb
View file @
fb085280
...
...
@@ -2,13 +2,13 @@
FactoryBot
.
define
do
factory
:detailed_error_tracking_error
,
class:
Gitlab
::
ErrorTracking
::
DetailedError
do
id
{
'
id
'
}
id
{
'
1
'
}
title
{
'title'
}
type
{
'error'
}
user_count
{
1
}
count
{
2
}
first_seen
{
Time
.
now
}
last_seen
{
Time
.
now
}
first_seen
{
Time
.
now
.
iso8601
}
last_seen
{
Time
.
now
.
iso8601
}
message
{
'message'
}
culprit
{
'culprit'
}
external_url
{
'http://example.com/id'
}
...
...
@@ -18,7 +18,11 @@ FactoryBot.define do
project_slug
{
'project_name'
}
short_id
{
'ID'
}
status
{
'unresolved'
}
frequency
{
[]
}
frequency
do
[
[
Time
.
now
.
to_i
,
10
]
]
end
first_release_last_commit
{
'68c914da9'
}
last_release_last_commit
{
'9ad419c86'
}
first_release_short_version
{
'abc123'
}
...
...
spec/graphql/resolvers/error_tracking/sentry_detailed_error_resolver_spec.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
require
'spec_helper'
describe
Resolvers
::
ErrorTracking
::
SentryDetailedErrorResolver
do
include
GraphqlHelpers
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:current_user
)
{
create
(
:user
)
}
let
(
:issue_details_service
)
{
spy
(
'ErrorTracking::IssueDetailsService'
)
}
before
do
project
.
add_developer
(
current_user
)
allow
(
ErrorTracking
::
IssueDetailsService
)
.
to
receive
(
:new
)
.
and_return
issue_details_service
end
describe
'#resolve'
do
let
(
:args
)
{
{
id:
issue_global_id
(
1234
)
}
}
it
'fetches the data via the sentry API'
do
resolve_error
(
args
)
expect
(
issue_details_service
).
to
have_received
(
:execute
)
end
context
'error matched'
do
let
(
:detailed_error
)
{
build
(
:detailed_error_tracking_error
)
}
before
do
allow
(
issue_details_service
).
to
receive
(
:execute
)
.
and_return
({
issue:
detailed_error
})
end
it
'resolves to a detailed error'
do
expect
(
resolve_error
(
args
)).
to
eq
detailed_error
end
it
'assigns the gitlab project'
do
expect
(
resolve_error
(
args
).
gitlab_project
).
to
eq
project
end
end
it
'resolves to nil if no match'
do
allow
(
issue_details_service
).
to
receive
(
:execute
)
.
and_return
({
issue:
nil
})
result
=
resolve_error
(
args
)
expect
(
result
).
to
eq
nil
end
end
def
resolve_error
(
args
=
{},
context
=
{
current_user:
current_user
})
resolve
(
described_class
,
obj:
project
,
args:
args
,
ctx:
context
)
end
def
issue_global_id
(
issue_id
)
Gitlab
::
ErrorTracking
::
DetailedError
.
new
(
id:
issue_id
).
to_global_id
.
to_s
end
end
spec/graphql/types/error_tracking/sentry_detailed_error_type_spec.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
require
'spec_helper'
describe
GitlabSchema
.
types
[
'SentryDetailedError'
]
do
it
{
expect
(
described_class
.
graphql_name
).
to
eq
(
'SentryDetailedError'
)
}
it
{
expect
(
described_class
).
to
require_graphql_authorizations
(
:read_sentry_issue
)
}
it
'exposes the expected fields'
do
expected_fields
=
%i[
id
sentryId
title
type
userCount
count
firstSeen
lastSeen
message
culprit
externalUrl
sentryProjectId
sentryProjectName
sentryProjectSlug
shortId
status
frequency
firstReleaseLastCommit
lastReleaseLastCommit
firstReleaseShortVersion
lastReleaseShortVersion
]
is_expected
.
to
have_graphql_fields
(
*
expected_fields
)
end
end
spec/graphql/types/project_type_spec.rb
View file @
fb085280
...
...
@@ -22,8 +22,7 @@ describe GitlabSchema.types['Project'] do
only_allow_merge_if_pipeline_succeeds request_access_enabled
only_allow_merge_if_all_discussions_are_resolved printing_merge_request_link_enabled
namespace group statistics repository merge_requests merge_request issues
issue pipelines
removeSourceBranchAfterMerge
issue pipelines removeSourceBranchAfterMerge sentryDetailedError
]
is_expected
.
to
have_graphql_fields
(
*
expected_fields
)
...
...
spec/presenters/sentry_detailed_error_presenter_spec.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
require
'spec_helper'
describe
SentryDetailedErrorPresenter
do
let
(
:error
)
{
build
(
:detailed_error_tracking_error
)
}
let
(
:presenter
)
{
described_class
.
new
(
error
)
}
describe
'#frequency'
do
subject
{
presenter
.
frequency
}
it
'returns an array of frequency structs'
do
expect
(
subject
).
to
include
(
a_kind_of
(
SentryDetailedErrorPresenter
::
FrequencyStruct
))
end
it
'converts the times into UTC time objects'
do
time
=
subject
.
first
.
time
expect
(
time
).
to
be_a
(
Time
)
expect
(
time
.
strftime
(
'%z'
)).
to
eq
'+0000'
end
it
'returns the correct counts'
do
count
=
subject
.
first
.
count
expect
(
count
).
to
eq
error
.
frequency
.
first
[
1
]
end
end
end
spec/requests/api/graphql/project/error_tracking/sentry_detailed_error_request_spec.rb
0 → 100644
View file @
fb085280
# frozen_string_literal: true
require
'spec_helper'
describe
'getting a detailed sentry error'
do
include
GraphqlHelpers
let_it_be
(
:project
)
{
create
(
:project
,
:repository
)
}
let_it_be
(
:project_setting
)
{
create
(
:project_error_tracking_setting
,
project:
project
)
}
let_it_be
(
:current_user
)
{
project
.
owner
}
let_it_be
(
:sentry_detailed_error
)
{
build
(
:detailed_error_tracking_error
)
}
let
(
:sentry_gid
)
{
sentry_detailed_error
.
to_global_id
.
to_s
}
let
(
:fields
)
do
<<~
QUERY
#{
all_graphql_fields_for
(
'SentryDetailedError'
.
classify
)
}
QUERY
end
let
(
:query
)
do
graphql_query_for
(
'project'
,
{
'fullPath'
=>
project
.
full_path
},
query_graphql_field
(
'sentryDetailedError'
,
{
id:
sentry_gid
},
fields
)
)
end
let
(
:error_data
)
{
graphql_data
[
'project'
][
'sentryDetailedError'
]
}
it_behaves_like
'a working graphql query'
do
before
do
post_graphql
(
query
,
current_user:
current_user
)
end
end
context
'when data is loading via reactive cache'
do
before
do
post_graphql
(
query
,
current_user:
current_user
)
end
it
"is expected to return an empty error"
do
expect
(
error_data
).
to
eq
nil
end
end
context
'reactive cache returns data'
do
before
do
expect_any_instance_of
(
ErrorTracking
::
ProjectErrorTrackingSetting
)
.
to
receive
(
:issue_details
)
.
and_return
({
issue:
sentry_detailed_error
})
post_graphql
(
query
,
current_user:
current_user
)
end
it
"is expected to return a valid error"
do
expect
(
error_data
[
'id'
]).
to
eql
sentry_gid
expect
(
error_data
[
'sentryId'
]).
to
eql
sentry_detailed_error
.
id
.
to_s
expect
(
error_data
[
'status'
]).
to
eql
sentry_detailed_error
.
status
.
upcase
expect
(
error_data
[
'firstSeen'
]).
to
eql
sentry_detailed_error
.
first_seen
expect
(
error_data
[
'lastSeen'
]).
to
eql
sentry_detailed_error
.
last_seen
end
it
'is expected to return the frequency correctly'
do
expect
(
error_data
[
'frequency'
].
count
).
to
eql
sentry_detailed_error
.
frequency
.
count
first_frequency
=
error_data
[
'frequency'
].
first
expect
(
Time
.
parse
(
first_frequency
[
'time'
])).
to
eql
Time
.
at
(
sentry_detailed_error
.
frequency
[
0
][
0
],
in:
0
)
expect
(
first_frequency
[
'count'
]).
to
eql
sentry_detailed_error
.
frequency
[
0
][
1
]
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