Commit 3864bf4e authored by Toon Claes's avatar Toon Claes

Geo: Implement GraphQL endpoint for MR diffs

Implement the GraphQL endpoint as documented at:
https://docs.gitlab.com/ee/development/geo/framework.html#graphql-api

Closes https://gitlab.com/gitlab-org/gitlab/-/issues/215138
parent f0722cd8
...@@ -6407,6 +6407,37 @@ type GeoNode { ...@@ -6407,6 +6407,37 @@ type GeoNode {
""" """
internalUrl: String internalUrl: String
"""
Find merge request diff registries on this Geo node. Available only when
feature flag `geo_merge_request_diff_replication` is enabled
"""
mergeRequestDiffRegistries(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Filters registries by their ID
"""
ids: [ID!]
"""
Returns the last _n_ elements from the list.
"""
last: Int
): MergeRequestDiffRegistryConnection
""" """
The interval (in days) in which the repository verification is valid. Once expired, it will be reverified The interval (in days) in which the repository verification is valid. Once expired, it will be reverified
""" """
...@@ -10199,6 +10230,86 @@ type MergeRequestCreatePayload { ...@@ -10199,6 +10230,86 @@ type MergeRequestCreatePayload {
mergeRequest: MergeRequest mergeRequest: MergeRequest
} }
"""
Represents the sync and verification state of a Merge Request diff
"""
type MergeRequestDiffRegistry {
"""
Timestamp when the MergeRequestDiffRegistry was created
"""
createdAt: Time
"""
ID of the MergeRequestDiffRegistry
"""
id: ID!
"""
Error message during sync of the MergeRequestDiffRegistry
"""
lastSyncFailure: String
"""
Timestamp of the most recent successful sync of the MergeRequestDiffRegistry
"""
lastSyncedAt: Time
"""
ID of the Merge Request diff
"""
mergeRequestDiffId: ID!
"""
Timestamp after which the MergeRequestDiffRegistry should be resynced
"""
retryAt: Time
"""
Number of consecutive failed sync attempts of the MergeRequestDiffRegistry
"""
retryCount: Int
"""
Sync state of the MergeRequestDiffRegistry
"""
state: RegistryState
}
"""
The connection type for MergeRequestDiffRegistry.
"""
type MergeRequestDiffRegistryConnection {
"""
A list of edges.
"""
edges: [MergeRequestDiffRegistryEdge]
"""
A list of nodes.
"""
nodes: [MergeRequestDiffRegistry]
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
}
"""
An edge in a connection.
"""
type MergeRequestDiffRegistryEdge {
"""
A cursor for use in pagination.
"""
cursor: String!
"""
The item at the end of the edge.
"""
node: MergeRequestDiffRegistry
}
""" """
An edge in a connection. An edge in a connection.
""" """
......
...@@ -17857,6 +17857,77 @@ ...@@ -17857,6 +17857,77 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "mergeRequestDiffRegistries",
"description": "Find merge request diff registries on this Geo node. Available only when feature flag `geo_merge_request_diff_replication` is enabled",
"args": [
{
"name": "ids",
"description": "Filters registries by their ID",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
}
},
"defaultValue": null
},
{
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "before",
"description": "Returns the elements in the list that come before the specified cursor.",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "first",
"description": "Returns the first _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
},
{
"name": "last",
"description": "Returns the last _n_ elements from the list.",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "MergeRequestDiffRegistryConnection",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "minimumReverificationInterval", "name": "minimumReverificationInterval",
"description": "The interval (in days) in which the repository verification is valid. Once expired, it will be reverified", "description": "The interval (in days) in which the repository verification is valid. Once expired, it will be reverified",
...@@ -28162,6 +28233,251 @@ ...@@ -28162,6 +28233,251 @@
"enumValues": null, "enumValues": null,
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "OBJECT",
"name": "MergeRequestDiffRegistry",
"description": "Represents the sync and verification state of a Merge Request diff",
"fields": [
{
"name": "createdAt",
"description": "Timestamp when the MergeRequestDiffRegistry was created",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
"description": "ID of the MergeRequestDiffRegistry",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "lastSyncFailure",
"description": "Error message during sync of the MergeRequestDiffRegistry",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "lastSyncedAt",
"description": "Timestamp of the most recent successful sync of the MergeRequestDiffRegistry",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "mergeRequestDiffId",
"description": "ID of the Merge Request diff",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "retryAt",
"description": "Timestamp after which the MergeRequestDiffRegistry should be resynced",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "retryCount",
"description": "Number of consecutive failed sync attempts of the MergeRequestDiffRegistry",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "state",
"description": "Sync state of the MergeRequestDiffRegistry",
"args": [
],
"type": {
"kind": "ENUM",
"name": "RegistryState",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "MergeRequestDiffRegistryConnection",
"description": "The connection type for MergeRequestDiffRegistry.",
"fields": [
{
"name": "edges",
"description": "A list of edges.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "MergeRequestDiffRegistryEdge",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "nodes",
"description": "A list of nodes.",
"args": [
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "MergeRequestDiffRegistry",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "pageInfo",
"description": "Information to aid in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "PageInfo",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "MergeRequestDiffRegistryEdge",
"description": "An edge in a connection.",
"fields": [
{
"name": "cursor",
"description": "A cursor for use in pagination.",
"args": [
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "node",
"description": "The item at the end of the edge.",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "MergeRequestDiffRegistry",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{ {
"kind": "OBJECT", "kind": "OBJECT",
"name": "MergeRequestEdge", "name": "MergeRequestEdge",
...@@ -1497,6 +1497,21 @@ Autogenerated return type of MergeRequestCreate. ...@@ -1497,6 +1497,21 @@ Autogenerated return type of MergeRequestCreate.
| `errors` | String! => Array | Errors encountered during execution of the mutation. | | `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `mergeRequest` | MergeRequest | The merge request after mutation | | `mergeRequest` | MergeRequest | The merge request after mutation |
### MergeRequestDiffRegistry
Represents the sync and verification state of a Merge Request diff.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `createdAt` | Time | Timestamp when the MergeRequestDiffRegistry was created |
| `id` | ID! | ID of the MergeRequestDiffRegistry |
| `lastSyncFailure` | String | Error message during sync of the MergeRequestDiffRegistry |
| `lastSyncedAt` | Time | Timestamp of the most recent successful sync of the MergeRequestDiffRegistry |
| `mergeRequestDiffId` | ID! | ID of the Merge Request diff |
| `retryAt` | Time | Timestamp after which the MergeRequestDiffRegistry should be resynced |
| `retryCount` | Int | Number of consecutive failed sync attempts of the MergeRequestDiffRegistry |
| `state` | RegistryState | Sync state of the MergeRequestDiffRegistry |
### MergeRequestPermissions ### MergeRequestPermissions
Check permissions for the current user on a merge request. Check permissions for the current user on a merge request.
......
# frozen_string_literal: true
module Geo
class MergeRequestDiffRegistryFinder
include FrameworkRegistryFinder
end
end
# frozen_string_literal: true
module Resolvers
module Geo
class MergeRequestDiffRegistriesResolver < BaseResolver
include RegistriesResolver
end
end
end
...@@ -22,6 +22,11 @@ module Types ...@@ -22,6 +22,11 @@ module Types
field :selective_sync_shards, type: [GraphQL::STRING_TYPE], null: true, description: 'The repository storages whose projects should be synced, if `selective_sync_type` == `shards`' field :selective_sync_shards, type: [GraphQL::STRING_TYPE], null: true, description: 'The repository storages whose projects should be synced, if `selective_sync_type` == `shards`'
field :selective_sync_namespaces, ::Types::NamespaceType.connection_type, null: true, method: :namespaces, description: 'The namespaces that should be synced, if `selective_sync_type` == `namespaces`' field :selective_sync_namespaces, ::Types::NamespaceType.connection_type, null: true, method: :namespaces, description: 'The namespaces that should be synced, if `selective_sync_type` == `namespaces`'
field :minimum_reverification_interval, GraphQL::INT_TYPE, null: true, description: 'The interval (in days) in which the repository verification is valid. Once expired, it will be reverified' field :minimum_reverification_interval, GraphQL::INT_TYPE, null: true, description: 'The interval (in days) in which the repository verification is valid. Once expired, it will be reverified'
field :merge_request_diff_registries, ::Types::Geo::MergeRequestDiffRegistryType.connection_type,
null: true,
resolver: ::Resolvers::Geo::MergeRequestDiffRegistriesResolver,
description: 'Find merge request diff registries on this Geo node',
feature_flag: :geo_merge_request_diff_replication
field :package_file_registries, ::Types::Geo::PackageFileRegistryType.connection_type, field :package_file_registries, ::Types::Geo::PackageFileRegistryType.connection_type,
null: true, null: true,
resolver: ::Resolvers::Geo::PackageFileRegistriesResolver, resolver: ::Resolvers::Geo::PackageFileRegistriesResolver,
......
# frozen_string_literal: true
module Types
module Geo
# rubocop:disable Graphql/AuthorizeTypes because it is included
class MergeRequestDiffRegistryType < BaseObject
include ::Types::Geo::RegistryType
graphql_name 'MergeRequestDiffRegistry'
description 'Represents the sync and verification state of a Merge Request diff'
field :merge_request_diff_id, GraphQL::ID_TYPE, null: false, description: 'ID of the Merge Request diff'
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Geo::MergeRequestDiffRegistryFinder do
it_behaves_like 'a framework registry finder', :geo_merge_request_diff_registry
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::Geo::MergeRequestDiffRegistriesResolver do
it_behaves_like 'a Geo registries resolver', :geo_merge_request_diff_registry
end
...@@ -11,7 +11,8 @@ RSpec.describe GitlabSchema.types['GeoNode'] do ...@@ -11,7 +11,8 @@ RSpec.describe GitlabSchema.types['GeoNode'] do
repos_max_capacity verification_max_capacity repos_max_capacity verification_max_capacity
container_repositories_max_capacity sync_object_storage container_repositories_max_capacity sync_object_storage
selective_sync_type selective_sync_shards selective_sync_namespaces selective_sync_type selective_sync_shards selective_sync_namespaces
minimum_reverification_interval package_file_registries minimum_reverification_interval merge_request_diff_registries
package_file_registries
terraform_state_registries terraform_state_version_registries terraform_state_registries terraform_state_version_registries
] ]
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['MergeRequestDiffRegistry'] do
it_behaves_like 'a Geo registry type'
it 'has the expected fields (other than those included in RegistryType)' do
expected_fields = %i[merge_request_diff_id]
expect(described_class).to have_graphql_fields(*expected_fields).at_least
end
end
...@@ -3,6 +3,13 @@ ...@@ -3,6 +3,13 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'Gets registries' do RSpec.describe 'Gets registries' do
it_behaves_like 'gets registries for', {
field_name: 'mergeRequestDiffRegistries',
registry_class_name: 'MergeRequestDiffRegistry',
registry_factory: :geo_merge_request_diff_registry,
registry_foreign_key_field_name: 'mergeRequestDiffId'
}
it_behaves_like 'gets registries for', { it_behaves_like 'gets registries for', {
field_name: 'packageFileRegistries', field_name: 'packageFileRegistries',
registry_class_name: 'PackageFileRegistry', registry_class_name: 'PackageFileRegistry',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment