Verified Commit 9612efaf authored by Dmitry Gruzd's avatar Dmitry Gruzd 2️⃣ Committed by GitLab
Browse files

docs(skill): add pipeline-for-MR recipe with source filter

parent 22717833
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -272,6 +272,47 @@ Find merged merge requests in a project:
}
```

Find every pipeline that ran for one merge request. Always filter
`Pipeline.source = "merge_request_event"` to match what the merge request's
**Pipelines** tab, the REST `/merge_requests/:iid/pipelines` endpoint, and
the GraphQL `mergeRequest.pipelines` connection return:

```json
{
  "query_type": "traversal",
  "node": {
    "id": "p",
    "entity": "Pipeline",
    "filters": {
      "merge_request_id": {"op": "eq", "value": 482908721},
      "source": {"op": "eq", "value": "merge_request_event"}
    },
    "columns": ["id", "status", "source", "sha", "ref", "created_at"]
  },
  "order_by": {"node": "p", "property": "created_at", "direction": "DESC"},
  "limit": 100
}
```

`merge_request_id` is the merge request's internal numeric `id`, not the
project-scoped `iid`. Look it up first with a `MergeRequest` traversal that
filters by `iid` and `project_id`, then plug the `id` into the query above.

Both `Pipeline.merge_request_id` and the `MergeRequest --TRIGGERED-->
Pipeline` edge link an MR to every CI pipeline spawned in its context,
including the downstream child pipelines (`source = "parent_pipeline"`)
that the top-level MR pipelines trigger. Without the
`source = "merge_request_event"` filter, the result over-counts by a large
factor on any MR that uses parent-child pipeline fan-out, and does not
match the MR UI or the REST and GraphQL definitions of "pipelines for this
MR". Apply the same filter when traversing
`MergeRequest --TRIGGERED--> Pipeline` in a multi-node query.

`MergeRequest --HAS_HEAD_PIPELINE--> Pipeline` is a different edge. It
points to the single most recent pipeline running against the tip of the
merge request's source branch. Use it for "what is currently running", not
for pipeline history.

## Aggregation

Aggregation queries use `aggregations`.
+25 −1
Original line number Diff line number Diff line
---
name: orbit
description: Query the GitLab Knowledge Graph (Orbit) via `glab orbit remote` CLI subcommands or run a local copy with `glab orbit local`. Use for code-structure questions (who calls this function, where is this symbol defined), cross-project dependency and blast-radius analysis, merge-request and contributor queries, and any question answerable by traversing GitLab's unified entity graph (projects, users, MRs, issues, pipelines, files, definitions, vulnerabilities).
version: 0.6.0
version: 0.7.0
license: MIT
metadata:
  audience: developers
@@ -68,6 +68,30 @@ shorthand equality (`{"state": "opened"}`) or the operator form
and `path_finding` use `nodes` (array) plus `relationships`. `max_depth`
and `max_hops` are capped at 3 server-side.

## Common pitfalls

Read [`references/recipes.md`](references/recipes.md) before constructing a
query — the same question often has one canonical paste-ready shape and
several wrong-looking-correct shapes. Two traps come up often:

- **"Pipelines for a merge request" requires `Pipeline.source =
  "merge_request_event"`.** The graph links every CI pipeline spawned in the
  context of an MR to that MR — including downstream child pipelines
  (`source = "parent_pipeline"`) that the top-level MR pipelines triggered.
  Both `Pipeline.merge_request_id` and the `MergeRequest --TRIGGERED-->
  Pipeline` edge return parents *and* children. Apply the
  `source = "merge_request_event"` filter (or use the canonical recipe in
  [`recipes.md`](references/recipes.md#pipelines-that-ran-for-one-merge-request))
  to match what the MR **Pipelines** tab, the REST
  `/merge_requests/:iid/pipelines` endpoint, and the GraphQL
  `mergeRequest.pipelines` connection return.
- **Prefer single-node queries when you can bound the target entity
  directly.** Adding extra nodes/relationships only to "anchor" the query
  (for example, joining `Project` + `MergeRequest` + `Pipeline` when you
  already know the MR's `merge_request_id`) can change the row shape in
  ways that affect `aggregation` counts. When `recipes.md` shows a
  single-node form for your question, use it.

## References

| Topic | Location |
+41 −4
Original line number Diff line number Diff line
@@ -25,10 +25,6 @@ title: Orbit query language
> For more information, see the history.
> This feature is available for testing, but not ready for production use.

<!-- -->

> [!disclaimer]

Use the Orbit query language when you need GitLab data as a graph instead of a
flat API response. A query is a JSON object. It names the entities to match,
the relationships to follow, and the properties to return.
@@ -276,6 +272,47 @@ Find merged merge requests in a project:
}
```

Find every pipeline that ran for one merge request. Always filter
`Pipeline.source = "merge_request_event"` to match what the merge request's
**Pipelines** tab, the REST `/merge_requests/:iid/pipelines` endpoint, and
the GraphQL `mergeRequest.pipelines` connection return:

```json
{
  "query_type": "traversal",
  "node": {
    "id": "p",
    "entity": "Pipeline",
    "filters": {
      "merge_request_id": {"op": "eq", "value": 482908721},
      "source": {"op": "eq", "value": "merge_request_event"}
    },
    "columns": ["id", "status", "source", "sha", "ref", "created_at"]
  },
  "order_by": {"node": "p", "property": "created_at", "direction": "DESC"},
  "limit": 100
}
```

`merge_request_id` is the merge request's internal numeric `id`, not the
project-scoped `iid`. Look it up first with a `MergeRequest` traversal that
filters by `iid` and `project_id`, then plug the `id` into the query above.

Both `Pipeline.merge_request_id` and the `MergeRequest --TRIGGERED-->
Pipeline` edge link an MR to every CI pipeline spawned in its context,
including the downstream child pipelines (`source = "parent_pipeline"`)
that the top-level MR pipelines trigger. Without the
`source = "merge_request_event"` filter, the result over-counts by a large
factor on any MR that uses parent-child pipeline fan-out, and does not
match the MR UI or the REST and GraphQL definitions of "pipelines for this
MR". Apply the same filter when traversing
`MergeRequest --TRIGGERED--> Pipeline` in a multi-node query.

`MergeRequest --HAS_HEAD_PIPELINE--> Pipeline` is a different edge. It
points to the single most recent pipeline running against the tip of the
merge request's source branch. Use it for "what is currently running", not
for pipeline history.

## Aggregation

Aggregation queries use `aggregations`.
+106 −0
Original line number Diff line number Diff line
@@ -75,6 +75,112 @@ Find up to 5 projects whose `full_path` contains `gitlab-org/cli`:
}
```

## Pipelines that ran for one merge request

> **Always filter `Pipeline.source = "merge_request_event"` for this question.**
> The graph also stores the downstream child pipelines those top-level MR
> pipelines triggered (`source = "parent_pipeline"`). Both
> `Pipeline.merge_request_id` and the `MergeRequest --TRIGGERED--> Pipeline`
> edge return parents **and** children. Without the `source` filter you
> will over-count by a factor of 5-10× and the answer will not match the
> MR's **Pipelines** tab, the REST `/merge_requests/:iid/pipelines`
> endpoint, or the GraphQL `mergeRequest.pipelines` connection.
> `MergeRequest --HAS_HEAD_PIPELINE--> Pipeline` is unrelated: it points
> to the one current head pipeline, useful for "what is running now" but
> not for history.

The canonical query is single-node and filters `Pipeline.merge_request_id`
plus `source`. `merge_request_id` is the MR's internal numeric `id` (not the
project-scoped `iid`); look it up first with the
[MR-by-IID recipe](#look-up-a-merge-request-by-iid) and reuse the returned
`id`.

```json
{
  "query": {
    "query_type": "traversal",
    "node": {
      "id": "p", "entity": "Pipeline",
      "filters": {
        "merge_request_id": {"op": "eq", "value": 482908721},
        "source": {"op": "eq", "value": "merge_request_event"}
      },
      "columns": ["id", "status", "source", "sha", "ref", "created_at"]
    },
    "order_by": {"node": "p", "property": "created_at", "direction": "DESC"},
    "limit": 100
  }
}
```

Apply the same filter when narrowing by status — for example, "failed
pipelines for this MR":

```json
{
  "query": {
    "query_type": "traversal",
    "node": {
      "id": "p", "entity": "Pipeline",
      "filters": {
        "merge_request_id": {"op": "eq", "value": 482908721},
        "source": {"op": "eq", "value": "merge_request_event"},
        "status": {"op": "eq", "value": "failed"}
      },
      "columns": ["id", "status", "sha", "ref", "failure_reason", "duration", "created_at"]
    },
    "order_by": {"node": "p", "property": "created_at", "direction": "DESC"},
    "limit": 100
  }
}
```

Count by status with a single-node `aggregation` (keep the node count at
one — adding `MergeRequest` or `Project` as extra nodes can change the
underlying join shape and inflate the count):

```json
{
  "query": {
    "query_type": "aggregation",
    "nodes": [
      {"id": "p", "entity": "Pipeline",
       "filters": {
         "merge_request_id": {"op": "eq", "value": 482908721},
         "source": {"op": "eq", "value": "merge_request_event"}
       }}
    ],
    "group_by": [{"kind": "property", "node": "p", "property": "status", "alias": "status"}],
    "aggregations": [{"function": "count", "target": "p", "alias": "pipeline_count"}],
    "aggregation_sort": {"column": "pipeline_count", "direction": "DESC"},
    "limit": 20
  }
}
```

If you only have the MR's `iid` and not its internal `id`, the equivalent
two-node form via `TRIGGERED` works — still with the `source` filter on the
Pipeline node:

```json
{
  "query": {
    "query_type": "traversal",
    "nodes": [
      {"id": "mr", "entity": "MergeRequest",
       "filters": {"iid": {"op": "eq", "value": 235291},
                   "project_id": {"op": "eq", "value": 278964}}},
      {"id": "p",  "entity": "Pipeline",
       "filters": {"source": {"op": "eq", "value": "merge_request_event"}},
       "columns": ["id", "status", "sha", "created_at"]}
    ],
    "relationships": [{"type": "TRIGGERED", "from": "mr", "to": "p"}],
    "order_by": {"node": "p", "property": "created_at", "direction": "DESC"},
    "limit": 100
  }
}
```

## `traversal` (multi-node) — start from nodes, follow relationships

List opened merge requests and their authors. Requires at least two nodes and