mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-25 03:11:01 +00:00
Remove old pipeline options (#4016)
This commit is contained in:
parent
8251ec198b
commit
aafd217cce
19 changed files with 100 additions and 574 deletions
|
@ -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`
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue