Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
3b5f1d2e
Commit
3b5f1d2e
authored
May 19, 2021
by
Frédéric Caplette
Committed by
Olena Horal-Koretska
May 19, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix pipeline throwing error when needs is undefined
parent
59ae7774
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
78 additions
and
21 deletions
+78
-21
app/assets/javascripts/pipelines/components/parsing_utils.js
app/assets/javascripts/pipelines/components/parsing_utils.js
+19
-15
app/assets/javascripts/pipelines/utils.js
app/assets/javascripts/pipelines/utils.js
+10
-4
changelogs/unreleased/329895-fix-needs-is-undefined-in-pipeline-graph.yml
...eased/329895-fix-needs-is-undefined-in-pipeline-graph.yml
+5
-0
spec/frontend/pipelines/components/dag/mock_data.js
spec/frontend/pipelines/components/dag/mock_data.js
+14
-0
spec/frontend/pipelines/parsing_utils_spec.js
spec/frontend/pipelines/parsing_utils_spec.js
+8
-2
spec/frontend/pipelines/pipeline_graph/utils_spec.js
spec/frontend/pipelines/pipeline_graph/utils_spec.js
+22
-0
No files found.
app/assets/javascripts/pipelines/components/parsing_utils.js
View file @
3b5f1d2e
...
@@ -55,21 +55,25 @@ export const createNodeDict = (nodes) => {
...
@@ -55,21 +55,25 @@ export const createNodeDict = (nodes) => {
export
const
makeLinksFromNodes
=
(
nodes
,
nodeDict
)
=>
{
export
const
makeLinksFromNodes
=
(
nodes
,
nodeDict
)
=>
{
const
constantLinkValue
=
10
;
// all links are the same weight
const
constantLinkValue
=
10
;
// all links are the same weight
return
nodes
return
nodes
.
map
((
group
)
=>
{
.
map
(({
jobs
,
name
:
groupName
})
=>
return
group
.
jobs
.
map
((
job
)
=>
{
jobs
.
map
(({
needs
=
[]
})
=>
if
(
!
job
.
needs
)
{
needs
.
reduce
((
acc
,
needed
)
=>
{
return
[];
// 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
return
job
.
needs
.
map
((
needed
)
=>
{
// create link for it.
return
{
if
(
nodeDict
[
needed
]?.
name
)
{
source
:
nodeDict
[
needed
]?.
name
,
acc
.
push
({
target
:
group
.
name
,
source
:
nodeDict
[
needed
].
name
,
value
:
constantLinkValue
,
target
:
groupName
,
};
value
:
constantLinkValue
,
});
});
});
}
})
return
acc
;
},
[]),
),
)
.
flat
(
2
);
.
flat
(
2
);
};
};
...
...
app/assets/javascripts/pipelines/utils.js
View file @
3b5f1d2e
...
@@ -39,7 +39,13 @@ export const generateJobNeedsDict = (jobs = {}) => {
...
@@ -39,7 +39,13 @@ export const generateJobNeedsDict = (jobs = {}) => {
}
}
return
jobs
[
jobName
].
needs
return
jobs
[
jobName
].
needs
.
map
((
job
)
=>
{
.
reduce
((
needsAcc
,
job
)
=>
{
// It's possible that a needs refer to an optional job
// that is not defined in which case we don't add that entry
if
(
!
jobs
[
job
])
{
return
needsAcc
;
}
// If we already have the needs of a job in the accumulator,
// If we already have the needs of a job in the accumulator,
// then we use the memoized data instead of the recursive call
// then we use the memoized data instead of the recursive call
// to save some performance.
// to save some performance.
...
@@ -50,11 +56,11 @@ export const generateJobNeedsDict = (jobs = {}) => {
...
@@ -50,11 +56,11 @@ export const generateJobNeedsDict = (jobs = {}) => {
// to the list of `needs` to ensure we can properly reference it.
// to the list of `needs` to ensure we can properly reference it.
const
group
=
jobs
[
job
];
const
group
=
jobs
[
job
];
if
(
group
.
size
>
1
)
{
if
(
group
.
size
>
1
)
{
return
[
job
,
group
.
name
,
newNeeds
];
return
[
...
needsAcc
,
job
,
group
.
name
,
newNeeds
];
}
}
return
[
job
,
newNeeds
];
return
[
...
needsAcc
,
job
,
newNeeds
];
})
}
,
[]
)
.
flat
(
Infinity
);
.
flat
(
Infinity
);
};
};
...
...
changelogs/unreleased/329895-fix-needs-is-undefined-in-pipeline-graph.yml
0 → 100644
View file @
3b5f1d2e
---
title
:
Fix pipeline graph undefined needs error
merge_request
:
62027
author
:
type
:
fixed
spec/frontend/pipelines/components/dag/mock_data.js
View file @
3b5f1d2e
...
@@ -398,6 +398,8 @@ export const multiNote = {
...
@@ -398,6 +398,8 @@ export const multiNote = {
},
},
};
};
export
const
missingJob
=
'
missing_job
'
;
/*
/*
It is important that the base include parallel jobs
It is important that the base include parallel jobs
as well as non-parallel jobs with spaces in the name to prevent
as well as non-parallel jobs with spaces in the name to prevent
...
@@ -657,4 +659,16 @@ export const mockParsedGraphQLNodes = [
...
@@ -657,4 +659,16 @@ export const mockParsedGraphQLNodes = [
],
],
__typename
:
'
CiGroup
'
,
__typename
:
'
CiGroup
'
,
},
},
{
category
:
'
production
'
,
name
:
'
production_e
'
,
size
:
1
,
jobs
:
[
{
name
:
'
production_e
'
,
needs
:
[
missingJob
],
},
],
__typename
:
'
CiGroup
'
,
},
];
];
spec/frontend/pipelines/parsing_utils_spec.js
View file @
3b5f1d2e
...
@@ -10,7 +10,7 @@ import {
...
@@ -10,7 +10,7 @@ import {
getMaxNodes
,
getMaxNodes
,
}
from
'
~/pipelines/components/parsing_utils
'
;
}
from
'
~/pipelines/components/parsing_utils
'
;
import
{
mockParsedGraphQLNodes
}
from
'
./components/dag/mock_data
'
;
import
{
mockParsedGraphQLNodes
,
missingJob
}
from
'
./components/dag/mock_data
'
;
import
{
generateResponse
,
mockPipelineResponse
}
from
'
./graph/mock_data
'
;
import
{
generateResponse
,
mockPipelineResponse
}
from
'
./graph/mock_data
'
;
describe
(
'
DAG visualization parsing utilities
'
,
()
=>
{
describe
(
'
DAG visualization parsing utilities
'
,
()
=>
{
...
@@ -24,6 +24,12 @@ describe('DAG visualization parsing utilities', () => {
...
@@ -24,6 +24,12 @@ describe('DAG visualization parsing utilities', () => {
expect
(
unfilteredLinks
[
0
]).
toHaveProperty
(
'
target
'
,
'
test_a
'
);
expect
(
unfilteredLinks
[
0
]).
toHaveProperty
(
'
target
'
,
'
test_a
'
);
expect
(
unfilteredLinks
[
0
]).
toHaveProperty
(
'
value
'
,
10
);
expect
(
unfilteredLinks
[
0
]).
toHaveProperty
(
'
value
'
,
10
);
});
});
it
(
'
does not generate a link for non-existing jobs
'
,
()
=>
{
const
sources
=
unfilteredLinks
.
map
(({
source
})
=>
source
);
expect
(
sources
.
includes
(
missingJob
)).
toBe
(
false
);
});
});
});
describe
(
'
filterByAncestors
'
,
()
=>
{
describe
(
'
filterByAncestors
'
,
()
=>
{
...
@@ -88,7 +94,7 @@ describe('DAG visualization parsing utilities', () => {
...
@@ -88,7 +94,7 @@ describe('DAG visualization parsing utilities', () => {
These lengths are determined by the mock data.
These lengths are determined by the mock data.
If the data changes, the numbers may also change.
If the data changes, the numbers may also change.
*/
*/
expect
(
parsed
.
nodes
).
toHaveLength
(
21
);
expect
(
parsed
.
nodes
).
toHaveLength
(
mockParsedGraphQLNodes
.
length
);
expect
(
cleanedNodes
).
toHaveLength
(
12
);
expect
(
cleanedNodes
).
toHaveLength
(
12
);
});
});
});
});
...
...
spec/frontend/pipelines/pipeline_graph/utils_spec.js
View file @
3b5f1d2e
...
@@ -111,6 +111,28 @@ describe('utils functions', () => {
...
@@ -111,6 +111,28 @@ describe('utils functions', () => {
});
});
});
});
it
(
'
removes needs which are not in the data
'
,
()
=>
{
const
inexistantJobName
=
'
job5
'
;
const
jobsWithNeeds
=
{
[
jobName1
]:
job1
,
[
jobName2
]:
job2
,
[
jobName3
]:
job3
,
[
jobName4
]:
{
name
:
jobName4
,
script
:
'
echo deploy
'
,
stage
:
'
deploy
'
,
needs
:
[
inexistantJobName
],
},
};
expect
(
generateJobNeedsDict
(
jobsWithNeeds
)).
toEqual
({
[
jobName1
]:
[],
[
jobName2
]:
[],
[
jobName3
]:
[
jobName1
,
jobName2
],
[
jobName4
]:
[],
});
});
it
(
'
handles parallel jobs by adding the group name as a need
'
,
()
=>
{
it
(
'
handles parallel jobs by adding the group name as a need
'
,
()
=>
{
const
size
=
3
;
const
size
=
3
;
const
jobOptimize1
=
'
optimize_1
'
;
const
jobOptimize1
=
'
optimize_1
'
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment