Adds lifecycle and status templates

What does this MR do and why?

This change adds a new "lifecycle templates" feature to GitLab's GraphQL API. It'll allow users to pick from predefined lifecycles upon lifecycle creation as a starting point.

The implementation creates template objects that combine system-defined statuses with any custom statuses that users have created with matching names. This means if a user has customized a status like "To Do" with their own color or description, the template will show those customizations instead of the defaults (to prevent overrides).

The feature includes comprehensive test coverage and is marked as experimental, introduced in GitLab version 18.4. Users need appropriate permissions to access these lifecycle templates through the API.

References

Screenshots or screen recordings

image

How to set up and validate locally

Open the GraphQL explorer and run the following query on a root group that doesn't use custom statuses:

query getNamespaceLifecycles {
  namespace(fullPath: "jashkenas") {
    lifecycleTemplates {
      id
      name
      workItemTypes {
        id
      }
      statuses {
        id
        name
        color
        description
        category
        iconName
      }
      defaultOpenStatus {
        id
        name
        color
        description
        category
        iconName
      }
      defaultClosedStatus {
        id
        name
        color
        description
        category
        iconName
      }
      defaultDuplicateStatus {
        id
        name
        color
        description
        category
        iconName
      }
    }
  }
}

The result should look like this:

Click to expand
{
  "data": {
    "namespace": {
      "lifecycleTemplates": [
        {
          "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Lifecycle/Default",
          "name": "Default",
          "workItemTypes": [],
          "statuses": [
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/To+do",
              "name": "To do",
              "color": "#737278",
              "description": null,
              "category": "to_do",
              "iconName": "status-waiting"
            },
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/In+progress",
              "name": "In progress",
              "color": "#1f75cb",
              "description": null,
              "category": "in_progress",
              "iconName": "status-running"
            },
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Done",
              "name": "Done",
              "color": "#108548",
              "description": null,
              "category": "done",
              "iconName": "status-success"
            },
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Won%27t+do",
              "name": "Won't do",
              "color": "#DD2B0E",
              "description": null,
              "category": "canceled",
              "iconName": "status-cancelled"
            },
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Duplicate",
              "name": "Duplicate",
              "color": "#DD2B0E",
              "description": null,
              "category": "canceled",
              "iconName": "status-cancelled"
            }
          ],
          "defaultOpenStatus": {
            "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/To+do",
            "name": "To do",
            "color": "#737278",
            "description": null,
            "category": "to_do"
          },
          "defaultClosedStatus": {
            "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Done",
            "name": "Done",
            "color": "#108548",
            "description":null
            "category": "done"
          },
          "defaultDuplicateStatus": {
            "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Duplicate",
            "name": "Duplicate",
            "color": "#DD2B0E",
            "description": null,
            "category": "canceled"
          }
        }
      ]
    }
  },
  "correlationId": "01K397H28R14QAEM2YWJT57GZM"
}

Now browse to another top level group and go to the Issues settings (e.g. http://127.0.0.1:3000/groups/jashkenas/-/settings/issues) and modify the statuses (like color and description), but keep names as is for now.

Perform the same query as above but with the new namespace name.

See that the result is different and it uses the newly updated attributes also in the template to prevent overrides when we use these to create new lifecycles later on.

For example:

Click to expand
{
  "data": {
    "namespace": {
      "lifecycleTemplates": [
        {
          "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Lifecycle/Default",
          "name": "Default",
          "workItemTypes": [],
          "statuses": [
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/To+do",
              "name": "To do",
              "color": "#737278",
              "description": null,
              "category": "to_do",
              "iconName": "status-waiting"
            },
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/In+progress",
              "name": "In progress",
              "color": "#1f75cb",
              "description": null,
              "category": "in_progress",
              "iconName": "status-running"
            },
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Done",
              "name": "Done",
              "color": "#9400d3",
              "description": "Super custom description",
              "category": "done",
              "iconName": "status-success"
            },
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Won%27t+do",
              "name": "Won't do",
              "color": "#DD2B0E",
              "description": null,
              "category": "canceled",
              "iconName": "status-cancelled"
            },
            {
              "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Duplicate",
              "name": "Duplicate",
              "color": "#DD2B0E",
              "description": null,
              "category": "canceled",
              "iconName": "status-cancelled"
            }
          ],
          "defaultOpenStatus": {
            "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/To+do",
            "name": "To do",
            "color": "#737278",
            "description": null,
            "category": "to_do"
          },
          "defaultClosedStatus": {
            "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Done",
            "name": "Done",
            "color": "#108548",
            "description":null
            "category": "done"
          },
          "defaultDuplicateStatus": {
            "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Templates::Status/Duplicate",
            "name": "Duplicate",
            "color": "#DD2B0E",
            "description": null,
            "category": "canceled"
          }
        }
      ]
    }
  },
  "correlationId": "01K33E507DA2CZT3FXHSD08TBG"
}

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Marc Saleiko

Merge request reports

Loading