You've already forked woodpecker
mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2026-06-03 16:35:37 +02:00
Move skip pipeline by commit message into pipeline/frontend package (#6437)
and add some custom types for events and failure in metadata package. no logic change at all.
This commit is contained in:
@@ -97,7 +97,7 @@ func metadataFromContext(_ context.Context, c *cli.Command, axis matrix.Axis, w
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-started", func(i int64) { m.Curr.Started = i }, c.Int64)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-finished", func(i int64) { m.Curr.Finished = i }, c.Int64)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-status", func(s string) { m.Curr.Status = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-event", func(s string) { m.Curr.Event = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-event", func(s string) { m.Curr.Event = metadata.Event(s) }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-url", func(s string) { m.Curr.ForgeURL = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-deploy-to", func(s string) { m.Curr.DeployTo = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "pipeline-deploy-task", func(s string) { m.Curr.DeployTask = s }, c.String)
|
||||
@@ -123,7 +123,7 @@ func metadataFromContext(_ context.Context, c *cli.Command, axis matrix.Axis, w
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-started", func(i int64) { m.Prev.Started = i }, c.Int64)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-finished", func(i int64) { m.Prev.Finished = i }, c.Int64)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-status", func(s string) { m.Prev.Status = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-event", func(s string) { m.Prev.Event = s }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-event", func(s string) { m.Prev.Event = metadata.Event(s) }, c.String)
|
||||
metadataFileAndOverrideOrDefault(c, "prev-pipeline-url", func(s string) { m.Prev.ForgeURL = s }, c.String)
|
||||
|
||||
// Previous Pipeline Commit
|
||||
|
||||
@@ -5891,6 +5891,31 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata.Event": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"push",
|
||||
"pull_request",
|
||||
"pull_request_closed",
|
||||
"pull_request_metadata",
|
||||
"tag",
|
||||
"release",
|
||||
"deployment",
|
||||
"cron",
|
||||
"manual"
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"EventPush",
|
||||
"EventPull",
|
||||
"EventPullClosed",
|
||||
"EventPullMetadata",
|
||||
"EventTag",
|
||||
"EventRelease",
|
||||
"EventDeploy",
|
||||
"EventCron",
|
||||
"EventManual"
|
||||
]
|
||||
},
|
||||
"metadata.Forge": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5950,7 +5975,7 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
},
|
||||
"event": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/metadata.Event"
|
||||
},
|
||||
"event_reason": {
|
||||
"type": "array",
|
||||
|
||||
@@ -14,20 +14,22 @@
|
||||
|
||||
package metadata
|
||||
|
||||
type Event string
|
||||
|
||||
// Event types corresponding to forge hooks.
|
||||
const (
|
||||
EventPush = "push"
|
||||
EventPull = "pull_request"
|
||||
EventPullClosed = "pull_request_closed"
|
||||
EventPullMetadata = "pull_request_metadata"
|
||||
EventTag = "tag"
|
||||
EventRelease = "release"
|
||||
EventDeploy = "deployment"
|
||||
EventCron = "cron"
|
||||
EventManual = "manual"
|
||||
EventPush Event = "push"
|
||||
EventPull Event = "pull_request"
|
||||
EventPullClosed Event = "pull_request_closed"
|
||||
EventPullMetadata Event = "pull_request_metadata"
|
||||
EventTag Event = "tag"
|
||||
EventRelease Event = "release"
|
||||
EventDeploy Event = "deployment"
|
||||
EventCron Event = "cron"
|
||||
EventManual Event = "manual"
|
||||
)
|
||||
|
||||
func EventIsPull(event string) bool {
|
||||
func (event Event) IsPull() bool {
|
||||
switch event {
|
||||
case EventPull,
|
||||
EventPullClosed,
|
||||
@@ -37,11 +39,11 @@ func EventIsPull(event string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type Failure string
|
||||
|
||||
// Different ways to handle failure states.
|
||||
const (
|
||||
FailureIgnore = "ignore"
|
||||
FailureFail = "fail"
|
||||
//nolint:godot
|
||||
// TODO: Not implemented yet.
|
||||
// FailureCancel = "cancel"
|
||||
FailureIgnore Failure = "ignore"
|
||||
FailureFail Failure = "fail"
|
||||
FailureCancel Failure = "cancel"
|
||||
)
|
||||
|
||||
@@ -67,7 +67,7 @@ func (m *Metadata) Environ() map[string]string {
|
||||
pipeline := m.Curr
|
||||
setNonEmptyEnvVar(params, "CI_PIPELINE_NUMBER", strconv.FormatInt(pipeline.Number, 10))
|
||||
setNonEmptyEnvVar(params, "CI_PIPELINE_PARENT", strconv.FormatInt(pipeline.Parent, 10))
|
||||
setNonEmptyEnvVar(params, "CI_PIPELINE_EVENT", pipeline.Event)
|
||||
setNonEmptyEnvVar(params, "CI_PIPELINE_EVENT", string(pipeline.Event))
|
||||
setNonEmptyEnvVar(params, "CI_PIPELINE_EVENT_REASON", strings.Join(pipeline.EventReason, ","))
|
||||
setNonEmptyEnvVar(params, "CI_PIPELINE_URL", m.getPipelineWebURL(pipeline, 0))
|
||||
setNonEmptyEnvVar(params, "CI_PIPELINE_FORGE_URL", pipeline.ForgeURL)
|
||||
@@ -102,7 +102,7 @@ func (m *Metadata) Environ() map[string]string {
|
||||
if pipeline.Event == EventRelease {
|
||||
setNonEmptyEnvVar(params, "CI_COMMIT_PRERELEASE", strconv.FormatBool(pipeline.Commit.IsPrerelease))
|
||||
}
|
||||
if EventIsPull(pipeline.Event) {
|
||||
if pipeline.Event.IsPull() {
|
||||
sourceBranch, targetBranch := getSourceTargetBranches(commit.Refspec)
|
||||
setNonEmptyEnvVar(params, "CI_COMMIT_SOURCE_BRANCH", sourceBranch)
|
||||
setNonEmptyEnvVar(params, "CI_COMMIT_TARGET_BRANCH", targetBranch)
|
||||
@@ -127,7 +127,7 @@ func (m *Metadata) Environ() map[string]string {
|
||||
prevPipeline := m.Prev
|
||||
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_NUMBER", strconv.FormatInt(prevPipeline.Number, 10))
|
||||
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_PARENT", strconv.FormatInt(prevPipeline.Parent, 10))
|
||||
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_EVENT", prevPipeline.Event)
|
||||
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_EVENT", string(prevPipeline.Event))
|
||||
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_EVENT_REASON", strings.Join(prevPipeline.EventReason, ","))
|
||||
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_URL", m.getPipelineWebURL(prevPipeline, 0))
|
||||
setNonEmptyEnvVar(params, "CI_PREV_PIPELINE_FORGE_URL", prevPipeline.ForgeURL)
|
||||
@@ -149,7 +149,7 @@ func (m *Metadata) Environ() map[string]string {
|
||||
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_BRANCH", prevCommit.Branch)
|
||||
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_AUTHOR", prevCommit.Author.Name)
|
||||
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_AUTHOR_EMAIL", prevCommit.Author.Email)
|
||||
if EventIsPull(prevPipeline.Event) {
|
||||
if prevPipeline.Event.IsPull() {
|
||||
prevSourceBranch, prevTargetBranch := getSourceTargetBranches(prevCommit.Refspec)
|
||||
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_SOURCE_BRANCH", prevSourceBranch)
|
||||
setNonEmptyEnvVar(params, "CI_PREV_COMMIT_TARGET_BRANCH", prevTargetBranch)
|
||||
|
||||
@@ -48,7 +48,7 @@ type (
|
||||
Started int64 `json:"started,omitempty"`
|
||||
Finished int64 `json:"finished,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Event string `json:"event,omitempty"`
|
||||
Event Event `json:"event,omitempty"`
|
||||
EventReason []string `json:"event_reason,omitempty"`
|
||||
ForgeURL string `json:"forge_url,omitempty"`
|
||||
DeployTo string `json:"target,omitempty"`
|
||||
|
||||
@@ -42,10 +42,10 @@ type Secret struct {
|
||||
Name string
|
||||
Value string
|
||||
AllowedPlugins []string
|
||||
Events []string
|
||||
Events []metadata.Event
|
||||
}
|
||||
|
||||
func (s *Secret) Available(event string, container *yaml_types.Container) error {
|
||||
func (s *Secret) Available(event metadata.Event, container *yaml_types.Container) error {
|
||||
onlyAllowSecretForPlugins := len(s.AllowedPlugins) > 0
|
||||
if onlyAllowSecretForPlugins && !container.IsPlugin() {
|
||||
return fmt.Errorf("secret %q is only allowed to be used by plugins (a filter has been set on the secret). Note: Image filters do not work for normal steps", s.Name)
|
||||
@@ -64,13 +64,13 @@ func (s *Secret) Available(event string, container *yaml_types.Container) error
|
||||
|
||||
// Match returns true if an image and event match the restricted list.
|
||||
// Note that EventPullClosed are treated as EventPull.
|
||||
func (s *Secret) Match(event string) bool {
|
||||
func (s *Secret) Match(event metadata.Event) bool {
|
||||
// if there is no filter set secret matches all webhook events
|
||||
if len(s.Events) == 0 {
|
||||
return true
|
||||
}
|
||||
// treat all pull events the same way
|
||||
if metadata.EventIsPull(event) {
|
||||
if event.IsPull() {
|
||||
event = metadata.EventPull
|
||||
}
|
||||
// one match is enough
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
func TestSecretAvailable(t *testing.T) {
|
||||
secret := Secret{
|
||||
AllowedPlugins: []string{},
|
||||
Events: []string{"push"},
|
||||
Events: []metadata.Event{"push"},
|
||||
}
|
||||
assert.NoError(t, secret.Available("push", &yaml_types.Container{
|
||||
Image: "golang",
|
||||
@@ -40,7 +40,7 @@ func TestSecretAvailable(t *testing.T) {
|
||||
secret = Secret{
|
||||
Name: "foo",
|
||||
AllowedPlugins: []string{"golang"},
|
||||
Events: []string{"push"},
|
||||
Events: []metadata.Event{"push"},
|
||||
}
|
||||
assert.NoError(t, secret.Available("push", &yaml_types.Container{
|
||||
Name: "step",
|
||||
@@ -440,18 +440,18 @@ func TestSecretMatch(t *testing.T) {
|
||||
tcl := []*struct {
|
||||
name string
|
||||
secret Secret
|
||||
event string
|
||||
event metadata.Event
|
||||
match bool
|
||||
}{
|
||||
{
|
||||
name: "should match event",
|
||||
secret: Secret{Events: []string{"pull_request"}},
|
||||
secret: Secret{Events: []metadata.Event{"pull_request"}},
|
||||
event: "pull_request",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
name: "should not match event",
|
||||
secret: Secret{Events: []string{"pull_request"}},
|
||||
secret: Secret{Events: []metadata.Event{"pull_request"}},
|
||||
event: "push",
|
||||
match: false,
|
||||
},
|
||||
@@ -463,13 +463,13 @@ func TestSecretMatch(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "pull close should match pull",
|
||||
secret: Secret{Events: []string{"pull_request"}},
|
||||
secret: Secret{Events: []metadata.Event{"pull_request"}},
|
||||
event: "pull_request_closed",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
name: "pull metadata change should match pull",
|
||||
secret: Secret{Events: []string{"pull_request"}},
|
||||
secret: Secret{Events: []metadata.Event{"pull_request"}},
|
||||
event: "pull_request_metadata",
|
||||
match: true,
|
||||
},
|
||||
|
||||
@@ -153,7 +153,7 @@ func (c *Compiler) createProcess(container *yaml_types.Container, workflow *yaml
|
||||
|
||||
failure := container.Failure
|
||||
if container.Failure == "" {
|
||||
failure = metadata.FailureFail
|
||||
failure = string(metadata.FailureFail)
|
||||
}
|
||||
|
||||
return &backend_types.Step{
|
||||
|
||||
@@ -172,13 +172,13 @@ func (c *Constraint) Match(m metadata.Metadata, global bool, env map[string]stri
|
||||
}
|
||||
|
||||
match = match && c.Platform.Match(m.Sys.Platform) &&
|
||||
(len(c.Event) == 0 || slices.Contains(c.Event, m.Curr.Event)) &&
|
||||
(len(c.Event) == 0 || slices.Contains(c.Event, string(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)
|
||||
|
||||
// changed files filter apply only for pull-request and push events
|
||||
if metadata.EventIsPull(m.Curr.Event) || m.Curr.Event == metadata.EventPush {
|
||||
if m.Curr.Event.IsPull() || m.Curr.Event == metadata.EventPush {
|
||||
match = match && c.Path.Match(m.Curr.Commit.ChangedFiles, m.Curr.Commit.Message)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2026 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 constraint
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/metadata"
|
||||
)
|
||||
|
||||
var skipPipelineRegex = regexp.MustCompile(`\[(?i:ci *skip|skip *ci)\]`)
|
||||
|
||||
func IsSkipCommitMessage(event metadata.Event, commitMessage string) bool {
|
||||
if event == metadata.EventPush || event.IsPull() {
|
||||
skipMatch := skipPipelineRegex.FindString(commitMessage)
|
||||
if len(skipMatch) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -62,7 +62,7 @@ func withExitCode(code int) func(*backend_types.Step) {
|
||||
}
|
||||
|
||||
func withIgnoreFailure() func(*backend_types.Step) {
|
||||
return func(s *backend_types.Step) { s.Failure = metadata.FailureIgnore }
|
||||
return func(s *backend_types.Step) { s.Failure = string(metadata.FailureIgnore) }
|
||||
}
|
||||
|
||||
func withOnFailure() func(*backend_types.Step) {
|
||||
|
||||
@@ -186,7 +186,7 @@ func (r *Runtime) runBlockingStep(runnerCtx context.Context, step *backend_types
|
||||
}
|
||||
|
||||
err = r.traceStep(processState, err, step)
|
||||
if err != nil && step.Failure == metadata.FailureIgnore {
|
||||
if err != nil && metadata.Failure(step.Failure) == metadata.FailureIgnore {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -553,7 +553,7 @@ func TestRunBlockingStep(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := newDummyRuntime(t, newTestTracer(t))
|
||||
step := dummyStep("s1")
|
||||
step.Failure = metadata.FailureIgnore
|
||||
step.Failure = string(metadata.FailureIgnore)
|
||||
step.Environment[dummy.EnvKeyStepExitCode] = "1"
|
||||
|
||||
err := r.runBlockingStep(t.Context(), step)
|
||||
|
||||
@@ -17,6 +17,7 @@ package model
|
||||
|
||||
import (
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/errors"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/metadata"
|
||||
)
|
||||
|
||||
type Pipeline struct {
|
||||
@@ -100,7 +101,7 @@ func (p Pipeline) IsMultiPipeline() bool {
|
||||
|
||||
// IsPullRequest checks if it's a PR event.
|
||||
func (p Pipeline) IsPullRequest() bool {
|
||||
return p.Event == EventPull || p.Event == EventPullClosed || p.Event == EventPullMetadata
|
||||
return metadata.Event(p.Event).IsPull()
|
||||
}
|
||||
|
||||
type PipelineOptions struct {
|
||||
|
||||
@@ -18,11 +18,12 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
pipeline_errors "go.woodpecker-ci.org/woodpecker/v3/pipeline/errors"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/metadata"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/pipeline/frontend/yaml/constraint"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v3/server/forge"
|
||||
forge_types "go.woodpecker-ci.org/woodpecker/v3/server/forge/types"
|
||||
@@ -31,8 +32,6 @@ import (
|
||||
"go.woodpecker-ci.org/woodpecker/v3/version"
|
||||
)
|
||||
|
||||
var skipPipelineRegex = regexp.MustCompile(`\[(?i:ci *skip|skip *ci)\]`)
|
||||
|
||||
// Create a new pipeline and start it.
|
||||
func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline *model.Pipeline) (*model.Pipeline, error) {
|
||||
repoUser, err := _store.GetUser(repo.UserID)
|
||||
@@ -42,16 +41,13 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
|
||||
if pipeline.Event == model.EventPush || pipeline.IsPullRequest() {
|
||||
skipMatch := skipPipelineRegex.FindString(pipeline.Message)
|
||||
if len(skipMatch) > 0 {
|
||||
ref := pipeline.Commit
|
||||
if len(ref) == 0 {
|
||||
ref = pipeline.Ref
|
||||
}
|
||||
log.Debug().Str("repo", repo.FullName).Msgf("ignoring pipeline as skip-ci was found in the commit (%s) message '%s'", ref, pipeline.Message)
|
||||
return nil, ErrFiltered
|
||||
if constraint.IsSkipCommitMessage(metadata.Event(pipeline.Event), pipeline.Message) {
|
||||
ref := pipeline.Commit
|
||||
if len(ref) == 0 {
|
||||
ref = pipeline.Ref
|
||||
}
|
||||
log.Debug().Str("repo", repo.FullName).Msgf("ignoring pipeline as skip-ci was found in the commit (%s) message '%s'", ref, pipeline.Message)
|
||||
return nil, ErrFiltered
|
||||
}
|
||||
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
|
||||
@@ -53,9 +53,9 @@ func parsePipeline(ctx context.Context, forge forge.Forge, store store.Store, cu
|
||||
|
||||
var secrets []compiler.Secret
|
||||
for _, sec := range secs {
|
||||
var events []string
|
||||
var events []pipeline_metadata.Event
|
||||
for _, event := range sec.Events {
|
||||
events = append(events, string(event))
|
||||
events = append(events, pipeline_metadata.Event(event))
|
||||
}
|
||||
|
||||
secrets = append(secrets, compiler.Secret{
|
||||
|
||||
@@ -112,7 +112,7 @@ func metadataPipelineFromModelPipeline(pipeline *model.Pipeline, includeParent b
|
||||
Started: pipeline.Started,
|
||||
Finished: pipeline.Finished,
|
||||
Status: string(pipeline.Status),
|
||||
Event: string(pipeline.Event),
|
||||
Event: metadata.Event(pipeline.Event),
|
||||
EventReason: pipeline.EventReason,
|
||||
ForgeURL: pipeline.ForgeURL,
|
||||
DeployTo: pipeline.DeployTo,
|
||||
|
||||
Reference in New Issue
Block a user