diff --git a/docs/docs/20-usage/20-workflow-syntax.md b/docs/docs/20-usage/20-workflow-syntax.md index 8effc3973..a3806b9c7 100644 --- a/docs/docs/20-usage/20-workflow-syntax.md +++ b/docs/docs/20-usage/20-workflow-syntax.md @@ -359,20 +359,6 @@ when: - platform: [linux/*, windows/amd64] ``` - - -#### `environment` - - - -Execute a step for deployment events matching the target deployment environment: - -```yaml -when: - - environment: production - - event: deployment -``` - #### `matrix` Execute a step for a single matrix permutation: @@ -758,7 +744,7 @@ Workflows that should run even on failure should set the `runs_on` tag. See [her Woodpecker gives the ability to configure privileged mode in the YAML. You can use this parameter to launch containers with escalated capabilities. :::info -Privileged mode is only available to trusted repositories and for security reasons should only be used in private environments. See [project settings](./71-project-settings.md#trusted) to enable trusted mode. +Privileged mode is only available to trusted repositories and for security reasons should only be used in private environments. See [project settings](./75-project-settings.md#trusted) to enable trusted mode. ::: ```diff diff --git a/docs/docs/20-usage/25-workflows.md b/docs/docs/20-usage/25-workflows.md index 88ed78f81..5adc39f85 100644 --- a/docs/docs/20-usage/25-workflows.md +++ b/docs/docs/20-usage/25-workflows.md @@ -6,7 +6,7 @@ In case there is a single configuration in `.woodpecker.yaml` Woodpecker will cr By placing the configurations in a folder which is by default named `.woodpecker/` Woodpecker will create a pipeline with multiple workflows each named by the file they are defined in. Only `.yml` and `.yaml` files will be used and files in any subfolders like `.woodpecker/sub-folder/test.yaml` will be ignored. -You can also set some custom path like `.my-ci/pipelines/` instead of `.woodpecker/` in the [project settings](./71-project-settings.md). +You can also set some custom path like `.my-ci/pipelines/` instead of `.woodpecker/` in the [project settings](./75-project-settings.md). ## Benefits of using workflows diff --git a/docs/docs/20-usage/70-volumes.md b/docs/docs/20-usage/70-volumes.md index 3397e879c..6897053fb 100644 --- a/docs/docs/20-usage/70-volumes.md +++ b/docs/docs/20-usage/70-volumes.md @@ -3,7 +3,7 @@ Woodpecker gives the ability to define Docker volumes in the YAML. You can use this parameter to mount files or folders on the host machine into your containers. :::note -Volumes are only available to trusted repositories and for security reasons should only be used in private environments. See [project settings](./71-project-settings.md#trusted) to enable trusted mode. +Volumes are only available to trusted repositories and for security reasons should only be used in private environments. See [project settings](./75-project-settings.md#trusted) to enable trusted mode. ::: ```diff diff --git a/docs/docs/20-usage/72-linter.md b/docs/docs/20-usage/72-linter.md new file mode 100644 index 000000000..4fae3d643 --- /dev/null +++ b/docs/docs/20-usage/72-linter.md @@ -0,0 +1,62 @@ +# Linter + +Woodpecker automatically lints your workflow files for errors, deprecations and bad habits. Errors and warnings are shown in the UI for any pipelines. + +![errors and warnings in UI](./linter-warnings-errors.png) + +## Running the linter from CLI + +You can run the linter also manually from the CLI: + +```shell +woodpecker-cli lint +``` + +## Bad habit warnings + +Woodpecker warns you if your configuration contains some bad habits. + +### Event filter for all steps + +All your items in `when` blocks should have an `event` filter, so no step runs on all events. This is recommended because if new events are added, your steps probably shouldn't run on those as well. + +Examples of an **incorrect** config for this rule: + +```yaml +when: + - branch: main + - event: tag +``` + +This will trigger the warning because the first item (`branch: main`) does not filter with an event. + +```yaml +steps: + - name: test + when: + branch: main + + - name: deploy + when: + event: tag +``` + +Examples of a **correct** config for this rule: + +```yaml +when: + - branch: main + event: push + - event: tag +``` + +```yaml +steps: + - name: test + when: + event: [tag, push] + + - name: deploy + when: + - event: tag +``` diff --git a/docs/docs/20-usage/71-project-settings.md b/docs/docs/20-usage/75-project-settings.md similarity index 100% rename from docs/docs/20-usage/71-project-settings.md rename to docs/docs/20-usage/75-project-settings.md diff --git a/docs/docs/20-usage/linter-warnings-errors.png b/docs/docs/20-usage/linter-warnings-errors.png new file mode 100644 index 000000000..663e49704 Binary files /dev/null and b/docs/docs/20-usage/linter-warnings-errors.png differ diff --git a/docs/docs/91-migrations.md b/docs/docs/91-migrations.md index 9b6fa8854..6ad8f7b13 100644 --- a/docs/docs/91-migrations.md +++ b/docs/docs/91-migrations.md @@ -11,6 +11,7 @@ Some versions need some changes to the server configuration or the pipeline conf - Deprecated uppercasing all secret env vars, instead, the value of the `secrets` property is used. [Read more](./20-usage/40-secrets.md#use-secrets-in-commands) - Deprecated alternative names for secrets, use `environment` with `from_secret` - Deprecated slice definition for env vars +- Deprecated `environment` filter, use `when.evaluate` ## 2.0.0 @@ -66,7 +67,7 @@ Some versions need some changes to the server configuration or the pipeline conf Only projects created after updating will have an empty value by default. Existing projects will stick to the current pipeline path which is `.drone.yml` in most cases. - Read more about it at the [Project Settings](./20-usage/71-project-settings.md#pipeline-path) + Read more about it at the [Project Settings](./20-usage/75-project-settings.md#pipeline-path) - From version `0.15.0` ongoing there will be three types of docker images: `latest`, `next` and `x.x.x` with an alpine variant for each type like `latest-alpine`. If you used `latest` before to try pre-release features you should switch to `next` after this release. diff --git a/pipeline/errors/error.go b/pipeline/errors/error.go index f8bba4c67..729839483 100644 --- a/pipeline/errors/error.go +++ b/pipeline/errors/error.go @@ -19,6 +19,12 @@ type DeprecationErrorData struct { Docs string `json:"docs"` } +type BadHabitErrorData struct { + File string `json:"file"` + Field string `json:"field"` + Docs string `json:"docs"` +} + func GetLinterData(e *types.PipelineError) *LinterErrorData { if e.Type != types.PipelineErrorTypeLinter { return nil diff --git a/pipeline/frontend/yaml/linter/linter.go b/pipeline/frontend/yaml/linter/linter.go index 646091972..32bad6aee 100644 --- a/pipeline/frontend/yaml/linter/linter.go +++ b/pipeline/frontend/yaml/linter/linter.go @@ -305,7 +305,39 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { Data: errors.DeprecationErrorData{ File: config.File, Field: fmt.Sprintf("steps.%s.secrets[%d]", step.Name, i), - Docs: "https://woodpecker-ci.org/docs/usage/workflow-syntax#event", + Docs: "https://woodpecker-ci.org/docs/usage/secrets#use-secrets-in-settings-and-environment", + }, + IsWarning: true, + }) + } + } + } + + for i, c := range parsed.When.Constraints { + if !c.Environment.IsEmpty() { + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeDeprecation, + Message: "environment filters are deprecated, use evaluate with CI_PIPELINE_DEPLOY_TARGET", + Data: errors.DeprecationErrorData{ + File: config.File, + Field: fmt.Sprintf("when[%d].environment", i), + Docs: "https://woodpecker-ci.org/docs/usage/workflow-syntax#evaluate", + }, + IsWarning: true, + }) + } + } + + for _, step := range parsed.Steps.ContainerList { + for i, c := range step.When.Constraints { + if !c.Environment.IsEmpty() { + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeDeprecation, + Message: "environment filters are deprecated, use evaluate with CI_PIPELINE_DEPLOY_TARGET", + Data: errors.DeprecationErrorData{ + File: config.File, + Field: fmt.Sprintf("steps.%s.when[%d].environment", step.Name, i), + Docs: "https://woodpecker-ci.org/docs/usage/workflow-syntax#evaluate", }, IsWarning: true, }) @@ -351,10 +383,11 @@ func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) { if field != "" { err = multierr.Append(err, &errorTypes.PipelineError{ Type: errorTypes.PipelineErrorTypeBadHabit, - Message: "Please set an event filter on all when branches", - Data: errors.LinterErrorData{ + Message: "Please set an event filter for all steps or the whole workflow on all items of the when block", + Data: errors.BadHabitErrorData{ File: config.File, Field: field, + Docs: "https://woodpecker-ci.org/docs/usage/linter#event-filter-for-all-steps", }, IsWarning: true, }) diff --git a/pipeline/frontend/yaml/linter/linter_test.go b/pipeline/frontend/yaml/linter/linter_test.go index 0c49e44ad..84afb44d8 100644 --- a/pipeline/frontend/yaml/linter/linter_test.go +++ b/pipeline/frontend/yaml/linter/linter_test.go @@ -189,11 +189,11 @@ func TestBadHabits(t *testing.T) { }{ { from: "steps: { build: { image: golang } }", - want: "Please set an event filter on all when branches", + want: "Please set an event filter for all steps or the whole workflow on all items of the when block", }, { from: "when: [{branch: xyz}, {event: push}]\nsteps: { build: { image: golang } }", - want: "Please set an event filter on all when branches", + want: "Please set an event filter for all steps or the whole workflow on all items of the when block", }, } diff --git a/web/src/views/repo/pipeline/PipelineErrors.vue b/web/src/views/repo/pipeline/PipelineErrors.vue index 349e52812..4455ec14a 100644 --- a/web/src/views/repo/pipeline/PipelineErrors.vue +++ b/web/src/views/repo/pipeline/PipelineErrors.vue @@ -11,13 +11,16 @@ }" /> [{{ error.type }}] - + {{ error.data?.file }}: {{ error.data?.field }} { return error.type === 'deprecation'; } + +function isBadHabitError(error: PipelineError): error is PipelineError<{ file?: string; field: string; docs: string }> { + return error.type === 'bad_habit'; +}