summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/pipelines/utils.js
blob: 0a6c326fa3d1f91cf9c88fea30784dcef5d75704 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import * as Sentry from '@sentry/browser';
import { pickBy } from 'lodash';
import { createNodeDict } from './components/parsing_utils';
import { SUPPORTED_FILTER_PARAMETERS } from './constants';

export const validateParams = (params) => {
  return pickBy(params, (val, key) => SUPPORTED_FILTER_PARAMETERS.includes(key) && val);
};

/**
 * This function takes the stages array and transform it
 * into a hash where each key is a job name and the job data
 * is associated to that key.
 * @param {Array} stages
 * @returns {Object} - Hash of jobs
 */
export const createJobsHash = (stages = []) => {
  const nodes = stages.flatMap(({ groups }) => groups);
  return createNodeDict(nodes);
};

/**
 * This function takes the jobs hash generated by
 * `createJobsHash` function and returns an easier
 * structure to work with for needs relationship
 * where the key is the job name and the value is an
 * array of all the needs this job has recursively
 * (includes the needs of the needs)
 * @param {Object} jobs
 * @returns {Object} - Hash of jobs and array of needs
 */
export const generateJobNeedsDict = (jobs = {}) => {
  const arrOfJobNames = Object.keys(jobs);

  return arrOfJobNames.reduce((acc, value) => {
    const recursiveNeeds = (jobName) => {
      if (!jobs[jobName]?.needs) {
        return [];
      }

      return jobs[jobName].needs
        .map((job) => {
          // If we already have the needs of a job in the accumulator,
          // then we use the memoized data instead of the recursive call
          // to save some performance.
          const newNeeds = acc[job] ?? recursiveNeeds(job);

          // In case it's a parallel job (size > 1), the name of the group
          // and the job will be different. This mean we also need to add the group name
          // to the list of `needs` to ensure we can properly reference it.
          const group = jobs[job];
          if (group.size > 1) {
            return [job, group.name, newNeeds];
          }

          return [job, newNeeds];
        })
        .flat(Infinity);
    };

    // To ensure we don't have duplicates job relationship when 2 jobs
    // needed by another both depends on the same jobs, we remove any
    // duplicates from the array.
    const uniqueValues = Array.from(new Set(recursiveNeeds(value)));

    return { ...acc, [value]: uniqueValues };
  }, {});
};

export const reportToSentry = (component, failureType) => {
  Sentry.withScope((scope) => {
    scope.setTag('component', component);
    Sentry.captureException(failureType);
  });
};