Commit d0306a75 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch 'fix-job-dependencies-view' into 'master'

Update job dependencies view

See merge request gitlab-org/gitlab!77036
parents c962655c 80eacad2
import { memoize } from 'lodash';
import { createNodeDict } from '../utils';
import { EXPLICIT_NEEDS_PROPERTY, NEEDS_PROPERTY } from '../constants';
import { createSankey } from './dag/drawing_utils';
/*
......@@ -15,12 +16,14 @@ const deduplicate = (item, itemIndex, arr) => {
return foundIdx === itemIndex;
};
export const makeLinksFromNodes = (nodes, nodeDict) => {
export const makeLinksFromNodes = (nodes, nodeDict, { needsKey = NEEDS_PROPERTY } = {}) => {
const constantLinkValue = 10; // all links are the same weight
return nodes
.map(({ jobs, name: groupName }) =>
jobs.map(({ needs = [] }) =>
needs.reduce((acc, needed) => {
jobs.map((job) => {
const needs = job[needsKey] || [];
return needs.reduce((acc, needed) => {
// It's possible that we have an optional job, which
// is being needed by another job. In that scenario,
// the needed job doesn't exist, so we don't want to
......@@ -34,8 +37,8 @@ export const makeLinksFromNodes = (nodes, nodeDict) => {
}
return acc;
}, []),
),
}, []);
}),
)
.flat(2);
};
......@@ -76,9 +79,9 @@ export const filterByAncestors = (links, nodeDict) =>
return !allAncestors.includes(source);
});
export const parseData = (nodes) => {
const nodeDict = createNodeDict(nodes);
const allLinks = makeLinksFromNodes(nodes, nodeDict);
export const parseData = (nodes, { needsKey = NEEDS_PROPERTY } = {}) => {
const nodeDict = createNodeDict(nodes, { needsKey });
const allLinks = makeLinksFromNodes(nodes, nodeDict, { needsKey });
const filteredLinks = allLinks.filter(deduplicate);
const links = filterByAncestors(filteredLinks, nodeDict);
......@@ -123,7 +126,8 @@ export const removeOrphanNodes = (sankeyfiedNodes) => {
export const listByLayers = ({ stages }) => {
const arrayOfJobs = stages.flatMap(({ groups }) => groups);
const parsedData = parseData(arrayOfJobs);
const dataWithLayers = createSankey()(parsedData);
const explicitParsedData = parseData(arrayOfJobs, { needsKey: EXPLICIT_NEEDS_PROPERTY });
const dataWithLayers = createSankey()(explicitParsedData);
const pipelineLayers = dataWithLayers.nodes.reduce((acc, { layer, name }) => {
/* sort groups by layer */
......
import { reportToSentry } from '../utils';
import { EXPLICIT_NEEDS_PROPERTY, NEEDS_PROPERTY } from '../constants';
const unwrapGroups = (stages) => {
return stages.map((stage, idx) => {
......@@ -27,12 +28,16 @@ const unwrapNodesWithName = (jobArray, prop, field = 'name') => {
}
return jobArray.map((job) => {
if (job[prop]) {
return { ...job, [prop]: job[prop].nodes.map((item) => item[field] || '') };
}
return job;
});
};
const unwrapJobWithNeeds = (denodedJobArray) => {
return unwrapNodesWithName(denodedJobArray, 'needs');
const explicitNeedsUnwrapped = unwrapNodesWithName(denodedJobArray, EXPLICIT_NEEDS_PROPERTY);
return unwrapNodesWithName(explicitNeedsUnwrapped, NEEDS_PROPERTY);
};
const unwrapStagesWithNeedsAndLookup = (denodedStages) => {
......
......@@ -7,6 +7,8 @@ export const ANY_TRIGGER_AUTHOR = 'Any';
export const SUPPORTED_FILTER_PARAMETERS = ['username', 'ref', 'status', 'source'];
export const FILTER_TAG_IDENTIFIER = 'tag';
export const SCHEDULE_ORIGIN = 'schedule';
export const NEEDS_PROPERTY = 'needs';
export const EXPLICIT_NEEDS_PROPERTY = 'previousStageJobsOrNeeds';
export const TestStatus = {
FAILED: 'failed',
......
{"__schema":{"types":[{"kind":"UNION","name":"JobNeedUnion","possibleTypes":[{"name":"CiBuildNeed"},{"name":"CiJob"}]}]}}
\ No newline at end of file
import VueApollo from 'vue-apollo';
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import createDefaultClient from '~/lib/graphql';
import introspectionQueryResultData from './graphql/fragmentTypes.json';
export const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData,
});
export const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(
{},
{
cacheConfig: {
fragmentMatcher,
},
useGet: true,
},
),
......
import * as Sentry from '@sentry/browser';
import { pickBy } from 'lodash';
import { SUPPORTED_FILTER_PARAMETERS } from './constants';
import { SUPPORTED_FILTER_PARAMETERS, NEEDS_PROPERTY } from './constants';
/*
The following functions are the main engine in transforming the data as
......@@ -35,11 +35,11 @@ import { SUPPORTED_FILTER_PARAMETERS } from './constants';
10 -> value (constant)
*/
export const createNodeDict = (nodes) => {
export const createNodeDict = (nodes, { needsKey = NEEDS_PROPERTY } = {}) => {
return nodes.reduce((acc, node) => {
const newNode = {
...node,
needs: node.jobs.map((job) => job.needs || []).flat(),
needs: node.jobs.map((job) => job[needsKey] || []).flat(),
};
if (node.size > 1) {
......
fragment CiNeeds on JobNeedUnion {
...CiBuildNeedFields
...CiJobNeedFields
}
fragment CiBuildNeedFields on CiBuildNeed {
id
name
}
fragment CiJobNeedFields on CiJob {
id
name
}
fragment LinkedPipelineData on Pipeline {
__typename
id
......@@ -91,6 +106,12 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) {
name
}
}
previousStageJobsOrNeeds {
__typename
nodes {
...CiNeeds
}
}
status: detailedStatus {
__typename
id
......
......@@ -13,6 +13,7 @@ Array [
"id": "6",
"name": "build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
"needs": Array [],
"previousStageJobsOrNeeds": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -53,6 +54,7 @@ Array [
"id": "11",
"name": "build_b",
"needs": Array [],
"previousStageJobsOrNeeds": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -93,6 +95,7 @@ Array [
"id": "16",
"name": "build_c",
"needs": Array [],
"previousStageJobsOrNeeds": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -133,6 +136,7 @@ Array [
"id": "21",
"name": "build_d 1/3",
"needs": Array [],
"previousStageJobsOrNeeds": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -157,6 +161,7 @@ Array [
"id": "24",
"name": "build_d 2/3",
"needs": Array [],
"previousStageJobsOrNeeds": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -181,6 +186,7 @@ Array [
"id": "27",
"name": "build_d 3/3",
"needs": Array [],
"previousStageJobsOrNeeds": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -221,6 +227,7 @@ Array [
"id": "59",
"name": "test_c",
"needs": Array [],
"previousStageJobsOrNeeds": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -267,6 +274,11 @@ Array [
"build_b",
"build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
],
"previousStageJobsOrNeeds": Array [
"build_c",
"build_b",
"build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -313,6 +325,13 @@ Array [
"build_b",
"build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
],
"previousStageJobsOrNeeds": Array [
"build_d 3/3",
"build_d 2/3",
"build_d 1/3",
"build_b",
"build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -343,6 +362,13 @@ Array [
"build_b",
"build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
],
"previousStageJobsOrNeeds": Array [
"build_d 3/3",
"build_d 2/3",
"build_d 1/3",
"build_b",
"build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......@@ -385,6 +411,9 @@ Array [
"needs": Array [
"build_b",
],
"previousStageJobsOrNeeds": Array [
"build_b",
],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
......
......@@ -73,6 +73,10 @@ export const mockPipelineResponse = {
__typename: 'CiBuildNeedConnection',
nodes: [],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [],
},
},
],
},
......@@ -118,6 +122,10 @@ export const mockPipelineResponse = {
__typename: 'CiBuildNeedConnection',
nodes: [],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [],
},
},
],
},
......@@ -163,6 +171,10 @@ export const mockPipelineResponse = {
__typename: 'CiBuildNeedConnection',
nodes: [],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [],
},
},
],
},
......@@ -208,6 +220,10 @@ export const mockPipelineResponse = {
__typename: 'CiBuildNeedConnection',
nodes: [],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [],
},
},
{
__typename: 'CiJob',
......@@ -235,6 +251,10 @@ export const mockPipelineResponse = {
__typename: 'CiBuildNeedConnection',
nodes: [],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [],
},
},
{
__typename: 'CiJob',
......@@ -262,6 +282,10 @@ export const mockPipelineResponse = {
__typename: 'CiBuildNeedConnection',
nodes: [],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [],
},
},
],
},
......@@ -339,6 +363,27 @@ export const mockPipelineResponse = {
},
],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [
{
__typename: 'CiBuildNeed',
id: '37',
name: 'build_c',
},
{
__typename: 'CiBuildNeed',
id: '38',
name: 'build_b',
},
{
__typename: 'CiBuildNeed',
id: '39',
name:
'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl',
},
],
},
},
],
},
......@@ -411,6 +456,37 @@ export const mockPipelineResponse = {
},
],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [
{
__typename: 'CiBuildNeed',
id: '45',
name: 'build_d 3/3',
},
{
__typename: 'CiBuildNeed',
id: '46',
name: 'build_d 2/3',
},
{
__typename: 'CiBuildNeed',
id: '47',
name: 'build_d 1/3',
},
{
__typename: 'CiBuildNeed',
id: '48',
name: 'build_b',
},
{
__typename: 'CiBuildNeed',
id: '49',
name:
'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl',
},
],
},
},
{
__typename: 'CiJob',
......@@ -465,6 +541,37 @@ export const mockPipelineResponse = {
},
],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [
{
__typename: 'CiBuildNeed',
id: '52',
name: 'build_d 3/3',
},
{
__typename: 'CiBuildNeed',
id: '53',
name: 'build_d 2/3',
},
{
__typename: 'CiBuildNeed',
id: '54',
name: 'build_d 1/3',
},
{
__typename: 'CiBuildNeed',
id: '55',
name: 'build_b',
},
{
__typename: 'CiBuildNeed',
id: '56',
name:
'build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl',
},
],
},
},
],
},
......@@ -503,6 +610,10 @@ export const mockPipelineResponse = {
__typename: 'CiBuildNeedConnection',
nodes: [],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [],
},
},
],
},
......@@ -547,6 +658,16 @@ export const mockPipelineResponse = {
},
],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [
{
__typename: 'CiBuildNeed',
id: '65',
name: 'build_b',
},
],
},
},
],
},
......@@ -720,6 +841,10 @@ export const wrappedPipelineReturn = {
__typename: 'CiBuildNeedConnection',
nodes: [],
},
previousStageJobsOrNeeds: {
__typename: 'CiJobConnection',
nodes: [],
},
status: {
__typename: 'DetailedStatus',
id: '84',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment