Add Orbit indexing status and item counts GraphQL fields
What does this MR do and why?
This MR adds an experimental orbit { indexingStatus itemCounts } field on the Group and Project GraphQL types (19.5), in place of the hidden REST endpoints that it first added. The UI can ask for one group, one project, or a full page of groups in one request, and nothing calls the field yet.
- All
indexingStatusfields in one query use one Orbit gRPC call (GetIndexingStatus), in slices of 100 paths. Paths outside the user's Orbit scope are not sent, and their field returnsnull. itemCountscan be requested for only one group or project in each query.- Rate limits for each user:
orbit_indexing_status30 requests per minute (one batched query counts once),orbit_item_counts10 per minute.
orbit is null when Orbit is not available to the user, and a granular personal access token needs read_orbit (user boundary) plus read_group or read_project. If the Orbit server is older than v0.135.0, the fields return null, so this MR can merge before the Orbit deploy. A follow-up moves orbitTrial, knowledgeGraphEnabled, and knowledgeGraphAvailable under orbit.
GraphQL examples
Real responses from a local GDK with this branch and Orbit v0.135.0.
A group and one of its projects in one query (one gRPC call)
query {
group(fullPath: "e2e-status-ready-1790460357") {
orbit {
indexingStatus { phase projects { indexed totalKnown gaps } domains { name phase } }
}
}
project(fullPath: "e2e-status-ready-1790460357/code1") {
orbit { indexingStatus { phase } }
}
}{
"data": {
"group": {
"orbit": {
"indexingStatus": {
"phase": "READY",
"projects": {
"indexed": 4,
"totalKnown": 4,
"gaps": 0
},
"domains": [
{
"name": "ci",
"phase": "READY"
},
{
"name": "code_review",
"phase": "READY"
},
{
"name": "container_registry",
"phase": "READY"
},
{
"name": "core",
"phase": "READY"
},
{
"name": "packages",
"phase": "READY"
},
{
"name": "plan",
"phase": "READY"
},
{
"name": "security",
"phase": "READY"
},
{
"name": "source_code",
"phase": "READY"
}
]
}
}
},
"project": {
"orbit": {
"indexingStatus": {
"phase": "READY"
}
}
}
}
}A page of enabled top-level groups (one gRPC call for the page)
query {
groups(topLevelOnly: true, withKnowledgeGraphEnabled: true, first: 3) {
nodes { fullPath orbit { indexingStatus { phase } } }
}
}{
"data": {
"groups": {
"nodes": [
{
"fullPath": "e2e-serving-1789135217",
"orbit": {
"indexingStatus": {
"phase": "READY"
}
}
},
{
"fullPath": "e2e-status-late-1790460357",
"orbit": {
"indexingStatus": {
"phase": "READY"
}
}
},
{
"fullPath": "e2e-status-latewrite-1790460357",
"orbit": {
"indexingStatus": {
"phase": "READY"
}
}
}
]
}
}
}A Reporter asks for their group and for `gitlab-org`, which is outside their Orbit scope
query {
mine: group(fullPath: "e2e-status-ready-1790460357") { orbit { indexingStatus { phase } } }
other: group(fullPath: "gitlab-org") { orbit { indexingStatus { phase } } }
}{
"data": {
"mine": {
"orbit": {
"indexingStatus": {
"phase": "READY"
}
}
},
"other": {
"orbit": {
"indexingStatus": null
}
}
}
}Item counts for one project
query {
project(fullPath: "e2e-status-ready-1790460357/code1") {
orbit { itemCounts { domains { name entities { name count } } } }
}
}{
"data": {
"project": {
"orbit": {
"itemCounts": {
"domains": [
{
"name": "ci",
"entities": [
{
"name": "Deployment",
"count": "0"
},
{
"name": "Environment",
"count": "0"
},
{
"name": "Job",
"count": "0"
},
{
"name": "Pipeline",
"count": "4"
},
{
"name": "Stage",
"count": "0"
}
]
},
{
"name": "code_review",
"entities": [
{
"name": "MergeRequest",
"count": "1"
},
{
"name": "MergeRequestDiff",
"count": "3"
},
{
"name": "MergeRequestDiffFile",
"count": "0"
}
]
},
{
"name": "container_registry",
"entities": [
{
"name": "ContainerRepository",
"count": "0"
}
]
},
{
"name": "core",
"entities": [
{
"name": "Group",
"count": "0"
},
{
"name": "Note",
"count": "0"
},
{
"name": "Project",
"count": "1"
}
]
},
{
"name": "packages",
"entities": [
{
"name": "Dependency",
"count": "0"
},
{
"name": "Package",
"count": "0"
},
{
"name": "PackageFile",
"count": "0"
}
]
},
{
"name": "plan",
"entities": [
{
"name": "Label",
"count": "0"
},
{
"name": "Milestone",
"count": "0"
},
{
"name": "WorkItem",
"count": "1"
}
]
},
{
"name": "security",
"entities": [
{
"name": "Finding",
"count": "0"
},
{
"name": "SecurityScan",
"count": "0"
},
{
"name": "Vulnerability",
"count": "0"
},
{
"name": "VulnerabilityIdentifier",
"count": "0"
},
{
"name": "VulnerabilityOccurrence",
"count": "0"
},
{
"name": "VulnerabilityScanner",
"count": "0"
}
]
},
{
"name": "source_code",
"entities": [
{
"name": "Branch",
"count": "1"
},
{
"name": "Commit",
"count": "0"
},
{
"name": "Definition",
"count": "3"
},
{
"name": "Directory",
"count": "1"
},
{
"name": "File",
"count": "3"
},
{
"name": "ImportedSymbol",
"count": "0"
}
]
}
]
}
}
}
}
}Item counts for a group and a project in one query (error)
query {
group(fullPath: "gitlab-org") { orbit { itemCounts { domains { name } } } }
project(fullPath: "e2e-status-ready-1790460357/code1") { orbit { itemCounts { domains { name } } } }
}{
"errors": [
{
"message": "\"itemCounts\" field can be requested only for 1 OrbitNamespace(s) at a time.",
"locations": [
{
"line": 3,
"column": 68
}
],
"path": [
"project",
"orbit",
"itemCounts"
]
}
],
"data": {
"group": {
"orbit": {
"itemCounts": {
"domains": [
{
"name": "ci"
},
{
"name": "code_review"
},
{
"name": "container_registry"
},
{
"name": "core"
},
{
"name": "packages"
},
{
"name": "plan"
},
{
"name": "security"
},
{
"name": "source_code"
}
]
}
}
},
"project": {
"orbit": {
"itemCounts": null
}
}
}
}References
- Relates to #631192 (closed)
- Parent: gitlab-org/orbit/knowledge-graph#1281 (closed)
- Orbit: gitlab-org/orbit/knowledge-graph!2668 (merged) (one path for
GetItemCounts)
Screenshots or screen recordings
The demo shows one group, a group and a project in one query, all enabled groups in one call (the Orbit server log shows one call each time), a Reporter with a group outside their Orbit scope (null, no error), item counts for a project and for a group, two item counts in one query (error), and the rate limit on item counts.
How to set up and validate locally
-
Run Orbit v0.135.0 with GDK, and enable Orbit on a group.
-
Open GraphiQL at
http://gdk.test:3000/-/graphql-explorerand run a query:query { group(fullPath: "<group_path>") { orbit { indexingStatus { phase projects { indexed totalKnown gaps } domains { name phase } } } } } -
Run a query for
itemCountson one project:query { project(fullPath: "<project_path>") { orbit { itemCounts { domains { name entities { name count } } } } } }
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist.