mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-03 18:24:29 +00:00
fix(actions): group reusable-workflow matrix legs in the workflow graph (#38475)
Fixes the UI issue reported in #38466: matrix jobs that invoke a reusable workflow (`build-call (linux)`, `build-call (windows)`, …) were rendered as separate nodes in the run's workflow graph, while an equivalent regular matrix (`build (linux)`, `build (windows)`, …) collapsed neatly into a single matrix node. Before: three loose `build-call (...)` boxes next to one grouped `build` box. After: both matrices collapse into a single node.
This commit is contained in:
@@ -157,16 +157,18 @@ test('reusable callers with identical dependency signature are kept as separate
|
||||
expect(graph.nodes.find((n) => n.id === 'job:3')?.name).toBe('cross-repo caller');
|
||||
});
|
||||
|
||||
test('reusable caller with matrix-pattern name does not get absorbed into a sibling matrix node', () => {
|
||||
test('matrix legs that call a reusable workflow are folded into a single matrix node', () => {
|
||||
const jobs: ActionsJob[] = [
|
||||
{id: 1, link: '', jobId: 'deploy_dev', name: 'deploy (dev)', status: 'success', canRerun: false, isReusableCaller: false, parentJobID: 0, duration: '1s'},
|
||||
{id: 2, link: '', jobId: 'deploy_qa', name: 'deploy (qa)', status: 'success', canRerun: false, isReusableCaller: false, parentJobID: 0, duration: '1s'},
|
||||
{id: 3, link: '', jobId: 'deploy_staging', name: 'deploy (staging)', status: 'running', canRerun: false, isReusableCaller: true, parentJobID: 0, duration: '2s', callUses: './.gitea/workflows/deploy.yml'},
|
||||
{id: 1, link: '', jobId: 'prepare', name: 'prepare', status: 'success', canRerun: false, isReusableCaller: false, parentJobID: 0, duration: '30s'},
|
||||
{id: 2, link: '', jobId: 'build_call_linux', name: 'build-call (linux)', status: 'success', canRerun: false, isReusableCaller: true, parentJobID: 0, duration: '1m', needs: ['prepare'], callUses: './.gitea/workflows/build.yml'},
|
||||
{id: 3, link: '', jobId: 'build_call_windows', name: 'build-call (windows)', status: 'success', canRerun: false, isReusableCaller: true, parentJobID: 0, duration: '2m', needs: ['prepare'], callUses: './.gitea/workflows/build.yml'},
|
||||
{id: 4, link: '', jobId: 'build_call_macos', name: 'build-call (macos)', status: 'success', canRerun: false, isReusableCaller: true, parentJobID: 0, duration: '90s', needs: ['prepare'], callUses: './.gitea/workflows/build.yml'},
|
||||
];
|
||||
const graph = createWorkflowGraphModel(jobs);
|
||||
expect(graph.nodes.find((n) => n.id === 'job:3')?.name).toBe('deploy (staging)');
|
||||
const matrixNode = graph.nodes.find((n) => n.type === 'matrix');
|
||||
expect(matrixNode?.jobs.map((j) => j.id).sort()).toEqual([1, 2]);
|
||||
const matrixNodes = graph.nodes.filter((n) => n.type === 'matrix');
|
||||
expect(matrixNodes).toHaveLength(1);
|
||||
expect(matrixNodes[0].matrixKey).toBe('build-call');
|
||||
expect(matrixNodes[0].jobs.map((j) => j.id).sort()).toEqual([2, 3, 4]);
|
||||
});
|
||||
|
||||
test('directed highlight state covers ancestors and descendants of the hovered node', () => {
|
||||
|
||||
@@ -264,9 +264,8 @@ function buildVisualGraph(
|
||||
|
||||
const matrixJobsByKey = new Map<string, ActionsJob[]>();
|
||||
for (const job of jobs) {
|
||||
// Reusable callers are distinct workflow files — never fold them into a matrix bucket
|
||||
// even if their display name happens to look like "name (variant)".
|
||||
if (job.isReusableCaller) continue;
|
||||
// Matrix legs that call a reusable workflow are still one logical job (a single `uses:`
|
||||
// expanded over the matrix), so fold them into a matrix node like any other matrix job.
|
||||
const matrixKey = matrixKeyFromJobName(job.name);
|
||||
if (!matrixKey) continue;
|
||||
if (!matrixJobsByKey.has(matrixKey)) matrixJobsByKey.set(matrixKey, []);
|
||||
@@ -322,10 +321,8 @@ function buildVisualGraph(
|
||||
const visualIdByJobId = new Map<number, string>();
|
||||
for (const job of jobs) {
|
||||
const matrixKey = matrixKeyFromJobName(job.name);
|
||||
// Symmetric with the matrix-bucket loop above: a reusable caller whose display name
|
||||
// happens to look like "name (variant)" must never be folded into the matrix node, or it
|
||||
// would silently vanish (its visualId would point at a matrix node it isn't part of).
|
||||
if (matrixKey && !job.isReusableCaller && (matrixJobsByKey.get(matrixKey)?.length ?? 0) > 1) {
|
||||
// Symmetric with the matrix-bucket loop above (callers included).
|
||||
if (matrixKey && (matrixJobsByKey.get(matrixKey)?.length ?? 0) > 1) {
|
||||
visualIdByJobId.set(job.id, `matrix:${matrixKey}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user