Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore pipelines without config #2949

Merged
merged 12 commits into from
Dec 21, 2023
1 change: 1 addition & 0 deletions docs/docs/91-migrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Some versions need some changes to the server configuration or the pipeline conf
## `next`

- 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

## 2.0.0

Expand Down
25 changes: 14 additions & 11 deletions server/forge/configFetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ import (
"go.woodpecker-ci.org/woodpecker/v2/shared/constant"
)

type ErrConfigNotFound struct {
6543 marked this conversation as resolved.
Show resolved Hide resolved
configs []string
}

func (m *ErrConfigNotFound) Error() string {
6543 marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Sprintf("configs not found: %s", strings.Join(m.configs, ", "))
}

type ConfigFetcher interface {
Fetch(ctx context.Context) (files []*types.FileMeta, err error)
}
Expand Down Expand Up @@ -106,7 +114,7 @@ func (cf *configFetcher) fetch(c context.Context, timeout time.Duration, config
// could be adapted to allow the user to supply a list like we do in the defaults
configs := []string{config}

fileMeta, err := cf.getFirstAvailableConfig(ctx, configs, true)
fileMeta, err := cf.getFirstAvailableConfig(ctx, configs)
if err == nil {
return fileMeta, err
}
Expand All @@ -116,7 +124,7 @@ func (cf *configFetcher) fetch(c context.Context, timeout time.Duration, config

log.Trace().Msgf("ConfigFetch[%s]: user did not define own config, following default procedure", cf.repo.FullName)
// for the order see shared/constants/constants.go
fileMeta, err := cf.getFirstAvailableConfig(ctx, constant.DefaultConfigOrder[:], false)
fileMeta, err := cf.getFirstAvailableConfig(ctx, constant.DefaultConfigOrder[:])
if err == nil {
return fileMeta, err
}
Expand Down Expand Up @@ -156,12 +164,7 @@ func (cf *configFetcher) checkPipelineFile(c context.Context, config string) (fi
return nil, false
}

func (cf *configFetcher) getFirstAvailableConfig(c context.Context, configs []string, userDefined bool) ([]*types.FileMeta, error) {
userDefinedLog := ""
if userDefined {
userDefinedLog = "user defined"
}

func (cf *configFetcher) getFirstAvailableConfig(c context.Context, configs []string) ([]*types.FileMeta, error) {
for _, fileOrFolder := range configs {
if strings.HasSuffix(fileOrFolder, "/") {
// config is a folder
Expand All @@ -172,18 +175,18 @@ func (cf *configFetcher) getFirstAvailableConfig(c context.Context, configs []st
}
files = filterPipelineFiles(files)
if err == nil && len(files) != 0 {
log.Trace().Msgf("ConfigFetch[%s]: found %d %s files in '%s'", cf.repo.FullName, len(files), userDefinedLog, fileOrFolder)
log.Trace().Msgf("ConfigFetch[%s]: found %d files in '%s'", cf.repo.FullName, len(files), fileOrFolder)
return files, nil
}
}

// config is a file
if fileMeta, found := cf.checkPipelineFile(c, fileOrFolder); found {
log.Trace().Msgf("ConfigFetch[%s]: found %s file: '%s'", cf.repo.FullName, userDefinedLog, fileOrFolder)
log.Trace().Msgf("ConfigFetch[%s]: found file: '%s'", cf.repo.FullName, fileOrFolder)
return fileMeta, nil
}
}

// nothing found
return nil, fmt.Errorf("%s configs not found searched: %s", userDefinedLog, strings.Join(configs, ", "))
return nil, &ErrConfigNotFound{configs: configs}
6543 marked this conversation as resolved.
Show resolved Hide resolved
}
19 changes: 13 additions & 6 deletions server/pipeline/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@

import (
"context"
"errors"
"fmt"
"regexp"
"time"

"github.com/rs/zerolog/log"

"go.woodpecker-ci.org/woodpecker/v2/pipeline/errors"
pipelineErrors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors"
6543 marked this conversation as resolved.
Show resolved Hide resolved
"go.woodpecker-ci.org/woodpecker/v2/server"
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
Expand Down Expand Up @@ -65,18 +66,24 @@
// fetch the pipeline file from the forge
configFetcher := forge.NewConfigFetcher(server.Config.Services.Forge, server.Config.Services.Timeout, server.Config.Services.ConfigService, repoUser, repo, pipeline)
forgeYamlConfigs, configFetchErr := configFetcher.Fetch(ctx)

if configFetchErr != nil {
if errors.Is(configFetchErr, &forge.ErrConfigNotFound{}) {

Check warning on line 69 in server/pipeline/create.go

View check run for this annotation

Codecov / codecov/patch

server/pipeline/create.go#L69

Added line #L69 was not covered by tests
log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("cannot find config '%s' in '%s' with user: '%s'", repo.Config, pipeline.Ref, repoUser.Login)
if err := _store.DeletePipeline(pipeline); err != nil {
log.Error().Str("repo", repo.FullName).Err(err).Msg("failed to delete pipeline without config")
}

Check warning on line 73 in server/pipeline/create.go

View check run for this annotation

Codecov / codecov/patch

server/pipeline/create.go#L71-L73

Added lines #L71 - L73 were not covered by tests

return nil, ErrFiltered
} else if configFetchErr != nil {
log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("error while fetching config '%s' in '%s' with user: '%s'", repo.Config, pipeline.Ref, repoUser.Login)

Check warning on line 77 in server/pipeline/create.go

View check run for this annotation

Codecov / codecov/patch

server/pipeline/create.go#L75-L77

Added lines #L75 - L77 were not covered by tests
return nil, updatePipelineWithErr(ctx, _store, pipeline, repo, repoUser, fmt.Errorf("pipeline definition not found in %s", repo.FullName))
}

pipelineItems, parseErr := parsePipeline(_store, pipeline, repoUser, repo, forgeYamlConfigs, nil)
if errors.HasBlockingErrors(parseErr) {
if pipelineErrors.HasBlockingErrors(parseErr) {

Check warning on line 82 in server/pipeline/create.go

View check run for this annotation

Codecov / codecov/patch

server/pipeline/create.go#L82

Added line #L82 was not covered by tests
log.Debug().Str("repo", repo.FullName).Err(parseErr).Msg("failed to parse yaml")
return nil, updatePipelineWithErr(ctx, _store, pipeline, repo, repoUser, parseErr)
} else if parseErr != nil {
pipeline.Errors = errors.GetPipelineErrors(parseErr)
pipeline.Errors = pipelineErrors.GetPipelineErrors(parseErr)

Check warning on line 86 in server/pipeline/create.go

View check run for this annotation

Codecov / codecov/patch

server/pipeline/create.go#L86

Added line #L86 was not covered by tests
}

if len(pipelineItems) == 0 {
Expand Down Expand Up @@ -131,7 +138,7 @@
pipeline.Started = time.Now().Unix()
pipeline.Finished = pipeline.Started
pipeline.Status = model.StatusError
pipeline.Errors = errors.GetPipelineErrors(err)
pipeline.Errors = pipelineErrors.GetPipelineErrors(err)

Check warning on line 141 in server/pipeline/create.go

View check run for this annotation

Codecov / codecov/patch

server/pipeline/create.go#L141

Added line #L141 was not covered by tests
dbErr := _store.UpdatePipeline(pipeline)
if dbErr != nil {
msg := fmt.Errorf("failed to save pipeline for %s", repo.FullName)
Expand Down