From 840fca198ed1bf3bf95e09790f0892db5c84c0df Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 27 Dec 2023 11:38:33 +0100 Subject: [PATCH] make backend step dag generation deterministic (#3037) the the generation for backend steps if a dag is used deterministic. this also fix where the test randomly fail like in: - https://ci.woodpecker-ci.org/repos/3780/pipeline/11057/30 - https://ci.woodpecker-ci.org/repos/3780/pipeline/11076/25 --- pipeline/frontend/yaml/compiler/dag.go | 14 +++++++++++++- web/components.d.ts | 6 +----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/pipeline/frontend/yaml/compiler/dag.go b/pipeline/frontend/yaml/compiler/dag.go index 5f2794e06..935100600 100644 --- a/pipeline/frontend/yaml/compiler/dag.go +++ b/pipeline/frontend/yaml/compiler/dag.go @@ -16,6 +16,7 @@ package compiler import ( "fmt" + "sort" backend_types "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types" ) @@ -130,14 +131,25 @@ func convertDAGToStages(steps map[string]*dagCompilerStep, prefix string) ([]*ba Alias: fmt.Sprintf("%s_stage_%d", prefix, len(stages)), } + var stepsToAdd []*dagCompilerStep for name, step := range steps { if allDependenciesSatisfied(step, addedSteps) { - stage.Steps = append(stage.Steps, step.step) + stepsToAdd = append(stepsToAdd, step) addedNodesThisLevel[name] = struct{}{} delete(steps, name) } } + // as steps are from a map that has no deterministic order, + // we sort the steps by original config position to make the order similar between pipelines + sort.Slice(stepsToAdd, func(i, j int) bool { + return stepsToAdd[i].position < stepsToAdd[j].position + }) + + for i := range stepsToAdd { + stage.Steps = append(stage.Steps, stepsToAdd[i].step) + } + for name := range addedNodesThisLevel { addedSteps[name] = struct{}{} } diff --git a/web/components.d.ts b/web/components.d.ts index 189d50f42..a93810057 100644 --- a/web/components.d.ts +++ b/web/components.d.ts @@ -30,16 +30,11 @@ declare module 'vue' { GeneralTab: typeof import('./src/components/repo/settings/GeneralTab.vue')['default'] Header: typeof import('./src/components/layout/scaffold/Header.vue')['default'] IBiCheckCircleFill: typeof import('~icons/bi/check-circle-fill')['default'] - IBiCircle: typeof import('~icons/bi/circle')['default'] IBiExclamationTriangle: typeof import('~icons/bi/exclamation-triangle')['default'] IBiExclamationTriangleFill: typeof import('~icons/bi/exclamation-triangle-fill')['default'] - IBiPlayCircleFill: typeof import('~icons/bi/play-circle-fill')['default'] IBiSlashCircleFill: typeof import('~icons/bi/slash-circle-fill')['default'] - IBiStopCircleFill: typeof import('~icons/bi/stop-circle-fill')['default'] - IBiXCircleFill: typeof import('~icons/bi/x-circle-fill')['default'] IBxBxPowerOff: typeof import('~icons/bx/bx-power-off')['default'] ICarbonCloseOutline: typeof import('~icons/carbon/close-outline')['default'] - ICarbonInProgress: typeof import('~icons/carbon/in-progress')['default'] IClarityDeployLine: typeof import('~icons/clarity/deploy-line')['default'] IClaritySettingsSolid: typeof import('~icons/clarity/settings-solid')['default'] Icon: typeof import('./src/components/atomic/Icon.vue')['default'] @@ -73,6 +68,7 @@ declare module 'vue' { IMdiRadioboxIndeterminateVariant: typeof import('~icons/mdi/radiobox-indeterminate-variant')['default'] IMdiSourceBranch: typeof import('~icons/mdi/source-branch')['default'] IMdisourceCommit: typeof import('~icons/mdi/source-commit')['default'] + IMdiSourceMerge: typeof import('~icons/mdi/source-merge')['default'] IMdiSourcePull: typeof import('~icons/mdi/source-pull')['default'] IMdiStop: typeof import('~icons/mdi/stop')['default'] IMdiSync: typeof import('~icons/mdi/sync')['default']