Add GraphQL mutation for updating custom lifecycles

What does this MR do and why?

As part of the configurable work item statuses initiative, this MR introduces a GraphQL mutation called lifecycleUpdate for updating custom lifecycles.

The lifecycleUpdate API handles:

  • Adding new statuses to the custom lifecycle
  • Removing existing statuses from the custom lifecycle
  • Updating names of custom statuses
  • Updating default custom statuses
  • Re-ordering custom statuses

Details

  • If a custom lifecycle doesn't exist yet, a new one is created along with its statuses.
  • Required updates—such as renaming default statuses—are applied as needed.
  • Whenever an array of statuses is provided, the indexes of the default custom statuses (open, closed, and duplicated) must also be included. This ensures the lifecycle has the correct default statuses configured.
  • The order of statuses in the array is important, as it determines their position within the lifecycle.
  • If an existing status is missing from the provided array, it will be removed—but only if it's not currently in use (i.e., no work items have it set) and it isn't defined as a default status in the lifecycle.

References

Screenshots or screen recordings

Scenario 1 - Create a custom lifecycle and statuses from the system-defined ones

Screenshot_2025-06-10_at_11.07.47_am

View mutation
mutation UpdateLifecycle($input: LifecycleUpdateInput!) {
  lifecycleUpdate(input: $input) {
    lifecycle {
      id
      name
      statuses {
        id
        name
      }
      defaultOpenStatus {
        id
        name
      }
      defaultClosedStatus {
        id
        name
      }
      defaultDuplicateStatus {
        id
        name
      }
    }
    errors
  }
}
{
  "input": {
    "namespacePath": "gitlab-org",
    "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Lifecycle/1",
    "statuses": [
      {
        "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/1",
        "name": "To do",
        "color": "#737278",
        "description": null,
        "category": "TO_DO"
      },
      {
        "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/3",
        "name": "Done",
        "color": "#108548",
        "description": null,
        "category": "DONE"
      },
      {
        "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/5",
        "name": "Duplicate",
        "color": "#DD2B0E",
        "description": null,
        "category": "CANCELLED"
      }
    ],
      "defaultOpenStatusIndex": 0,
      "defaultClosedStatusIndex": 1,
      "defaultDuplicateStatusIndex": 2
  }
}

Scenario 2 - Add new custom statuses to an existing custom lifecycle, set new statuses as default ones and reorder all the statuses

Screenshot_2025-06-10_at_11.14.03_am

View mutation
mutation UpdateLifecycle($input: LifecycleUpdateInput!) {
  lifecycleUpdate(input: $input) {
    lifecycle {
      id
      name
      statuses {
        id
        name
      }
      defaultOpenStatus {
        id
        name
      }
      defaultClosedStatus {
        id
        name
      }
      defaultDuplicateStatus {
        id
        name
      }
    }
    errors
  }
}
{
  "input": {
    "namespacePath": "gitlab-org",
    "id": "gid://gitlab/WorkItems::Statuses::Custom::Lifecycle/30",
    "statuses": [
      {
          "name": "Ready for development",
          "color": "#737278",
          "description": null,
          "category": "TO_DO"
      },
      {
        "id": "gid://gitlab/WorkItems::Statuses::Custom::Status/127",
        "name": "To do",
        "color": "#737278",
        "description": null,
        "category": "TO_DO"
      },
      {
          "name": "Complete",
          "color": "#108548",
          "description": null,
          "category": "DONE"
      },
      {
        "id": "gid://gitlab/WorkItems::Statuses::Custom::Status/128",
        "name": "Done",
        "color": "#108548",
        "description": null,
        "category": "DONE"
      },
      {
        "id": "gid://gitlab/WorkItems::Statuses::Custom::Status/129",
        "name": "Duplicate",
        "color": "#DD2B0E",
        "description": null,
        "category": "CANCELLED"
      }
    ],
      "defaultOpenStatusIndex": 0,
      "defaultClosedStatusIndex": 2,
      "defaultDuplicateStatusIndex": 4
  }
}

Scenario 3 - Remove custom statuses from an existing custom lifecycle, reorder statuses

Screenshot_2025-06-10_at_11.26.32_am

View mutation

mutation UpdateLifecycle($input: LifecycleUpdateInput!) {
  lifecycleUpdate(input: $input) {
    lifecycle {
      id
      name
      statuses {
        id
        name
      }
      defaultOpenStatus {
        id
        name
      }
      defaultClosedStatus {
        id
        name
      }
      defaultDuplicateStatus {
        id
        name
      }
    }
    errors
  }
}
{
  "input": {
    "namespacePath": "gitlab-org",
    "id": "gid://gitlab/WorkItems::Statuses::Custom::Lifecycle/30",
    "statuses": [
      {
          "id": "gid://gitlab/WorkItems::Statuses::Custom::Status/130",
          "name": "Ready for development",
          "color": "#737278",
          "description": null,
          "category": "TO_DO"
      },
      {
          "id": "gid://gitlab/WorkItems::Statuses::Custom::Status/131",
          "name": "Complete",
          "color": "#108548",
          "description": null,
          "category": "DONE"
      },
      {
        "id": "gid://gitlab/WorkItems::Statuses::Custom::Status/129",
        "name": "Duplicate",
        "color": "#DD2B0E",
        "description": null,
        "category": "CANCELLED"
      }
    ],
      "defaultOpenStatusIndex": 0,
      "defaultClosedStatusIndex": 1,
      "defaultDuplicateStatusIndex": 2
  }
}

How to set up and validate locally

  1. Enable the work_item_status_feature_flag feature flag.
  2. Use the mutations above to test creating a custom lifecycle, adding, updating, removing or reordering custom statuses.

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 Agnes Slota

Merge request reports

Loading