From 5699d22a553021610414c07934b1018adbc40caa Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Thu, 14 Nov 2024 23:23:42 +0200 Subject: [PATCH] Add server configuration option to add default set of labels for workflows that has no labels specified (#4326) --- cmd/server/flags.go | 5 ++++ cmd/server/setup.go | 11 +++++++ .../30-administration/10-server-config.md | 8 +++++ server/config.go | 1 + server/pipeline/items.go | 21 ++++++------- server/pipeline/stepbuilder/stepBuilder.go | 30 +++++++++++-------- 6 files changed, 53 insertions(+), 23 deletions(-) diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 2ad82b9ac89..6ef1f37f0ef 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -173,6 +173,11 @@ var flags = append([]cli.Flag{ Usage: "The maximum time in minutes you can set in the repo settings before a pipeline gets killed", Value: 120, }, + &cli.StringSliceFlag{ + Sources: cli.EnvVars("WOODPECKER_DEFAULT_WORKFLOW_LABELS"), + Name: "default-workflow-labels", + Usage: "The default label filter to set for workflows that has no label filter set. By default workflows will be allowed to run on any agent, if not specified in the workflow.", + }, &cli.DurationFlag{ Sources: cli.EnvVars("WOODPECKER_SESSION_EXPIRES"), Name: "session-expires", diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 608a5ba1471..d682e31cfde 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -188,6 +188,17 @@ func setupEvilGlobals(ctx context.Context, c *cli.Command, s store.Store) (err e server.Config.Pipeline.DefaultTimeout = c.Int("default-pipeline-timeout") server.Config.Pipeline.MaxTimeout = c.Int("max-pipeline-timeout") + _labels := c.StringSlice("default-workflow-labels") + labels := make(map[string]string, len(_labels)) + for _, v := range _labels { + name, value, ok := strings.Cut(v, "=") + if !ok { + return fmt.Errorf("invalid label filter: %s", v) + } + labels[name] = value + } + server.Config.Pipeline.DefaultWorkflowLabels = labels + // backend options for pipeline compiler server.Config.Pipeline.Proxy.No = c.String("backend-no-proxy") server.Config.Pipeline.Proxy.HTTP = c.String("backend-http-proxy") diff --git a/docs/docs/30-administration/10-server-config.md b/docs/docs/30-administration/10-server-config.md index 6b9297f6a0a..2556ef664d5 100644 --- a/docs/docs/30-administration/10-server-config.md +++ b/docs/docs/30-administration/10-server-config.md @@ -357,6 +357,14 @@ The default docker image to be used when cloning the repo. It is also added to the trusted clone plugin list. +### `WOODPECKER_DEFAULT_WORKFLOW_LABELS` + +> By default run workflows on any agent if no label conditions are set in workflow definition. + +You can specify default label/platform conditions that will be used for agent selection for workflows that does not have labels conditions set. + +Example: `platform=linux/amd64,backend=docker` + ### `WOODPECKER_DEFAULT_PIPELINE_TIMEOUT` > 60 (minutes) diff --git a/server/config.go b/server/config.go index 3349e535bae..d9c8bee3018 100644 --- a/server/config.go +++ b/server/config.go @@ -67,6 +67,7 @@ var Config = struct { Pipeline struct { AuthenticatePublicRepos bool DefaultCancelPreviousPipelineEvents []model.WebhookEvent + DefaultWorkflowLabels map[string]string DefaultClonePlugin string TrustedClonePlugins []string Volumes []string diff --git a/server/pipeline/items.go b/server/pipeline/items.go index 70e31f348cc..c34ffa96edb 100644 --- a/server/pipeline/items.go +++ b/server/pipeline/items.go @@ -72,16 +72,17 @@ func parsePipeline(forge forge.Forge, store store.Store, currentPipeline *model. } b := stepbuilder.StepBuilder{ - Repo: repo, - Curr: currentPipeline, - Prev: prev, - Netrc: netrc, - Secs: secs, - Regs: regs, - Envs: envs, - Host: server.Config.Server.Host, - Yamls: yamls, - Forge: forge, + Repo: repo, + Curr: currentPipeline, + Prev: prev, + Netrc: netrc, + Secs: secs, + Regs: regs, + Envs: envs, + Host: server.Config.Server.Host, + Yamls: yamls, + Forge: forge, + DefaultLabels: server.Config.Pipeline.DefaultWorkflowLabels, ProxyOpts: compiler.ProxyOptions{ NoProxy: server.Config.Pipeline.Proxy.No, HTTPProxy: server.Config.Pipeline.Proxy.HTTP, diff --git a/server/pipeline/stepbuilder/stepBuilder.go b/server/pipeline/stepbuilder/stepBuilder.go index 8adc1d71bc7..c628fe83cc8 100644 --- a/server/pipeline/stepbuilder/stepBuilder.go +++ b/server/pipeline/stepbuilder/stepBuilder.go @@ -17,6 +17,7 @@ package stepbuilder import ( "fmt" + "maps" "path/filepath" "strings" @@ -40,17 +41,18 @@ import ( // StepBuilder Takes the hook data and the yaml and returns in internal data model. type StepBuilder struct { - Repo *model.Repo - Curr *model.Pipeline - Prev *model.Pipeline - Netrc *model.Netrc - Secs []*model.Secret - Regs []*model.Registry - Host string - Yamls []*forge_types.FileMeta - Envs map[string]string - Forge metadata.ServerForge - ProxyOpts compiler.ProxyOptions + Repo *model.Repo + Curr *model.Pipeline + Prev *model.Pipeline + Netrc *model.Netrc + Secs []*model.Secret + Regs []*model.Registry + Host string + Yamls []*forge_types.FileMeta + Envs map[string]string + Forge metadata.ServerForge + DefaultLabels map[string]string + ProxyOpts compiler.ProxyOptions } type Item struct { @@ -186,8 +188,10 @@ func (b *StepBuilder) genItemForWorkflow(workflow *model.Workflow, axis matrix.A DependsOn: parsed.DependsOn, RunsOn: parsed.RunsOn, } - if item.Labels == nil { - item.Labels = map[string]string{} + if len(item.Labels) == 0 { + item.Labels = make(map[string]string, len(b.DefaultLabels)) + // Set default labels if no labels are defined in the pipeline + maps.Copy(item.Labels, b.DefaultLabels) } return item, errorsAndWarnings