Fetch allowed statuses from work item widget definitions

What does this MR do and why?

This MR introduces the ability to fetch allowed statuses from work item widget definitions via the GraphQL API as part of the first iteration of the configurable statuses initiative.

At this stage:

  • Only statuses from the system-defined lifecycle that match the work item type are exposed.
  • The feature is limited to the task work item type.
  • Functionality is only available for Premium and Ultimate users.

Changes

  • Fetch allowed statuses from work item widget definitions via GraphQL API.
  • Limit access to the fetched data by using the work_item_status feature flag and work_item_custom_status licensed feature.
  • Introduce the work_item_status feature flag that will be used for both the backend and frontend by the configurable statuses initiative. The feature flag rollout plan can be found here.
  • Fix the Project#predefined_project_variables flaky spec that caused the pipeline to fail.

Notes

  • The base functionality has been pulled out from the POC MR (Draft: POC Static default status for work items (!178180 - closed)). In this MR, I've ensured that the functionality is only available for Premium and Ultimate users and has good test coverage.
  • Given that the API endpoint is marked as experimental, I believe a CHANGELOG entry is not required.

Scenarios

Fetch allowed custom statuses for a given work item type:

Scenario 1: when the work_item_status FF is enabled and the work item type is supported

(Note that only task is supported)

View query
query namespaceWorkItemTypes($fullPath: ID!, $name: IssueType) {
  workspace: namespace(fullPath: $fullPath) {
    id
    workItemTypes(name: $name) {
      nodes {
        id
        name
        widgetDefinitions {
          ... on WorkItemWidgetDefinitionCustomStatus {
            allowedCustomStatuses {
              nodes {
                id
                name
                iconName
                color
                position
              }
            }
          }
        }
        __typename
      }
      __typename
    }
    __typename
  }
}
{
  "fullPath": "gitlab-org",
  "name": "TASK"
}
View response
{
  "data": {
    "workspace": {
      "id": "gid://gitlab/Group/24",
      "workItemTypes": {
        "nodes": [
          {
            "id": "gid://gitlab/WorkItems::Type/5",
            "name": "Task",
            "widgetDefinitions": [
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {
                "allowedCustomStatuses": {
                  "nodes": [
                    {
                      "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/1",
                      "name": "To do",
                      "iconName": "status-waiting",
                      "color": "#737278",
                      "position": 0
                    },
                    {
                      "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/2",
                      "name": "In progress",
                      "iconName": "status-running",
                      "color": "#1f75cb",
                      "position": 0
                    },
                    {
                      "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/3",
                      "name": "Done",
                      "iconName": "status-success",
                      "color": "#108548",
                      "position": 0
                    },
                    {
                      "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/4",
                      "name": "Won't do",
                      "iconName": "status-cancelled",
                      "color": "#DD2B0E",
                      "position": 0
                    },
                    {
                      "id": "gid://gitlab/WorkItems::Statuses::SystemDefined::Status/5",
                      "name": "Duplicate",
                      "iconName": "status-cancelled",
                      "color": "#DD2B0E",
                      "position": 10
                    }
                  ]
                }
              }
            ],
            "__typename": "WorkItemType"
          }
        ],
        "__typename": "WorkItemTypeConnection"
      },
      "__typename": "Namespace"
    }
  },
  "correlationId": "01JN5C6PTDMMJ4DE854HJBQ4AS"
}

Scenario 2: when the work_item_status FF is enabled and the work item type is not supported

(For example, an issue or epic)

View query
query namespaceWorkItemTypes($fullPath: ID!, $name: IssueType) {
  workspace: namespace(fullPath: $fullPath) {
    id
    workItemTypes(name: $name) {
      nodes {
        id
        name
        widgetDefinitions {
          ... on WorkItemWidgetDefinitionCustomStatus {
            allowedCustomStatuses {
              nodes {
                id
                name
                iconName
                color
                position
              }
            }
          }
        }
        __typename
      }
      __typename
    }
    __typename
  }
}
{
  "fullPath": "gitlab-org",
  "name": "EPIC"
}
View response
{
  "data": {
    "workspace": {
      "id": "gid://gitlab/Group/24",
      "workItemTypes": {
        "nodes": [
          {
            "id": "gid://gitlab/WorkItems::Type/1",
            "name": "Issue",
            "widgetDefinitions": [
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {}
            ],
            "__typename": "WorkItemType"
          }
        ],
        "__typename": "WorkItemTypeConnection"
      },
      "__typename": "Namespace"
    }
  },
  "correlationId": "01JMXM9A811ZDV5XGY27ENJGFJ"
}

Scenario 3: when the work_item_status FF is disabled

View query
query namespaceWorkItemTypes($fullPath: ID!, $name: IssueType) {
  workspace: namespace(fullPath: $fullPath) {
    id
    workItemTypes(name: $name) {
      nodes {
        id
        name
        widgetDefinitions {
          ... on WorkItemWidgetDefinitionCustomStatus {
            allowedCustomStatuses {
              nodes {
                id
                name
                iconName
                color
                position
              }
            }
          }
        }
        __typename
      }
      __typename
    }
    __typename
  }
}
{
  "fullPath": "gitlab-org",
  "name": "TASK"
}
View response
{
  "data": {
    "workspace": {
      "id": "gid://gitlab/Group/24",
      "workItemTypes": {
        "nodes": [
          {
            "id": "gid://gitlab/WorkItems::Type/5",
            "name": "Task",
            "widgetDefinitions": [
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {},
              {
                "allowedCustomStatuses": {
                  "nodes": []
                }
              }
            ],
            "__typename": "WorkItemType"
          }
        ],
        "__typename": "WorkItemTypeConnection"
      },
      "__typename": "Namespace"
    }
  },
  "correlationId": "01JN5AXW1191MR7V6ZSATT64BM"
}

References

Please include cross links to any resources that are relevant to this MR. This will give reviewers and future readers helpful context to give an efficient review of the changes introduced.

MR acceptance checklist

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

Screenshots or screen recordings

backend only changes

How to set up and validate locally

Numbered steps to set up and validate the change are strongly suggested.

  1. Enable the namespace_level_work_items feature flag to have access to work items.
  2. Navigate to the GraphQL Explorer: http://127.0.0.1:3000/-/graphql-explorer.
  3. Use the test queries provided above. Depending on a test scenario enable or disable work_item_status feature flag.
  4. Verify the fetched statuses for work item types like tasks (supported types), issues or epics (unsupported types).
Edited by Agnes Slota

Merge request reports

Loading