From f0e518a5a230258f687e95ad67982dfe2afc242c Mon Sep 17 00:00:00 2001 From: Sergio Fenoll Date: Tue, 15 Nov 2022 19:47:27 +0100 Subject: [PATCH] Add option to ignore failures on steps (#1219) closes #1181 closes #834 Adds `ignore_failure` to pipeline steps. When it's set to true, if the step fails the following steps continue to execute as if no failure had occurred. --- failure enums idea: * fail (default) = if other steps run in parallel, wait for them and then let workflow fail * cancel = if other steps run in parallel, kill them * ignore = we mark the step as failed but it wont have any impact --- docs/docs/20-usage/20-pipeline-syntax.md | 14 ++++++++++++++ pipeline/backend/types/step.go | 1 + pipeline/frontend/metadata.go | 7 +++++++ pipeline/frontend/yaml/compiler/convert.go | 7 +++++++ pipeline/frontend/yaml/container.go | 1 + pipeline/pipeline.go | 7 ++++++- pipeline/schema/schema.json | 6 ++++++ 7 files changed, 42 insertions(+), 1 deletion(-) diff --git a/docs/docs/20-usage/20-pipeline-syntax.md b/docs/docs/20-usage/20-pipeline-syntax.md index 55a2ddb37..eaa365a4a 100644 --- a/docs/docs/20-usage/20-pipeline-syntax.md +++ b/docs/docs/20-usage/20-pipeline-syntax.md @@ -206,6 +206,20 @@ Woodpecker provides the ability to store named parameters external to the YAML c For more details check the [secrets docs](./40-secrets.md). +### `failure` + +Some of the pipeline steps may be allowed to fail without causing the whole pipeline to report a failure (e.g., a step executing a linting check). To enable this, add `failure: ignore` to your pipeline step. If Woodpecker encounters an error while executing the step, it will report it as failed but still execute the next steps of the pipeline, if any, without affecting the status of the pipeline. + +```diff + pipeline: + backend: + image: golang + commands: + - go build + - go test ++ failure: ignore +``` + ### `when` - Conditional Execution Woodpecker supports defining a list of conditions for a pipeline step by using a `when` block. If at least one of the conditions in the `when` block evaluate to true the step is executed, otherwise it is skipped. A condition can be a check like: diff --git a/pipeline/backend/types/step.go b/pipeline/backend/types/step.go index b5ba55bd8..419d2d36b 100644 --- a/pipeline/backend/types/step.go +++ b/pipeline/backend/types/step.go @@ -28,6 +28,7 @@ type Step struct { CPUSet string `json:"cpu_set,omitempty"` OnFailure bool `json:"on_failure,omitempty"` OnSuccess bool `json:"on_success,omitempty"` + Failure string `json:"failure,omitempty"` AuthConfig Auth `json:"auth_config,omitempty"` NetworkMode string `json:"network_mode,omitempty"` IpcMode string `json:"ipc_mode,omitempty"` diff --git a/pipeline/frontend/metadata.go b/pipeline/frontend/metadata.go index e37e1e68a..197ccf1af 100644 --- a/pipeline/frontend/metadata.go +++ b/pipeline/frontend/metadata.go @@ -32,6 +32,13 @@ const ( EventManual = "manual" ) +// Different ways to handle failure states +const ( + FailureIgnore = "ignore" + FailureFail = "fail" + // FailureCancel = "cancel" // Not implemented yet +) + type ( // Metadata defines runtime m. Metadata struct { diff --git a/pipeline/frontend/yaml/compiler/convert.go b/pipeline/frontend/yaml/compiler/convert.go index f91412ca5..5ff01b99e 100644 --- a/pipeline/frontend/yaml/compiler/convert.go +++ b/pipeline/frontend/yaml/compiler/convert.go @@ -9,6 +9,7 @@ import ( "github.com/rs/zerolog/log" backend "github.com/woodpecker-ci/woodpecker/pipeline/backend/types" + "github.com/woodpecker-ci/woodpecker/pipeline/frontend" "github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml" "github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/compiler/settings" ) @@ -139,6 +140,11 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section // at least one constraint must include the status failure. onFailure := container.When.IncludesStatus("failure") + failure := container.Failure + if container.Failure == "" { + failure = frontend.FailureFail + } + return &backend.Step{ Name: name, Alias: container.Name, @@ -167,6 +173,7 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section AuthConfig: authConfig, OnSuccess: onSuccess, OnFailure: onFailure, + Failure: failure, NetworkMode: networkMode, IpcMode: ipcMode, } diff --git a/pipeline/frontend/yaml/container.go b/pipeline/frontend/yaml/container.go index 7815545c7..f6957a18c 100644 --- a/pipeline/frontend/yaml/container.go +++ b/pipeline/frontend/yaml/container.go @@ -41,6 +41,7 @@ type ( ExtraHosts []string `yaml:"extra_hosts,omitempty"` Group string `yaml:"group,omitempty"` Image string `yaml:"image,omitempty"` + Failure string `yaml:"failure,omitempty"` Isolation string `yaml:"isolation,omitempty"` Labels types.SliceorMap `yaml:"labels,omitempty"` MemLimit types.MemStringorInt `yaml:"mem_limit,omitempty"` diff --git a/pipeline/pipeline.go b/pipeline/pipeline.go index e37dd8d6f..572ea84fb 100644 --- a/pipeline/pipeline.go +++ b/pipeline/pipeline.go @@ -11,6 +11,7 @@ import ( "golang.org/x/sync/errgroup" backend "github.com/woodpecker-ci/woodpecker/pipeline/backend/types" + "github.com/woodpecker-ci/woodpecker/pipeline/frontend" "github.com/woodpecker-ci/woodpecker/pipeline/multipart" ) @@ -193,7 +194,11 @@ func (r *Runtime) execAll(steps []*backend.Step) <-chan error { } // Return the error after tracing it. - return r.traceStep(processState, err, step) + err = r.traceStep(processState, err, step) + if err != nil && step.Failure == frontend.FailureIgnore { + return nil + } + return err }) } diff --git a/pipeline/schema/schema.json b/pipeline/schema/schema.json index 947803561..59bb57176 100644 --- a/pipeline/schema/schema.json +++ b/pipeline/schema/schema.json @@ -237,6 +237,12 @@ "detach": { "description": "Detach a step to run in background until pipeline finishes. Read more: https://woodpecker-ci.org/docs/usage/services#detachment", "type": "boolean" + }, + "failure": { + "description": "How to handle the failure of this step. Read more: https://woodpecker-ci.org/docs/usage/pipeline-syntax#failure", + "type": "string", + "enum": ["fail", "ignore"], + "default": "fail" } } },