diff --git a/.woodpecker/binaries.yml b/.woodpecker/binaries.yml index fd6aaf106..f268bef9d 100644 --- a/.woodpecker/binaries.yml +++ b/.woodpecker/binaries.yml @@ -1,3 +1,5 @@ +version: 1 + depends_on: - test - web diff --git a/.woodpecker/docker.yml b/.woodpecker/docker.yml index d9dfb9f17..b89324768 100644 --- a/.woodpecker/docker.yml +++ b/.woodpecker/docker.yml @@ -1,3 +1,5 @@ +version: 1 + when: - event: [pull_request, tag] - event: push diff --git a/.woodpecker/docs.yml b/.woodpecker/docs.yml index 0498765b0..b8c239eeb 100644 --- a/.woodpecker/docs.yml +++ b/.woodpecker/docs.yml @@ -1,3 +1,5 @@ +version: 1 + when: - event: tag - event: pull_request diff --git a/.woodpecker/release-helper.yml b/.woodpecker/release-helper.yml index 0b83ad5c7..5363934cb 100644 --- a/.woodpecker/release-helper.yml +++ b/.woodpecker/release-helper.yml @@ -1,3 +1,5 @@ +version: 1 + steps: release-helper: image: woodpeckerci/plugin-ready-release-go:0.7.0 diff --git a/.woodpecker/securityscan.yml b/.woodpecker/securityscan.yml index c5e06dcd2..934fc768c 100644 --- a/.woodpecker/securityscan.yml +++ b/.woodpecker/securityscan.yml @@ -1,3 +1,5 @@ +version: 1 + when: - event: [pull_request, cron] - event: push diff --git a/.woodpecker/test.yml b/.woodpecker/test.yml index b8ce27cc2..03e1ce8f0 100644 --- a/.woodpecker/test.yml +++ b/.woodpecker/test.yml @@ -1,3 +1,5 @@ +version: 1 + when: - event: [pull_request, tag] - event: push diff --git a/.woodpecker/web.yml b/.woodpecker/web.yml index bacdb9a99..06f8d68c9 100644 --- a/.woodpecker/web.yml +++ b/.woodpecker/web.yml @@ -1,3 +1,5 @@ +version: 1 + when: - event: [pull_request, tag] - event: push diff --git a/contrib/woodpecker-test-repo/.woodpecker/demo.yml b/contrib/woodpecker-test-repo/.woodpecker/demo.yml index 02824a8de..cc6ae3bb9 100644 --- a/contrib/woodpecker-test-repo/.woodpecker/demo.yml +++ b/contrib/woodpecker-test-repo/.woodpecker/demo.yml @@ -1,3 +1,4 @@ +version: 1 steps: demo: image: 'alpine' diff --git a/contrib/woodpecker-test-repo/.woodpecker/test.yml b/contrib/woodpecker-test-repo/.woodpecker/test.yml index 1f41cddc3..b8e568ece 100644 --- a/contrib/woodpecker-test-repo/.woodpecker/test.yml +++ b/contrib/woodpecker-test-repo/.woodpecker/test.yml @@ -1,3 +1,4 @@ +version: 1 steps: test_1: image: 'alpine' diff --git a/pipeline/frontend/yaml/linter/linter_test.go b/pipeline/frontend/yaml/linter/linter_test.go index 0bad7fc4d..a416f0eb0 100644 --- a/pipeline/frontend/yaml/linter/linter_test.go +++ b/pipeline/frontend/yaml/linter/linter_test.go @@ -26,6 +26,7 @@ import ( func TestLint(t *testing.T) { testdatas := []struct{ Title, Data string }{{ Title: "map", Data: ` +version: 1 steps: build: image: docker @@ -45,6 +46,7 @@ services: `, }, { Title: "list", Data: ` +version: 1 steps: - name: build image: docker @@ -61,6 +63,7 @@ steps: `, }, { Title: "merge maps", Data: ` +version: 1 variables: step_template: &base-step image: golang:1.19 @@ -155,7 +158,7 @@ func TestLintErrors(t *testing.T) { } for _, test := range testdata { - conf, err := yaml.ParseString(test.from) + conf, err := yaml.ParseString("version: 1\n" + test.from) if err != nil { t.Fatalf("Cannot unmarshal yaml %q. Error: %s", test.from, err) } diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-array.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-array.yml index d530db055..32db454de 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-array.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-array.yml @@ -1,3 +1,5 @@ +version: 1 + branches: [main, pages] steps: diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-exclude-include.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-exclude-include.yml index 03b534d23..142788702 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-exclude-include.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches-exclude-include.yml @@ -1,3 +1,5 @@ +version: 1 + branches: include: main exclude: [develop, feature/*] diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches.yml index 75b72bbcf..38122b513 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-branches.yml @@ -1,3 +1,5 @@ +version: 1 + branches: main steps: diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken.yml index 17d721865..f716f520a 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-broken.yml @@ -1,3 +1,5 @@ +version: 1 + branches: main matri: diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-clone-skip.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-clone-skip.yml index 50c20409c..2c0ce1dc2 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-clone-skip.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-clone-skip.yml @@ -1,3 +1,5 @@ +version: 1 + steps: test: image: alpine diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-clone.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-clone.yml index 81ef330c6..95c6d3050 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-clone.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-clone.yml @@ -1,3 +1,5 @@ +version: 1 + clone: git: image: plugins/git:next diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-labels.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-labels.yml index a8b793367..ea441f501 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-labels.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-labels.yml @@ -1,3 +1,5 @@ +version: 1 + labels: location: europe weather: sun diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-matrix.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-matrix.yml index 449ab7a57..ff15e65a3 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-matrix.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-matrix.yml @@ -1,3 +1,5 @@ +version: 1 + steps: test: image: golang:${GO_VERSION} diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-merge-map-and-sequence.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-merge-map-and-sequence.yml index acd24e0f3..673db526b 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-merge-map-and-sequence.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-merge-map-and-sequence.yml @@ -1,3 +1,5 @@ +version: 1 + variables: step_template: &base-step image: golang:1.19 diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-multi.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-multi.yml index e5d4fda79..5f1e491f3 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-multi.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-multi.yml @@ -1,3 +1,5 @@ +version: 1 + steps: deploy: image: golang diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-pipeline-when.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-pipeline-when.yml index 84f02b403..ff0af601f 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-pipeline-when.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-pipeline-when.yml @@ -1,3 +1,5 @@ +version: 1 + when: - branch: [main, deploy] event: push diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-platform.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-platform.yml index 7b4abf027..b3da75a96 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-platform.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-platform.yml @@ -1,3 +1,5 @@ +version: 1 + platform: linux/amd64 steps: diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-plugin.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-plugin.yml index db85967b2..6c0bfdbc1 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-plugin.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-plugin.yml @@ -1,3 +1,5 @@ +version: 1 + steps: build: image: golang diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-run-on.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-run-on.yml index fc6d53dc2..b6039bbe6 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-run-on.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-run-on.yml @@ -1,3 +1,5 @@ +version: 1 + steps: build: image: golang diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yml index 03564e9fc..98dce9f53 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-service.yml @@ -1,3 +1,5 @@ +version: 1 + steps: build: image: golang diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yml index 3db52b95c..43a9a2af2 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-step.yml @@ -1,3 +1,5 @@ +version: 1 + steps: image: image: golang diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yml index 721c92bf8..fa40d04d2 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-when.yml @@ -1,3 +1,5 @@ +version: 1 + steps: when-branch: image: alpine diff --git a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-workspace.yml b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-workspace.yml index 5ee7ae988..3ac5202e0 100644 --- a/pipeline/frontend/yaml/linter/schema/.woodpecker/test-workspace.yml +++ b/pipeline/frontend/yaml/linter/schema/.woodpecker/test-workspace.yml @@ -1,3 +1,5 @@ +version: 1 + workspace: base: /go path: src/github.com/octocat/hello-world diff --git a/pipeline/frontend/yaml/linter/schema/schema.json b/pipeline/frontend/yaml/linter/schema/schema.json index aa26dd69b..af32d89fc 100644 --- a/pipeline/frontend/yaml/linter/schema/schema.json +++ b/pipeline/frontend/yaml/linter/schema/schema.json @@ -34,7 +34,8 @@ "type": "array", "minLength": 1, "items": { "type": "string" } - } + }, + "version": { "type": "number", "default": 1 } }, "definitions": { "clone": { diff --git a/pipeline/frontend/yaml/parse.go b/pipeline/frontend/yaml/parse.go index ae01c0c5f..f57a973e0 100644 --- a/pipeline/frontend/yaml/parse.go +++ b/pipeline/frontend/yaml/parse.go @@ -15,6 +15,7 @@ package yaml import ( + "errors" "fmt" "codeberg.org/6543/xyaml" @@ -22,16 +23,27 @@ import ( "github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/constraint" "github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/types" "github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/types/base" + "github.com/woodpecker-ci/woodpecker/shared/constant" ) +var ErrUnsuportedVersion = errors.New("unsuported pipeline config version detected") + // ParseBytes parses the configuration from bytes b. func ParseBytes(b []byte) (*types.Workflow, error) { - out := new(types.Workflow) - err := xyaml.Unmarshal(b, out) + yamlVersion, err := checkVersion(b) if err != nil { return nil, err } + out := new(types.Workflow) + err = xyaml.Unmarshal(b, out) + if err != nil { + return nil, err + } + + // make sure detected version is set + out.Version = yamlVersion + // support deprecated branch filter if out.BranchesDontUseIt != nil { if out.When.Constraints == nil { @@ -70,3 +82,19 @@ func ParseString(s string) (*types.Workflow, error) { []byte(s), ) } + +func checkVersion(b []byte) (int, error) { + ver := struct { + Version int `yaml:"version"` + }{} + _ = xyaml.Unmarshal(b, &ver) + if ver.Version == 0 { + // default: version 1 + return constant.DefaultPipelineVersion, nil + } + + if ver.Version != Version { + return 0, ErrUnsuportedVersion + } + return ver.Version, nil +} diff --git a/pipeline/frontend/yaml/parse_test.go b/pipeline/frontend/yaml/parse_test.go index 2628dab8c..aa5a76259 100644 --- a/pipeline/frontend/yaml/parse_test.go +++ b/pipeline/frontend/yaml/parse_test.go @@ -88,6 +88,16 @@ func TestParse(t *testing.T) { g.Assert(out.Steps.ContainerList[1].When.Constraints[0].Event.Include).Equal([]string{"success"}) }) + g.It("Should unmarshal with default version", func() { + out, err := ParseString(sampleYamlDefaultVersion) + if err != nil { + g.Fail(err) + } + g.Assert(len(out.Steps.ContainerList)).Equal(1) + g.Assert(out.Steps.ContainerList[0].Name).Equal("notify_success") + g.Assert(out.Steps.ContainerList[0].Image).Equal("xyz") + }) + matchConfig, err := ParseString(sampleYaml) if err != nil { g.Fail(err) @@ -180,6 +190,7 @@ pipeline: } var sampleYaml = ` +version: 1 image: hello-world when: - event: @@ -231,7 +242,14 @@ runs_on: - failure ` +var sampleYamlDefaultVersion = ` +steps: + - name: notify_success + image: xyz +` + var simpleYamlAnchors = ` +version: 1 vars: image: &image plugins/slack steps: @@ -240,6 +258,7 @@ steps: ` var sampleVarYaml = ` +version: 1 _slack: &SLACK image: plugins/slack steps: diff --git a/pipeline/frontend/yaml/types/workflow.go b/pipeline/frontend/yaml/types/workflow.go index 9c397e6c1..343dd666f 100644 --- a/pipeline/frontend/yaml/types/workflow.go +++ b/pipeline/frontend/yaml/types/workflow.go @@ -31,6 +31,7 @@ type ( DependsOn []string `yaml:"depends_on,omitempty"` RunsOn []string `yaml:"runs_on,omitempty"` SkipClone bool `yaml:"skip_clone"` + Version int `yaml:"version"` // Undocumented Cache base.StringOrSlice `yaml:"cache,omitempty"` diff --git a/pipeline/frontend/yaml/version.go b/pipeline/frontend/yaml/version.go new file mode 100644 index 000000000..e48311388 --- /dev/null +++ b/pipeline/frontend/yaml/version.go @@ -0,0 +1,18 @@ +// 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 yaml + +// Version of this package and it's subpackages +const Version = 1 diff --git a/pipeline/stepBuilder_test.go b/pipeline/stepBuilder_test.go index 6a687a713..574ec9596 100644 --- a/pipeline/stepBuilder_test.go +++ b/pipeline/stepBuilder_test.go @@ -47,6 +47,7 @@ func TestGlobalEnvsubst(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Data: []byte(` +version: 1 steps: build: image: ${IMAGE} @@ -83,6 +84,7 @@ func TestMissingGlobalEnvsubst(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Data: []byte(` +version: 1 steps: build: image: ${IMAGE} @@ -116,6 +118,7 @@ bbb`, Link: "", Yamls: []*forge_types.FileMeta{ {Data: []byte(` +version: 1 steps: xxx: image: scratch @@ -123,6 +126,7 @@ steps: yyy: ${CI_COMMIT_MESSAGE} `)}, {Data: []byte(` +version: 1 steps: build: image: scratch @@ -153,11 +157,13 @@ func TestMultiPipeline(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Data: []byte(` +version: 1 steps: xxx: image: scratch `)}, {Data: []byte(` +version: 1 steps: build: image: scratch @@ -188,16 +194,19 @@ func TestDependsOn(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Name: "lint", Data: []byte(` +version: 1 steps: build: image: scratch `)}, {Name: "test", Data: []byte(` +version: 1 steps: build: image: scratch `)}, {Data: []byte(` +version: 1 steps: deploy: image: scratch @@ -235,6 +244,7 @@ func TestRunsOn(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Data: []byte(` +version: 1 steps: deploy: image: scratch @@ -272,11 +282,13 @@ func TestPipelineName(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Name: ".woodpecker/lint.yml", Data: []byte(` +version: 1 steps: build: image: scratch `)}, {Name: ".woodpecker/.test.yml", Data: []byte(` +version: 1 steps: build: image: scratch @@ -308,12 +320,14 @@ func TestBranchFilter(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Data: []byte(` +version: 1 steps: xxx: image: scratch branches: main `)}, {Data: []byte(` +version: 1 steps: build: image: scratch @@ -347,6 +361,7 @@ func TestRootWhenFilter(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Data: []byte(` +version: 1 when: event: - tag @@ -355,6 +370,7 @@ steps: image: scratch `)}, {Data: []byte(` +version: 1 when: event: - push @@ -363,6 +379,7 @@ steps: image: scratch `)}, {Data: []byte(` +version: 1 steps: build: image: scratch @@ -396,6 +413,7 @@ func TestZeroSteps(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Data: []byte(` +version: 1 skip_clone: true steps: build: @@ -431,6 +449,7 @@ func TestZeroStepsAsMultiPipelineDeps(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Name: "zerostep", Data: []byte(` +version: 1 skip_clone: true steps: build: @@ -439,11 +458,13 @@ steps: image: scratch `)}, {Name: "justastep", Data: []byte(` +version: 1 steps: build: image: scratch `)}, {Name: "shouldbefiltered", Data: []byte(` +version: 1 steps: build: image: scratch @@ -480,6 +501,7 @@ func TestZeroStepsAsMultiPipelineTransitiveDeps(t *testing.T) { Link: "", Yamls: []*forge_types.FileMeta{ {Name: "zerostep", Data: []byte(` +version: 1 skip_clone: true steps: build: @@ -488,17 +510,20 @@ steps: image: scratch `)}, {Name: "justastep", Data: []byte(` +version: 1 steps: build: image: scratch `)}, {Name: "shouldbefiltered", Data: []byte(` +version: 1 steps: build: image: scratch depends_on: [ zerostep ] `)}, {Name: "shouldbefilteredtoo", Data: []byte(` +version: 1 steps: build: image: scratch diff --git a/shared/constant/constant.go b/shared/constant/constant.go index 3d46ee769..a6eb50c92 100644 --- a/shared/constant/constant.go +++ b/shared/constant/constant.go @@ -40,3 +40,5 @@ var TrustedCloneImages = []string{ DefaultCloneImage, "quay.io/woodpeckerci/plugin-git", } + +const DefaultPipelineVersion = 1