Skip to content

API for related epics within a group

Nicolas Dular requested to merge nd/group-related-epics-api into master

What does this MR do and why?

Issue: #386169 (closed)

Adds an API on /groups/:id/related_epic_links which returns a list of RelatedEpicLink from the group and sub-groups. It also exposes the id, created_at, and updated_at attributes of an RelatedEpicLink.

While the RelatedEpicLinks are not directly part of a Group, this was a design trade-off we had to make to satisfy the requirement. See the discussion in #386169 (comment 1242444910).

Database

Tested with the gitlab-org group: https://console.postgres.ai/gitlab/gitlab-production-tunnel-pg12/sessions/15334/commands/53345

Resulting Query for the GitLab group
SELECT
  "related_epic_links".*
FROM
  "related_epic_links"
WHERE
  (
    "related_epic_links"."source_id" IN (
      SELECT
        "epics"."id"
      FROM
        "epics"
      WHERE
        "epics"."group_id" IN (
          SELECT
            "namespaces"."id"
          FROM
            "namespaces"
          WHERE
            "namespaces"."type" = 'Group'
            AND (traversal_ids @> ('{9970}'))
        )
      ORDER BY
        "epics"."id" DESC
    )
    OR "related_epic_links"."target_id" IN (
      SELECT
        "epics"."id"
      FROM
        "epics"
      WHERE
        "epics"."group_id" IN (
          SELECT
            "namespaces"."id"
          FROM
            "namespaces"
          WHERE
            "namespaces"."type" = 'Group'
            AND (traversal_ids @> ('{9970}'))
        )
      ORDER BY
        "epics"."id" DESC
    )
  )
ORDER BY
  "related_epic_links"."id" ASC
LIMIT
  20 OFFSET 0

How to set up and validate locally

  1. Create Epics and link them together
  2. Execute the curl command:
curl --header "PRIVATE-TOKEN: <PAT>"  "http://gdk.test:3000/api/v4/groups/<GROUP_ID>/related_epic_links" | jq
Example output
[
  {
    "id": 4,
    "source_epic": {
      "id": 2807,
      "iid": 15,
      "color": "#1068bf",
      "text_color": "#FFFFFF",
      "group_id": 22,
      "parent_id": null,
      "parent_iid": null,
      "title": "movable sub epic",
      "description": null,
      "confidential": false,
      "author": {
        "id": 1,
        "username": "root",
        "name": "Administrator",
        "state": "active",
        "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
        "web_url": "http://gdk.test:3000/root"
      },
      "start_date": null,
      "end_date": null,
      "due_date": null,
      "state": "opened",
      "web_url": "http://gdk.test:3000/groups/gitlab-org/-/epics/15",
      "references": {
        "short": "&15",
        "relative": "&15",
        "full": "gitlab-org&15"
      },
      "created_at": "2022-09-15T10:42:15.789Z",
      "updated_at": "2023-01-24T17:33:51.214Z",
      "closed_at": null,
      "labels": [],
      "upvotes": 0,
      "downvotes": 0,
      "_links": {
        "self": "http://gdk.test:3000/api/v4/groups/22/epics/15",
        "epic_issues": "http://gdk.test:3000/api/v4/groups/22/epics/15/issues",
        "group": "http://gdk.test:3000/api/v4/groups/22",
        "parent": null
      }
    },
    "target_epic": {
      "id": 2814,
      "iid": 20,
      "color": "#1068bf",
      "text_color": "#FFFFFF",
      "group_id": 22,
      "parent_id": 2788,
      "parent_iid": 6,
      "title": "first sub epic",
      "description": null,
      "confidential": false,
      "author": {
        "id": 1,
        "username": "root",
        "name": "Administrator",
        "state": "active",
        "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
        "web_url": "http://gdk.test:3000/root"
      },
      "start_date": null,
      "end_date": null,
      "due_date": null,
      "state": "opened",
      "web_url": "http://gdk.test:3000/groups/gitlab-org/-/epics/20",
      "references": {
        "short": "&20",
        "relative": "&20",
        "full": "gitlab-org&20"
      },
      "created_at": "2023-01-20T15:24:12.439Z",
      "updated_at": "2023-02-01T15:42:15.998Z",
      "closed_at": null,
      "labels": [],
      "upvotes": 0,
      "downvotes": 0,
      "_links": {
        "self": "http://gdk.test:3000/api/v4/groups/22/epics/20",
        "epic_issues": "http://gdk.test:3000/api/v4/groups/22/epics/20/issues",
        "group": "http://gdk.test:3000/api/v4/groups/22",
        "parent": "http://gdk.test:3000/api/v4/groups/22/epics/6"
      }
    },
    "link_type": "relates_to",
    "created_at": "2023-01-24T17:33:45.791Z",
    "updated_at": "2023-01-24T17:33:45.791Z"
  },
  {
    "id": 5,
    "source_epic": {
      "id": 2807,
      "iid": 15,
      "color": "#1068bf",
      "text_color": "#FFFFFF",
      "group_id": 22,
      "parent_id": null,
      "parent_iid": null,
      "title": "movable sub epic",
      "description": null,
      "confidential": false,
      "author": {
        "id": 1,
        "username": "root",
        "name": "Administrator",
        "state": "active",
        "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
        "web_url": "http://gdk.test:3000/root"
      },
      "start_date": null,
      "end_date": null,
      "due_date": null,
      "state": "opened",
      "web_url": "http://gdk.test:3000/groups/gitlab-org/-/epics/15",
      "references": {
        "short": "&15",
        "relative": "&15",
        "full": "gitlab-org&15"
      },
      "created_at": "2022-09-15T10:42:15.789Z",
      "updated_at": "2023-01-24T17:33:51.214Z",
      "closed_at": null,
      "labels": [],
      "upvotes": 0,
      "downvotes": 0,
      "_links": {
        "self": "http://gdk.test:3000/api/v4/groups/22/epics/15",
        "epic_issues": "http://gdk.test:3000/api/v4/groups/22/epics/15/issues",
        "group": "http://gdk.test:3000/api/v4/groups/22",
        "parent": null
      }
    },
    "target_epic": {
      "id": 2812,
      "iid": 18,
      "color": "#1068bf",
      "text_color": "#FFFFFF",
      "group_id": 22,
      "parent_id": null,
      "parent_iid": null,
      "title": "other epic",
      "description": null,
      "confidential": false,
      "author": {
        "id": 1,
        "username": "root",
        "name": "Administrator",
        "state": "active",
        "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
        "web_url": "http://gdk.test:3000/root"
      },
      "start_date": null,
      "end_date": null,
      "due_date": null,
      "state": "opened",
      "web_url": "http://gdk.test:3000/groups/gitlab-org/-/epics/18",
      "references": {
        "short": "&18",
        "relative": "&18",
        "full": "gitlab-org&18"
      },
      "created_at": "2022-12-20T11:12:34.746Z",
      "updated_at": "2023-02-03T13:57:35.686Z",
      "closed_at": null,
      "labels": [],
      "upvotes": 0,
      "downvotes": 0,
      "_links": {
        "self": "http://gdk.test:3000/api/v4/groups/22/epics/18",
        "epic_issues": "http://gdk.test:3000/api/v4/groups/22/epics/18/issues",
        "group": "http://gdk.test:3000/api/v4/groups/22",
        "parent": null
      }
    },
    "link_type": "relates_to",
    "created_at": "2023-01-24T17:33:51.184Z",
    "updated_at": "2023-01-24T17:33:51.184Z"
  },
  {
    "id": 6,
    "source_epic": {
      "id": 2814,
      "iid": 20,
      "color": "#1068bf",
      "text_color": "#FFFFFF",
      "group_id": 22,
      "parent_id": 2788,
      "parent_iid": 6,
      "title": "first sub epic",
      "description": null,
      "confidential": false,
      "author": {
        "id": 1,
        "username": "root",
        "name": "Administrator",
        "state": "active",
        "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
        "web_url": "http://gdk.test:3000/root"
      },
      "start_date": null,
      "end_date": null,
      "due_date": null,
      "state": "opened",
      "web_url": "http://gdk.test:3000/groups/gitlab-org/-/epics/20",
      "references": {
        "short": "&20",
        "relative": "&20",
        "full": "gitlab-org&20"
      },
      "created_at": "2023-01-20T15:24:12.439Z",
      "updated_at": "2023-02-01T15:42:15.998Z",
      "closed_at": null,
      "labels": [],
      "upvotes": 0,
      "downvotes": 0,
      "_links": {
        "self": "http://gdk.test:3000/api/v4/groups/22/epics/20",
        "epic_issues": "http://gdk.test:3000/api/v4/groups/22/epics/20/issues",
        "group": "http://gdk.test:3000/api/v4/groups/22",
        "parent": "http://gdk.test:3000/api/v4/groups/22/epics/6"
      }
    },
    "target_epic": {
      "id": 35,
      "iid": 5,
      "color": "#1068bf",
      "text_color": "#FFFFFF",
      "group_id": 35,
      "parent_id": null,
      "parent_iid": null,
      "title": "Eius quaerat non perferendis harum consequuntur rem sint sint voluptate.",
      "description": "Illum et exercitationem expedita ut voluptatem quas perspiciatis. Quas delectus numquam autem id. A corrupti totam animi alias repellat.\n\nVeniam error reprehenderit ut officiis hic. Expedita velit ipsam minus rerum pariatur quasi omnis nihil. Minus odit eius voluptatem aperiam eum. Velit exercitationem quidem excepturi quibusdam quam quas aliquam ea. Ut qui voluptas quaerat rerum dolores omnis.\n\nSit amet delectus et voluptatem et voluptatibus provident. Consequuntur consequatur dicta sint et deserunt nihil. Omnis ut soluta magnam quae praesentium.",
      "confidential": false,
      "author": {
        "id": 4,
        "username": "matha_heidenreich",
        "name": "Fransisca Willms",
        "state": "active",
        "avatar_url": "https://www.gravatar.com/avatar/9cfbabdadd7cbfbf66f790a6e19f0d37?s=80&d=identicon",
        "web_url": "http://gdk.test:3000/matha_heidenreich"
      },
      "start_date": null,
      "end_date": null,
      "due_date": null,
      "state": "opened",
      "web_url": "http://gdk.test:3000/groups/h5bp/-/epics/5",
      "references": {
        "short": "&5",
        "relative": "&5",
        "full": "h5bp&5"
      },
      "created_at": "2022-08-10T13:17:17.406Z",
      "updated_at": "2023-02-01T15:42:16.059Z",
      "closed_at": null,
      "labels": [],
      "upvotes": 0,
      "downvotes": 0,
      "_links": {
        "self": "http://gdk.test:3000/api/v4/groups/35/epics/5",
        "epic_issues": "http://gdk.test:3000/api/v4/groups/35/epics/5/issues",
        "group": "http://gdk.test:3000/api/v4/groups/35",
        "parent": null
      }
    },
    "link_type": "relates_to",
    "created_at": "2023-02-01T15:42:15.959Z",
    "updated_at": "2023-02-01T15:42:15.959Z"
  }
]

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Nicolas Dular

Merge request reports

Loading