From aafd217cceb6af6b8497def4a4ae87e4f9e388b9 Mon Sep 17 00:00:00 2001 From: qwerty287 <80460567+qwerty287@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:58:51 +0200 Subject: [PATCH] Remove old pipeline options (#4016) --- docs/docs/91-migrations.md | 12 +- pipeline/frontend/yaml/compiler/compiler.go | 1 - .../frontend/yaml/compiler/compiler_test.go | 84 +++++++------- pipeline/frontend/yaml/compiler/convert.go | 11 +- pipeline/frontend/yaml/compiler/dag.go | 20 +--- pipeline/frontend/yaml/compiler/dag_test.go | 3 - .../frontend/yaml/constraint/constraint.go | 30 +++-- pipeline/frontend/yaml/linter/linter.go | 102 +---------------- pipeline/frontend/yaml/linter/linter_test.go | 2 +- .../linter/schema/.woodpecker/test-step.yaml | 18 +-- .../linter/schema/.woodpecker/test-when.yaml | 9 -- .../frontend/yaml/linter/schema/schema.json | 104 +----------------- pipeline/frontend/yaml/parse_test.go | 5 +- pipeline/frontend/yaml/types/base/map.go | 51 --------- pipeline/frontend/yaml/types/base/map_test.go | 58 ---------- pipeline/frontend/yaml/types/container.go | 9 +- .../frontend/yaml/types/container_test.go | 34 ++---- pipeline/frontend/yaml/types/secret.go | 48 -------- pipeline/frontend/yaml/types/secret_test.go | 73 ------------ 19 files changed, 100 insertions(+), 574 deletions(-) delete mode 100644 pipeline/frontend/yaml/types/base/map.go delete mode 100644 pipeline/frontend/yaml/types/base/map_test.go delete mode 100644 pipeline/frontend/yaml/types/secret.go delete mode 100644 pipeline/frontend/yaml/types/secret_test.go diff --git a/docs/docs/91-migrations.md b/docs/docs/91-migrations.md index 88d4c426d..db82b83b8 100644 --- a/docs/docs/91-migrations.md +++ b/docs/docs/91-migrations.md @@ -6,15 +6,15 @@ Some versions need some changes to the server configuration or the pipeline conf - Removed `WOODPECKER_DEV_OAUTH_HOST` and `WOODPECKER_DEV_GITEA_OAUTH_URL` use `WOODPECKER_EXPERT_FORGE_OAUTH_HOST` - Compatibility mode of deprecated `pipeline:`, `platform:` and `branches:` pipeline config options are now removed and pipeline will now fail if still in use. -- Deprecated `steps.[name].group` in favor of `steps.[name].depends_on` (see [workflow syntax](./20-usage/20-workflow-syntax.md#depends_on) to learn how to set dependencies) +- Removed `steps.[name].group` in favor of `steps.[name].depends_on` (see [workflow syntax](./20-usage/20-workflow-syntax.md#depends_on) to learn how to set dependencies) - Removed `WOODPECKER_ROOT_PATH` and `WOODPECKER_ROOT_URL` config variables. Use `WOODPECKER_HOST` with a path instead - Pipelines without a config file will now be skipped instead of failing - Removed implicitly defined `regcred` image pull secret name. Set it explicitly via `WOODPECKER_BACKEND_K8S_PULL_SECRET_NAMES` -- Deprecated `includes` and `excludes` support from **event** filter -- 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` +- Removed `includes` and `excludes` support from **event** filter +- Removed 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) +- Removed alternative names for secrets, use `environment` with `from_secret` +- Removed slice definition for env vars +- Removed `environment` filter, use `when.evaluate` - Removed `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST` - Migrated to rfc9421 for webhook signatures - Renamed `start_time`, `end_time`, `created_at`, `started_at`, `finished_at` and `reviewed_at` JSON fields to `started`, `finished`, `created`, `started`, `finished`, `reviewed` diff --git a/pipeline/frontend/yaml/compiler/compiler.go b/pipeline/frontend/yaml/compiler/compiler.go index 9525a3a12..9b9c2d7d4 100644 --- a/pipeline/frontend/yaml/compiler/compiler.go +++ b/pipeline/frontend/yaml/compiler/compiler.go @@ -275,7 +275,6 @@ func (c *Compiler) Compile(conf *yaml_types.Workflow) (*backend_types.Config, er step: step, position: pos, name: container.Name, - group: container.Group, dependsOn: container.DependsOn, }) } diff --git a/pipeline/frontend/yaml/compiler/compiler_test.go b/pipeline/frontend/yaml/compiler/compiler_test.go index d391b5506..66bb1a19b 100644 --- a/pipeline/frontend/yaml/compiler/compiler_test.go +++ b/pipeline/frontend/yaml/compiler/compiler_test.go @@ -150,63 +150,65 @@ func TestCompilerCompile(t *testing.T) { }, }, { - name: "workflow with three steps and one group", + name: "workflow with three steps", fronConf: &yaml_types.Workflow{Steps: yaml_types.ContainerList{ContainerList: []*yaml_types.Container{{ Name: "echo env", Image: "bash", Commands: []string{"env"}, }, { Name: "parallel echo 1", - Group: "parallel", Image: "bash", Commands: []string{"echo 1"}, }, { Name: "parallel echo 2", - Group: "parallel", Image: "bash", Commands: []string{"echo 2"}, }}}}, backConf: &backend_types.Config{ Networks: defaultNetworks, Volumes: defaultVolumes, - Stages: []*backend_types.Stage{defaultCloneStage, { - Steps: []*backend_types.Step{{ - Name: "echo env", - Type: backend_types.StepTypeCommands, - Image: "bash", - Commands: []string{"env"}, - OnSuccess: true, - Failure: "fail", - Volumes: []string{defaultVolumes[0].Name + ":/test"}, - WorkingDir: "/test/src/github.com/octocat/hello-world", - Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"echo env"}}}, - ExtraHosts: []backend_types.HostAlias{}, - }}, - }, { - Steps: []*backend_types.Step{{ - Name: "parallel echo 1", - Type: backend_types.StepTypeCommands, - Image: "bash", - Commands: []string{"echo 1"}, - OnSuccess: true, - Failure: "fail", - Volumes: []string{defaultVolumes[0].Name + ":/test"}, - WorkingDir: "/test/src/github.com/octocat/hello-world", - Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 1"}}}, - ExtraHosts: []backend_types.HostAlias{}, + Stages: []*backend_types.Stage{ + defaultCloneStage, { + Steps: []*backend_types.Step{{ + Name: "echo env", + Type: backend_types.StepTypeCommands, + Image: "bash", + Commands: []string{"env"}, + OnSuccess: true, + Failure: "fail", + Volumes: []string{defaultVolumes[0].Name + ":/test"}, + WorkingDir: "/test/src/github.com/octocat/hello-world", + Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"echo env"}}}, + ExtraHosts: []backend_types.HostAlias{}, + }}, }, { - Name: "parallel echo 2", - Type: backend_types.StepTypeCommands, - Image: "bash", - Commands: []string{"echo 2"}, - OnSuccess: true, - Failure: "fail", - Volumes: []string{defaultVolumes[0].Name + ":/test"}, - WorkingDir: "/test/src/github.com/octocat/hello-world", - Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 2"}}}, - ExtraHosts: []backend_types.HostAlias{}, - }}, - }}, + Steps: []*backend_types.Step{{ + Name: "parallel echo 1", + Type: backend_types.StepTypeCommands, + Image: "bash", + Commands: []string{"echo 1"}, + OnSuccess: true, + Failure: "fail", + Volumes: []string{defaultVolumes[0].Name + ":/test"}, + WorkingDir: "/test/src/github.com/octocat/hello-world", + Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 1"}}}, + ExtraHosts: []backend_types.HostAlias{}, + }}, + }, { + Steps: []*backend_types.Step{{ + Name: "parallel echo 2", + Type: backend_types.StepTypeCommands, + Image: "bash", + Commands: []string{"echo 2"}, + OnSuccess: true, + Failure: "fail", + Volumes: []string{defaultVolumes[0].Name + ":/test"}, + WorkingDir: "/test/src/github.com/octocat/hello-world", + Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 2"}}}, + ExtraHosts: []backend_types.HostAlias{}, + }}, + }, + }, }, }, { @@ -274,7 +276,7 @@ func TestCompilerCompile(t *testing.T) { Name: "step", Image: "bash", Commands: []string{"env"}, - Secrets: yaml_types.Secrets{Secrets: []*yaml_types.Secret{{Source: "missing", Target: "missing"}}}, + Secrets: []string{"missing"}, }}}}, backConf: nil, expectedErr: "secret \"missing\" not found", diff --git a/pipeline/frontend/yaml/compiler/convert.go b/pipeline/frontend/yaml/compiler/convert.go index df4c3ec8d..d01175368 100644 --- a/pipeline/frontend/yaml/compiler/convert.go +++ b/pipeline/frontend/yaml/compiler/convert.go @@ -125,20 +125,17 @@ func (c *Compiler) createProcess(container *yaml_types.Container, stepType backe return nil, err } - for _, requested := range container.Secrets.Secrets { - secretValue, err := getSecretValue(requested.Source) + for _, requested := range container.Secrets { + secretValue, err := getSecretValue(requested) if err != nil { return nil, err } - toUpperTarget := strings.ToUpper(requested.Target) - if !environmentAllowed(toUpperTarget, stepType) { + if !environmentAllowed(requested, stepType) { continue } - environment[requested.Target] = secretValue - // TODO: deprecated, remove in 3.x - environment[toUpperTarget] = secretValue + environment[requested] = secretValue } if utils.MatchImage(container.Image, c.escalated...) && container.IsPlugin() { diff --git a/pipeline/frontend/yaml/compiler/dag.go b/pipeline/frontend/yaml/compiler/dag.go index 461807259..deb673e4c 100644 --- a/pipeline/frontend/yaml/compiler/dag.go +++ b/pipeline/frontend/yaml/compiler/dag.go @@ -24,7 +24,6 @@ type dagCompilerStep struct { step *backend_types.Step position int name string - group string dependsOn []string } @@ -51,25 +50,16 @@ func (c dagCompiler) compile() ([]*backend_types.Stage, error) { if c.isDAG() { return c.compileByDependsOn() } - return c.compileByGroup() + return c.compileSequence() } -func (c dagCompiler) compileByGroup() ([]*backend_types.Stage, error) { +func (c dagCompiler) compileSequence() ([]*backend_types.Stage, error) { stages := make([]*backend_types.Stage, 0, len(c.steps)) - var currentStage *backend_types.Stage - var currentGroup string for _, s := range c.steps { - // create a new stage if current step is in a new group compared to last one - if currentStage == nil || currentGroup != s.group || s.group == "" { - currentGroup = s.group - - currentStage = new(backend_types.Stage) - stages = append(stages, currentStage) - } - - // add step to current stage - currentStage.Steps = append(currentStage.Steps, s.step) + stages = append(stages, &backend_types.Stage{ + Steps: []*backend_types.Step{s.step}, + }) } return stages, nil diff --git a/pipeline/frontend/yaml/compiler/dag_test.go b/pipeline/frontend/yaml/compiler/dag_test.go index 51dd3b5a6..620b67776 100644 --- a/pipeline/frontend/yaml/compiler/dag_test.go +++ b/pipeline/frontend/yaml/compiler/dag_test.go @@ -85,7 +85,6 @@ func TestConvertDAGToStages(t *testing.T) { "echo env": { position: 0, name: "echo env", - group: "", step: &backend_types.Step{ UUID: "01HJDPEW6R7J0JBE3F1T7Q0TYX", Type: "commands", @@ -96,7 +95,6 @@ func TestConvertDAGToStages(t *testing.T) { "echo 1": { position: 1, name: "echo 1", - group: "", dependsOn: []string{"echo env", "echo 2"}, step: &backend_types.Step{ UUID: "01HJDPF770QGRZER8RF79XVS4M", @@ -108,7 +106,6 @@ func TestConvertDAGToStages(t *testing.T) { "echo 2": { position: 2, name: "echo 2", - group: "", step: &backend_types.Step{ UUID: "01HJDPFF5RMEYZW0YTGR1Y1ZR0", Type: "commands", diff --git a/pipeline/frontend/yaml/constraint/constraint.go b/pipeline/frontend/yaml/constraint/constraint.go index 205f21fd3..28c29f2ab 100644 --- a/pipeline/frontend/yaml/constraint/constraint.go +++ b/pipeline/frontend/yaml/constraint/constraint.go @@ -18,6 +18,7 @@ import ( "fmt" "maps" "path" + "slices" "strings" "github.com/bmatcuk/doublestar/v4" @@ -37,20 +38,18 @@ type ( } Constraint struct { - Ref List - Repo List - Instance List - Platform List - Environment List - Branch List - Cron List - Status List - Matrix Map - Local yamlBaseTypes.BoolTrue - Path Path - Evaluate string `yaml:"evaluate,omitempty"` - // TODO: change to StringOrSlice in 3.x - Event List + Ref List + Repo List + Instance List + Platform List + Branch List + Cron List + Status List + Matrix Map + Local yamlBaseTypes.BoolTrue + Path Path + Evaluate string `yaml:"evaluate,omitempty"` + Event yamlBaseTypes.StringOrSlice } // List defines a runtime constraint for exclude & include string slices. @@ -164,8 +163,7 @@ func (c *Constraint) Match(m metadata.Metadata, global bool, env map[string]stri } match = match && c.Platform.Match(m.Sys.Platform) && - c.Environment.Match(m.Curr.DeployTo) && - c.Event.Match(m.Curr.Event) && + (len(c.Event) == 0 || slices.Contains(c.Event, m.Curr.Event)) && c.Repo.Match(path.Join(m.Repo.Owner, m.Repo.Name)) && c.Ref.Match(m.Curr.Commit.Ref) && c.Instance.Match(m.Sys.Host) diff --git a/pipeline/frontend/yaml/linter/linter.go b/pipeline/frontend/yaml/linter/linter.go index b64d7bf4c..6b4a51fc7 100644 --- a/pipeline/frontend/yaml/linter/linter.go +++ b/pipeline/frontend/yaml/linter/linter.go @@ -145,7 +145,7 @@ func (l *Linter) lintSettings(config *WorkflowConfig, c *types.Container, field if len(c.Environment) != 0 { return newLinterError("Should not configure both environment and settings", config.File, fmt.Sprintf("%s.%s", field, c.Name), true) } - if len(c.Secrets.Secrets) != 0 { + if len(c.Secrets) != 0 { return newLinterError("Should not configure both secrets and settings", config.File, fmt.Sprintf("%s.%s", field, c.Name), true) } return nil @@ -218,102 +218,6 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { return err } - for _, step := range parsed.Steps.ContainerList { - if step.Group != "" { - err = multierr.Append(err, &errorTypes.PipelineError{ - Type: errorTypes.PipelineErrorTypeDeprecation, - Message: "Please use depends_on instead of deprecated 'group' setting", - Data: errors.DeprecationErrorData{ - File: config.File, - Field: "steps." + step.Name + ".group", - Docs: "https://woodpecker-ci.org/docs/next/usage/workflow-syntax#depends_on", - }, - IsWarning: true, - }) - } - } - - for i, c := range parsed.When.Constraints { - if len(c.Event.Exclude) != 0 { - err = multierr.Append(err, &errorTypes.PipelineError{ - Type: errorTypes.PipelineErrorTypeDeprecation, - Message: "Please only use allow lists for events", - Data: errors.DeprecationErrorData{ - File: config.File, - Field: fmt.Sprintf("when[%d].event", i), - Docs: "https://woodpecker-ci.org/docs/usage/workflow-syntax#event-1", - }, - IsWarning: true, - }) - } - } - - for _, step := range parsed.Steps.ContainerList { - for i, c := range step.When.Constraints { - if len(c.Event.Exclude) != 0 { - err = multierr.Append(err, &errorTypes.PipelineError{ - Type: errorTypes.PipelineErrorTypeDeprecation, - Message: "Please only use allow lists for events", - Data: errors.DeprecationErrorData{ - File: config.File, - Field: fmt.Sprintf("steps.%s.when[%d].event", step.Name, i), - Docs: "https://woodpecker-ci.org/docs/usage/workflow-syntax#event", - }, - IsWarning: true, - }) - } - } - } - - for _, step := range parsed.Steps.ContainerList { - for i, c := range step.Secrets.Secrets { - if c.Source != c.Target { - err = multierr.Append(err, &errorTypes.PipelineError{ - Type: errorTypes.PipelineErrorTypeDeprecation, - Message: "Secrets alternative names are deprecated, use environment with from_secret", - Data: errors.DeprecationErrorData{ - File: config.File, - Field: fmt.Sprintf("steps.%s.secrets[%d]", step.Name, i), - 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, - }) - } - } - } - return err } @@ -326,7 +230,7 @@ func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) { rootEventFilters := len(parsed.When.Constraints) > 0 for _, c := range parsed.When.Constraints { - if len(c.Event.Include) == 0 { + if len(c.Event) == 0 { rootEventFilters = false break } @@ -340,7 +244,7 @@ func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) { } else { stepEventIndex := -1 for i, c := range step.When.Constraints { - if len(c.Event.Include) == 0 { + if len(c.Event) == 0 { stepEventIndex = i break } diff --git a/pipeline/frontend/yaml/linter/linter_test.go b/pipeline/frontend/yaml/linter/linter_test.go index 4c9000d24..19bc5ae43 100644 --- a/pipeline/frontend/yaml/linter/linter_test.go +++ b/pipeline/frontend/yaml/linter/linter_test.go @@ -162,7 +162,7 @@ func TestLintErrors(t *testing.T) { want: "Cannot configure both entrypoint and settings", }, { - from: "steps: { build: { image: golang, settings: { test: 'true' }, environment: [ 'TEST=true' ] } }", + from: "steps: { build: { image: golang, settings: { test: 'true' }, environment: { 'TEST': 'true' } } }", want: "Should not configure both environment and settings", }, { diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yaml index 9f60fcf44..da6ada4f2 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yaml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yaml @@ -38,15 +38,6 @@ steps: commands: - go test - environment-array: - image: golang - environment: - - CGO=0 - - GOOS=linux - - GOARCH=amd64 - commands: - - go test - secrets: image: docker commands: @@ -54,14 +45,7 @@ steps: - echo $DOCKER_PASSWORD secrets: - docker_username - - source: docker_prod_password - target: docker_password - - group: - group: test - image: golang - commands: - - go test + - docker_prod_password detached: image: redis diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yaml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yaml index 1e163e854..a8235b65e 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yaml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yaml @@ -37,14 +37,6 @@ steps: - deployment - release - when-event-exclude-pull_request_closed: - image: alpine - commands: - - echo "test" - when: - event: - exclude: pull_request_closed - when-ref: image: alpine commands: @@ -78,7 +70,6 @@ steps: commands: - echo "test" when: - environment: production event: deployment when-matrix: diff --git a/pipeline/frontend/yaml/linter/schema/schema.json b/pipeline/frontend/yaml/linter/schema/schema.json index ffe9fac74..026dda685 100644 --- a/pipeline/frontend/yaml/linter/schema/schema.json +++ b/pipeline/frontend/yaml/linter/schema/schema.json @@ -163,18 +163,7 @@ "event": { "description": "Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#event", "default": [], - "oneOf": [ - { - "type": "array", - "minLength": 1, - "items": { - "$ref": "#/definitions/event_enum" - } - }, - { - "$ref": "#/definitions/event_enum" - } - ] + "$ref": "#/definitions/event_constraint_list" }, "ref": { "description": "Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#ref", @@ -188,10 +177,6 @@ "description": "Execute a step only on a specific platform. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#platform", "$ref": "#/definitions/constraint_list" }, - "environment": { - "description": "Execute a step only for a specific environment. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#environment", - "$ref": "#/definitions/constraint_list" - }, "instance": { "description": "Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#instance", "$ref": "#/definitions/constraint_list" @@ -291,10 +276,6 @@ "volumes": { "$ref": "#/definitions/step_volumes" }, - "group": { - "description": "deprecated, use depends_on", - "type": "string" - }, "depends_on": { "description": "Execute a step after another step has finished.", "oneOf": [ @@ -377,10 +358,6 @@ "volumes": { "$ref": "#/definitions/step_volumes" }, - "group": { - "description": "deprecated, use depends_on", - "type": "string" - }, "depends_on": { "description": "Execute a step after another step has finished.", "oneOf": [ @@ -457,10 +434,6 @@ "volumes": { "$ref": "#/definitions/step_volumes" }, - "group": { - "description": "deprecated, use depends_on", - "type": "string" - }, "depends_on": { "description": "Execute a step after another step has finished.", "oneOf": [ @@ -551,10 +524,6 @@ "description": "Execute a step only on a specific platform. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#platform", "$ref": "#/definitions/constraint_list" }, - "environment": { - "description": "Execute a step only for a specific environment. Read more: https://woodpecker-ci.org/docs/usage/workflow-syntax#environment", - "$ref": "#/definitions/constraint_list" - }, "matrix": { "description": "Read more: https://woodpecker-ci.org/docs/usage/matrix-workflows", "type": "object", @@ -624,40 +593,6 @@ "items": { "$ref": "#/definitions/event_enum" } - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "include": { - "oneOf": [ - { - "$ref": "#/definitions/event_enum" - }, - { - "type": "array", - "minLength": 1, - "items": { - "$ref": "#/definitions/event_enum" - } - } - ] - }, - "exclude": { - "oneOf": [ - { - "$ref": "#/definitions/event_enum" - }, - { - "type": "array", - "minLength": 1, - "items": { - "$ref": "#/definitions/event_enum" - } - } - ] - } - } } ] }, @@ -739,43 +674,16 @@ }, "step_environment": { "description": "Pass environment variables to a pipeline step. Read more: https://woodpecker-ci.org/docs/usage/environment", - "oneOf": [ - { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1 - }, - { - "type": "object", - "additionalProperties": { - "type": ["boolean", "string", "number", "array", "object"] - } - } - ] + "type": "object", + "additionalProperties": { + "type": ["boolean", "string", "number", "array", "object"] + } }, "step_secrets": { "description": "Pass secrets to a pipeline step at runtime. Read more: https://woodpecker-ci.org/docs/usage/secrets", "type": "array", "items": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "required": ["source", "target"], - "properties": { - "source": { - "type": "string" - }, - "target": { - "type": "string" - } - } - } - ] + "type": "string" }, "minLength": 1 }, diff --git a/pipeline/frontend/yaml/parse_test.go b/pipeline/frontend/yaml/parse_test.go index fdd91f767..3dec23cd1 100644 --- a/pipeline/frontend/yaml/parse_test.go +++ b/pipeline/frontend/yaml/parse_test.go @@ -15,6 +15,7 @@ package yaml import ( + "slices" "testing" "github.com/franela/goblin" @@ -35,7 +36,7 @@ func TestParse(t *testing.T) { g.Fail(err) } - g.Assert(out.When.Constraints[0].Event.Match("tester")).Equal(true) + g.Assert(slices.Contains(out.When.Constraints[0].Event, "tester")).Equal(true) g.Assert(out.Workspace.Base).Equal("/go") g.Assert(out.Workspace.Path).Equal("src/github.com/octocat/hello-world") @@ -85,7 +86,7 @@ func TestParse(t *testing.T) { g.Assert(len(out.Steps.ContainerList[0].When.Constraints)).Equal(0) g.Assert(out.Steps.ContainerList[1].Name).Equal("notify_success") g.Assert(out.Steps.ContainerList[1].Image).Equal("plugins/slack") - g.Assert(out.Steps.ContainerList[1].When.Constraints[0].Event.Include).Equal([]string{"success"}) + g.Assert(out.Steps.ContainerList[1].When.Constraints[0].Event).Equal(yaml_base_types.StringOrSlice{"success"}) }) matchConfig, err := ParseString(sampleYaml) diff --git a/pipeline/frontend/yaml/types/base/map.go b/pipeline/frontend/yaml/types/base/map.go deleted file mode 100644 index 2cdd35b8b..000000000 --- a/pipeline/frontend/yaml/types/base/map.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2023 Woodpecker Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package base - -import ( - "errors" - "fmt" - "strings" -) - -// SliceOrMap represents a map of strings, string slice are converted into a map. -type SliceOrMap map[string]any - -// UnmarshalYAML implements the Unmarshaler interface. -func (s *SliceOrMap) UnmarshalYAML(unmarshal func(any) error) error { - var sliceType []any - if err := unmarshal(&sliceType); err == nil { - parts := map[string]any{} - for _, s := range sliceType { - if str, ok := s.(string); ok { - str := strings.TrimSpace(str) - key, val, _ := strings.Cut(str, "=") - parts[key] = val - } else { - return fmt.Errorf("cannot unmarshal '%v' of type %T into a string value", s, s) - } - } - *s = parts - return nil - } - - var mapType map[string]any - if err := unmarshal(&mapType); err == nil { - *s = mapType - return nil - } - - return errors.New("failed to unmarshal SliceOrMap") -} diff --git a/pipeline/frontend/yaml/types/base/map_test.go b/pipeline/frontend/yaml/types/base/map_test.go deleted file mode 100644 index 750fd1714..000000000 --- a/pipeline/frontend/yaml/types/base/map_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2024 Woodpecker Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package base - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v3" -) - -type StructSliceOrMap struct { - Foos SliceOrMap `yaml:"foos,omitempty"` - Bars []string `yaml:"bars"` -} - -func TestSliceOrMapYaml(t *testing.T) { - str := `{foos: [bar=baz, far=faz]}` - - s := StructSliceOrMap{} - assert.NoError(t, yaml.Unmarshal([]byte(str), &s)) - - assert.Equal(t, SliceOrMap{"bar": "baz", "far": "faz"}, s.Foos) - - d, err := yaml.Marshal(&s) - assert.NoError(t, err) - - s2 := StructSliceOrMap{} - assert.NoError(t, yaml.Unmarshal(d, &s2)) - - assert.Equal(t, SliceOrMap{"bar": "baz", "far": "faz"}, s2.Foos) -} - -func TestStr2SliceOrMapPtrMap(t *testing.T) { - s := map[string]*StructSliceOrMap{"udav": { - Foos: SliceOrMap{"io.rancher.os.bar": "baz", "io.rancher.os.far": "true"}, - Bars: []string{}, - }} - d, err := yaml.Marshal(&s) - assert.NoError(t, err) - - s2 := map[string]*StructSliceOrMap{} - assert.NoError(t, yaml.Unmarshal(d, &s2)) - - assert.Equal(t, s, s2) -} diff --git a/pipeline/frontend/yaml/types/container.go b/pipeline/frontend/yaml/types/container.go index edfacd5c2..3cb683381 100644 --- a/pipeline/frontend/yaml/types/container.go +++ b/pipeline/frontend/yaml/types/container.go @@ -39,7 +39,6 @@ type ( Detached bool `yaml:"detach,omitempty"` Directory string `yaml:"directory,omitempty"` Failure string `yaml:"failure,omitempty"` - Group string `yaml:"group,omitempty"` Image string `yaml:"image,omitempty"` Name string `yaml:"name,omitempty"` Pull bool `yaml:"pull,omitempty"` @@ -49,10 +48,8 @@ type ( Ports []string `yaml:"ports,omitempty"` DependsOn base.StringOrSlice `yaml:"depends_on,omitempty"` - // TODO: make []string in 3.x - Secrets Secrets `yaml:"secrets,omitempty"` - // TODO: make map[string]any in 3.x - Environment base.SliceOrMap `yaml:"environment,omitempty"` + Secrets []string `yaml:"secrets,omitempty"` + Environment map[string]any `yaml:"environment,omitempty"` // Docker and Kubernetes Specific Privileged bool `yaml:"privileged,omitempty"` @@ -125,7 +122,7 @@ func (c *Container) IsPlugin() bool { return len(c.Commands) == 0 && len(c.Entrypoint) == 0 && len(c.Environment) == 0 && - len(c.Secrets.Secrets) == 0 + len(c.Secrets) == 0 } func (c *Container) IsTrustedCloneImage() bool { diff --git a/pipeline/frontend/yaml/types/container_test.go b/pipeline/frontend/yaml/types/container_test.go index 3573fbc13..10de961c7 100644 --- a/pipeline/frontend/yaml/types/container_test.go +++ b/pipeline/frontend/yaml/types/container_test.go @@ -41,8 +41,8 @@ dns: 8.8.8.8 dns_search: example.com entrypoint: [/bin/sh, -c] environment: - - RACK_ENV=development - - SHOW=true + RACK_ENV: development + SHOW: true extra_hosts: - somehost:162.242.195.82 - otherhost:50.31.209.229 @@ -88,7 +88,7 @@ func TestUnmarshalContainer(t *testing.T) { DNS: base.StringOrSlice{"8.8.8.8"}, DNSSearch: base.StringOrSlice{"example.com"}, Entrypoint: []string{"/bin/sh", "-c"}, - Environment: base.SliceOrMap{"RACK_ENV": "development", "SHOW": "true"}, + Environment: map[string]any{"RACK_ENV": "development", "SHOW": true}, ExtraHosts: []string{"somehost:162.242.195.82", "otherhost:50.31.209.229", "ipv6:2001:db8::10"}, Image: "golang:latest", MemLimit: base.MemStringOrInt(1024), @@ -114,9 +114,7 @@ func TestUnmarshalContainer(t *testing.T) { }, }, { - Event: constraint.List{ - Include: []string{"cron"}, - }, + Event: base.StringOrSlice{"cron"}, Cron: constraint.List{ Include: []string{"job1"}, }, @@ -166,7 +164,6 @@ func TestUnmarshalContainers(t *testing.T) { }, { from: `publish-agent: - group: bundle image: print/env settings: repo: woodpeckerci/woodpecker-agent @@ -179,16 +176,9 @@ func TestUnmarshalContainers(t *testing.T) { event: push`, want: []*Container{ { - Name: "publish-agent", - Image: "print/env", - Group: "bundle", - Secrets: Secrets{Secrets: []*Secret{{ - Source: "docker_username", - Target: "docker_username", - }, { - Source: "docker_password", - Target: "docker_password", - }}}, + Name: "publish-agent", + Image: "print/env", + Secrets: []string{"docker_username", "docker_password"}, Settings: map[string]any{ "repo": "woodpeckerci/woodpecker-agent", "dockerfile": "docker/Dockerfile.agent", @@ -198,7 +188,7 @@ func TestUnmarshalContainers(t *testing.T) { When: constraint.When{ Constraints: []constraint.Constraint{ { - Event: constraint.List{Include: []string{"push"}}, + Event: base.StringOrSlice{"push"}, Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}}, }, }, @@ -208,7 +198,6 @@ func TestUnmarshalContainers(t *testing.T) { }, { from: `publish-cli: - group: docker image: print/env settings: repo: woodpeckerci/woodpecker-cli @@ -221,7 +210,6 @@ func TestUnmarshalContainers(t *testing.T) { { Name: "publish-cli", Image: "print/env", - Group: "docker", Settings: map[string]any{ "repo": "woodpeckerci/woodpecker-cli", "dockerfile": "docker/Dockerfile.cli", @@ -230,7 +218,7 @@ func TestUnmarshalContainers(t *testing.T) { When: constraint.When{ Constraints: []constraint.Constraint{ { - Event: constraint.List{Include: []string{"push"}}, + Event: base.StringOrSlice{"push"}, Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}}, }, }, @@ -252,11 +240,11 @@ func TestUnmarshalContainers(t *testing.T) { When: constraint.When{ Constraints: []constraint.Constraint{ { - Event: constraint.List{Include: []string{"push"}}, + Event: base.StringOrSlice{"push"}, Branch: constraint.List{Include: []string{"${CI_REPO_DEFAULT_BRANCH}"}}, }, { - Event: constraint.List{Include: []string{"pull_request"}}, + Event: base.StringOrSlice{"pull_request"}, }, }, }, diff --git a/pipeline/frontend/yaml/types/secret.go b/pipeline/frontend/yaml/types/secret.go deleted file mode 100644 index 9958b41aa..000000000 --- a/pipeline/frontend/yaml/types/secret.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2023 Woodpecker Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types - -import "gopkg.in/yaml.v3" - -type ( - // Secrets defines a collection of secrets. - Secrets struct { - Secrets []*Secret - } - - // Secret defines a container secret. - Secret struct { - Source string `yaml:"source"` - Target string `yaml:"target"` - } -) - -// UnmarshalYAML implements the Unmarshaler interface. -func (s *Secrets) UnmarshalYAML(value *yaml.Node) error { - y, _ := yaml.Marshal(value) - - var secrets []string - err := yaml.Unmarshal(y, &secrets) - if err == nil { - for _, str := range secrets { - s.Secrets = append(s.Secrets, &Secret{ - Source: str, - Target: str, - }) - } - return nil - } - return yaml.Unmarshal(y, &s.Secrets) -} diff --git a/pipeline/frontend/yaml/types/secret_test.go b/pipeline/frontend/yaml/types/secret_test.go deleted file mode 100644 index fcfc6d212..000000000 --- a/pipeline/frontend/yaml/types/secret_test.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2023 Woodpecker Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "gopkg.in/yaml.v3" -) - -func TestUnmarshalSecrets(t *testing.T) { - testdata := []struct { - from string - want []*Secret - }{ - { - from: "[ mysql_username, mysql_password]", - want: []*Secret{ - { - Source: "mysql_username", - Target: "mysql_username", - }, - { - Source: "mysql_password", - Target: "mysql_password", - }, - }, - }, - { - from: "[ { source: mysql_prod_username, target: mysql_username } ]", - want: []*Secret{ - { - Source: "mysql_prod_username", - Target: "mysql_username", - }, - }, - }, - { - from: "[ { source: mysql_prod_username, target: mysql_username }, { source: redis_username, target: redis_username } ]", - want: []*Secret{ - { - Source: "mysql_prod_username", - Target: "mysql_username", - }, - { - Source: "redis_username", - Target: "redis_username", - }, - }, - }, - } - - for _, test := range testdata { - in := []byte(test.from) - got := Secrets{} - err := yaml.Unmarshal(in, &got) - assert.NoError(t, err) - assert.EqualValues(t, test.want, got.Secrets, "problem parsing secrets %q", test.from) - } -}