Skip to content
Snippets Groups Projects
Commit d203316c authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 8dafc3b6
No related branches found
No related tags found
No related merge requests found
Showing
with 414 additions and 39 deletions
# frozen_string_literal: true
module Resolvers
module Projects
class GrafanaIntegrationResolver < BaseResolver
type Types::GrafanaIntegrationType, null: true
alias_method :project, :object
def resolve(**args)
return unless project.is_a? Project
project.grafana_integration
end
end
end
end
# frozen_string_literal: true
module Types
class GrafanaIntegrationType < ::Types::BaseObject
graphql_name 'GrafanaIntegration'
authorize :admin_operations
field :id, GraphQL::ID_TYPE, null: false,
description: 'Internal ID of the Grafana integration'
field :grafana_url, GraphQL::STRING_TYPE, null: false,
description: 'Url for the Grafana host for the Grafana integration'
field :token, GraphQL::STRING_TYPE, null: false,
description: 'API token for the Grafana integration'
field :enabled, GraphQL::BOOLEAN_TYPE, null: false,
description: 'Indicates whether Grafana integration is enabled'
field :created_at, Types::TimeType, null: false,
description: 'Timestamp of the issue\'s creation'
field :updated_at, Types::TimeType, null: false,
description: 'Timestamp of the issue\'s last activity'
end
end
Loading
Loading
@@ -152,6 +152,12 @@ module Types
description: 'Detailed version of a Sentry error on the project',
resolver: Resolvers::ErrorTracking::SentryDetailedErrorResolver
 
field :grafana_integration,
Types::GrafanaIntegrationType,
null: true,
description: 'Grafana integration details for the project',
resolver: Resolvers::Projects::GrafanaIntegrationResolver
field :snippets,
Types::SnippetType.connection_type,
null: true,
Loading
Loading
# frozen_string_literal: true
class GrafanaIntegrationPolicy < BasePolicy
delegate { @subject.project }
end
---
title: Add API for rollout Elasticsearch per plan level
merge_request: 22240
author:
type: added
---
title: Add fetching of Grafana Auth via the GraphQL API
merge_request: 21756
author:
type: changed
Loading
Loading
@@ -117,6 +117,7 @@
- [elastic_full_index, 1]
- [elastic_commit_indexer, 1]
- [elastic_namespace_indexer, 1]
- [elastic_namespace_rollout, 1]
- [export_csv, 1]
- [incident_management, 2]
- [jira_connect, 1]
Loading
Loading
# frozen_string_literal: true
class AddIndexToElasticsearchIndexedNamespaces < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index(:elasticsearch_indexed_namespaces, :created_at)
end
def down
remove_concurrent_index(:elasticsearch_indexed_namespaces, :created_at)
end
end
Loading
Loading
@@ -1460,6 +1460,7 @@ ActiveRecord::Schema.define(version: 2020_01_06_085831) do
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.integer "namespace_id"
t.index ["created_at"], name: "index_elasticsearch_indexed_namespaces_on_created_at"
t.index ["namespace_id"], name: "index_elasticsearch_indexed_namespaces_on_namespace_id", unique: true
end
 
Loading
Loading
Loading
Loading
@@ -2275,6 +2275,38 @@ type EpicTreeReorderPayload {
errors: [String!]!
}
 
type GrafanaIntegration {
"""
Timestamp of the issue's creation
"""
createdAt: Time!
"""
Indicates whether Grafana integration is enabled
"""
enabled: Boolean!
"""
Url for the Grafana host for the Grafana integration
"""
grafanaUrl: String!
"""
Internal ID of the Grafana integration
"""
id: ID!
"""
API token for the Grafana integration
"""
token: String!
"""
Timestamp of the issue's last activity
"""
updatedAt: Time!
}
type Group {
"""
Avatar URL of the group
Loading
Loading
@@ -4612,6 +4644,11 @@ type Project {
"""
fullPath: ID!
 
"""
Grafana integration details for the project
"""
grafanaIntegration: GrafanaIntegration
"""
Group of the project
"""
Loading
Loading
Loading
Loading
@@ -428,6 +428,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "grafanaIntegration",
"description": "Grafana integration details for the project",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "GrafanaIntegration",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "group",
"description": "Group of the project",
Loading
Loading
@@ -15668,6 +15682,127 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "GrafanaIntegration",
"description": null,
"fields": [
{
"name": "createdAt",
"description": "Timestamp of the issue's creation",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "enabled",
"description": "Indicates whether Grafana integration is enabled",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "grafanaUrl",
"description": "Url for the Grafana host for the Grafana integration",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
"description": "Internal ID of the Grafana integration",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "token",
"description": "API token for the Grafana integration",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updatedAt",
"description": "Timestamp of the issue's last activity",
"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",
Loading
Loading
Loading
Loading
@@ -317,6 +317,17 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
 
### GrafanaIntegration
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | Internal ID of the Grafana integration |
| `grafanaUrl` | String! | Url for the Grafana host for the Grafana integration |
| `token` | String! | API token for the Grafana integration |
| `enabled` | Boolean! | Indicates whether Grafana integration is enabled |
| `createdAt` | Time! | Timestamp of the issue's creation |
| `updatedAt` | Time! | Timestamp of the issue's last activity |
### Group
 
| Name | Type | Description |
Loading
Loading
@@ -700,6 +711,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `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 |
| `grafanaIntegration` | GrafanaIntegration | Grafana integration details for the project |
| `serviceDeskEnabled` | Boolean | Indicates if the project has service desk enabled. |
| `serviceDeskAddress` | String | E-mail address of the service desk. |
 
Loading
Loading
Loading
Loading
@@ -12,6 +12,10 @@ module Gitlab
Gitlab::Graphql::FilterableArray,
Gitlab::Graphql::Connections::FilterableArrayConnection
)
GraphQL::Relay::BaseConnection.register_connection_implementation(
Gitlab::Graphql::ExternallyPaginatedArray,
Gitlab::Graphql::Connections::ExternallyPaginatedArrayConnection
)
end
end
end
Loading
Loading
# frozen_string_literal: true
# Make a customized connection type
module Gitlab
module Graphql
module Connections
class ExternallyPaginatedArrayConnection < GraphQL::Relay::ArrayConnection
# As the pagination happens externally
# we just return all the nodes here.
def sliced_nodes
@nodes
end
def start_cursor
nodes.previous_cursor
end
def end_cursor
nodes.next_cursor
end
def next_page?
end_cursor.present?
end
def previous_page?
start_cursor.present?
end
alias_method :has_next_page, :next_page?
alias_method :has_previous_page, :previous_page?
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Graphql
class ExternallyPaginatedArray < Array
attr_reader :previous_cursor, :next_cursor
def initialize(previous_cursor, next_cursor, *args)
super(args)
@previous_cursor = previous_cursor
@next_cursor = next_cursor
end
end
end
end
Loading
Loading
@@ -2,6 +2,7 @@
 
module Sentry
class Client
include Sentry::Client::Event
include Sentry::Client::Projects
include Sentry::Client::Issue
 
Loading
Loading
@@ -24,12 +25,6 @@ module Sentry
@token = token
end
 
def issue_latest_event(issue_id:)
latest_event = get_issue_latest_event(issue_id: issue_id)
map_to_event(latest_event)
end
def list_issues(**keyword_args)
response = get_issues(keyword_args)
 
Loading
Loading
@@ -115,10 +110,6 @@ module Sentry
}.compact
end
 
def get_issue_latest_event(issue_id:)
http_get(issue_latest_event_api_url(issue_id))[:body]
end
def handle_request_exceptions
yield
rescue Gitlab::HTTP::Error => e
Loading
Loading
@@ -149,13 +140,6 @@ module Sentry
raise Client::Error, message
end
 
def issue_latest_event_api_url(issue_id)
latest_event_url = URI(@url)
latest_event_url.path = "/api/0/issues/#{issue_id}/events/latest/"
latest_event_url
end
def issues_api_url
issues_url = URI(@url + '/issues/')
issues_url.path.squeeze!('/')
Loading
Loading
@@ -188,27 +172,6 @@ module Sentry
uri
end
 
def map_to_event(event)
stack_trace = parse_stack_trace(event)
Gitlab::ErrorTracking::ErrorEvent.new(
issue_id: event.dig('groupID'),
date_received: event.dig('dateReceived'),
stack_trace_entries: stack_trace
)
end
def parse_stack_trace(event)
exception_entry = event.dig('entries')&.detect { |h| h['type'] == 'exception' }
return [] unless exception_entry
exception_values = exception_entry.dig('data', 'values')
stack_trace_entry = exception_values&.detect { |h| h['stacktrace'].present? }
return [] unless stack_trace_entry
stack_trace_entry.dig('stacktrace', 'frames') || []
end
def map_to_error(issue)
Gitlab::ErrorTracking::Error.new(
id: issue.fetch('id'),
Loading
Loading
# frozen_string_literal: true
module Sentry
class Client
module Event
def issue_latest_event(issue_id:)
latest_event = http_get(issue_latest_event_api_url(issue_id))[:body]
map_to_event(latest_event)
end
private
def issue_latest_event_api_url(issue_id)
latest_event_url = URI(url)
latest_event_url.path = "/api/0/issues/#{issue_id}/events/latest/"
latest_event_url
end
def map_to_event(event)
stack_trace = parse_stack_trace(event)
Gitlab::ErrorTracking::ErrorEvent.new(
issue_id: event.dig('groupID'),
date_received: event.dig('dateReceived'),
stack_trace_entries: stack_trace
)
end
def parse_stack_trace(event)
exception_entry = event.dig('entries')&.detect { |h| h['type'] == 'exception' }
return [] unless exception_entry
exception_values = exception_entry.dig('data', 'values')
stack_trace_entry = exception_values&.detect { |h| h['stacktrace'].present? }
return [] unless stack_trace_entry
stack_trace_entry.dig('stacktrace', 'frames') || []
end
end
end
end
Loading
Loading
@@ -43,7 +43,7 @@
"@gitlab/ui": "8.10.0",
"@gitlab/visual-review-tools": "1.5.1",
"@sentry/browser": "^5.10.2",
"@sourcegraph/code-host-integration": "^0.0.16",
"@sourcegraph/code-host-integration": "^0.0.18",
"apollo-cache-inmemory": "^1.6.3",
"apollo-client": "^2.6.4",
"apollo-link": "^1.2.11",
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe Resolvers::Projects::GrafanaIntegrationResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
let_it_be(:current_user) { create(:user) }
let_it_be(:grafana_integration) { create(:grafana_integration, project: project)}
describe '#resolve' do
context 'when object is not a project' do
it { expect(resolve_integration(obj: current_user)).to eq nil }
end
context 'when object is a project' do
it { expect(resolve_integration(obj: project)).to eq grafana_integration }
end
context 'when object is nil' do
it { expect(resolve_integration(obj: nil)).to eq nil}
end
end
def resolve_integration(obj: project, context: { current_user: current_user })
resolve(described_class, obj: obj, ctx: context)
end
end
# frozen_string_literal: true
require 'spec_helper'
describe GitlabSchema.types['GrafanaIntegration'] do
let(:expected_fields) do
%i[
id
grafana_url
token
enabled
created_at
updated_at
]
end
it { expect(described_class.graphql_name).to eq('GrafanaIntegration') }
it { expect(described_class).to require_graphql_authorizations(:admin_operations) }
it { is_expected.to have_graphql_fields(*expected_fields) }
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment