Skip to content

Using optional needs causes rendering error in pipeline view

Summary

Using a pipeline with optional needs causes rendering errors in the pipeline view.

Steps to reproduce

  1. Create a pipeline with optional needs like this for example:
stages:
  - stage1
  - stage2

job1:
  stage: stage1
  script:
    - echo "job1"
  rules:
    - if: $CI_COMMIT_REF_NAME != "master"

job2:
  stage: stage2
  needs:
    - job: job1
      optional: true
  script:
    - echo "job2"
  1. Go into the pipeline view of that run and click "Group jobs by Job dependencies"

Example Project

https://gitlab.com/WIStudent/needs-optional-gitlab-ui-issue-demo/-/pipelines/300869103

What is the current bug behavior?

The ui shows an indefinte loading animation. "Group jobs by" buttons also might not be rendered at all if you already switched to "Job dependencies" in a previous pipeline run where the optional needs did not exist or the optional job was included.

What is the expected correct behavior?

Job dependency graph should be rendered.

Relevant logs and/or screenshots

instrument.js:109 TypeError: Cannot read property 'needs' of undefined
    at parsing_utils.js:79
    at Array.map (<anonymous>)
    at t (parsing_utils.js:78)
    at parsing_utils.js:108
    at Array.filter (<anonymous>)
    at h (parsing_utils.js:92)
    at g (parsing_utils.js:115)
    at b (parsing_utils.js:158)
    at a.getPipelineLayers (graph_component_wrapper.vue:190)
    at a.<anonymous> (graph_component_wrapper.vue?c440:1)
    at a.t._render (vue.esm.js:3557)
    at a.r (vue.esm.js:4075)
    at mn.get (vue.esm.js:4488)
    at mn.run (vue.esm.js:4563)
    at pn (vue.esm.js:4319)
    at Array.<anonymous> (vue.esm.js:1989)
    at Jt (vue.esm.js:1915)

image

Different private project where view was switched to "Job dependencies" in a previous pipeline run: image

Output of checks

This bug happens on GitLab.com

Possible fixes

Probably caused by this part: https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/pipelines/components/parsing_utils.js#L79

export const getAllAncestors = (nodes, nodeDict) => {
  const needs = nodes
    .map((node) => {
      return nodeDict[node].needs || '';
    })
    .flat()
    .filter(Boolean);

  if (needs.length) {
    return [...needs, ...getAllAncestors(needs, nodeDict)];
  }

  return [];
};

nodeDict does not contain job1 because of its rule but needs still contains job1 even if optional is set to true. So nodeDict[node] is undefined causing Cannot read property 'needs' of undefined when trying to access nodeDict[node].needs.