Deprecate environment filter and improve errors (#3634)

Co-authored-by: Anbraten <6918444+anbraten@users.noreply.github.com>
This commit is contained in:
qwerty287 2024-04-24 16:07:16 +02:00 committed by GitHub
parent eaceff4483
commit b2cfa37682
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 120 additions and 25 deletions

View file

@ -359,20 +359,6 @@ when:
- platform: [linux/*, windows/amd64] - platform: [linux/*, windows/amd64]
``` ```
<!-- markdownlint-disable no-duplicate-heading -->
#### `environment`
<!-- markdownlint-enable no-duplicate-heading -->
Execute a step for deployment events matching the target deployment environment:
```yaml
when:
- environment: production
- event: deployment
```
#### `matrix` #### `matrix`
Execute a step for a single matrix permutation: 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. Woodpecker gives the ability to configure privileged mode in the YAML. You can use this parameter to launch containers with escalated capabilities.
:::info :::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

View file

@ -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. 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 ## Benefits of using workflows

View file

@ -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. 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 :::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

View file

@ -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 <workflow files>
```
## 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
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

View file

@ -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 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 alternative names for secrets, use `environment` with `from_secret`
- Deprecated slice definition for env vars - Deprecated slice definition for env vars
- Deprecated `environment` filter, use `when.evaluate`
## 2.0.0 ## 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. 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`. - 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. If you used `latest` before to try pre-release features you should switch to `next` after this release.

View file

@ -19,6 +19,12 @@ type DeprecationErrorData struct {
Docs string `json:"docs"` 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 { func GetLinterData(e *types.PipelineError) *LinterErrorData {
if e.Type != types.PipelineErrorTypeLinter { if e.Type != types.PipelineErrorTypeLinter {
return nil return nil

View file

@ -305,7 +305,39 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) {
Data: errors.DeprecationErrorData{ Data: errors.DeprecationErrorData{
File: config.File, File: config.File,
Field: fmt.Sprintf("steps.%s.secrets[%d]", step.Name, i), 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, IsWarning: true,
}) })
@ -351,10 +383,11 @@ func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) {
if field != "" { if field != "" {
err = multierr.Append(err, &errorTypes.PipelineError{ err = multierr.Append(err, &errorTypes.PipelineError{
Type: errorTypes.PipelineErrorTypeBadHabit, Type: errorTypes.PipelineErrorTypeBadHabit,
Message: "Please set an event filter on all when branches", Message: "Please set an event filter for all steps or the whole workflow on all items of the when block",
Data: errors.LinterErrorData{ Data: errors.BadHabitErrorData{
File: config.File, File: config.File,
Field: field, Field: field,
Docs: "https://woodpecker-ci.org/docs/usage/linter#event-filter-for-all-steps",
}, },
IsWarning: true, IsWarning: true,
}) })

View file

@ -189,11 +189,11 @@ func TestBadHabits(t *testing.T) {
}{ }{
{ {
from: "steps: { build: { image: golang } }", 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 } }", 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",
}, },
} }

View file

@ -11,13 +11,16 @@
}" }"
/> />
<span>[{{ error.type }}]</span> <span>[{{ error.type }}]</span>
<span v-if="isLinterError(error) || isDeprecationError(error)" class="whitespace-nowrap"> <span
v-if="isLinterError(error) || isDeprecationError(error) || isBadHabitError(error)"
class="whitespace-nowrap"
>
<span v-if="error.data?.file" class="font-bold">{{ error.data?.file }}: </span> <span v-if="error.data?.file" class="font-bold">{{ error.data?.file }}: </span>
<span>{{ error.data?.field }}</span> <span>{{ error.data?.field }}</span>
</span> </span>
<span v-else /> <span v-else />
<a <a
v-if="isDeprecationError(error)" v-if="isDeprecationError(error) || isBadHabitError(error)"
:href="error.data?.docs" :href="error.data?.docs"
target="_blank" target="_blank"
class="underline col-span-full col-start-2 md:col-span-auto md:col-start-auto" class="underline col-span-full col-start-2 md:col-span-auto md:col-start-auto"
@ -52,6 +55,10 @@ function isDeprecationError(
): error is PipelineError<{ file: string; field: string; docs: string }> { ): error is PipelineError<{ file: string; field: string; docs: string }> {
return error.type === 'deprecation'; return error.type === 'deprecation';
} }
function isBadHabitError(error: PipelineError): error is PipelineError<{ file?: string; field: string; docs: string }> {
return error.type === 'bad_habit';
}
</script> </script>
<style scoped> <style scoped>