1
0
mirror of https://github.com/woodpecker-ci/woodpecker.git synced 2026-06-03 16:35:37 +02:00

Add config to change default pipeline config paths and extensions (#6580)

Signed-off-by: jolheiser <git@jolheiser.com>
This commit is contained in:
John Olheiser
2026-05-26 12:57:39 -05:00
committed by GitHub
parent b6880141e2
commit 23102152fb
8 changed files with 76 additions and 24 deletions
+18
View File
@@ -291,6 +291,24 @@ var flags = append([]cli.Flag{
Name: "config-extension-netrc",
Usage: "whether global configuration extension should receive netrc data",
},
&cli.StringSliceFlag{
Sources: cli.EnvVars("WOODPECKER_DEFAULT_PIPELINE_CONFIGS"),
Name: "default-pipeline-configs",
Usage: "default pipeline config paths to check",
Value: constant.DefaultConfigOrder,
Config: cli.StringConfig{
TrimSpace: true,
},
},
&cli.StringSliceFlag{
Sources: cli.EnvVars("WOODPECKER_DEFAULT_PIPELINE_CONFIG_EXTENSIONS"),
Name: "default-pipeline-config-extensions",
Usage: "default pipeline config extensions when scanning a pipeline config directory",
Value: []string{".yaml", ".yml"},
Config: cli.StringConfig{
TrimSpace: true,
},
},
&cli.StringFlag{
Sources: cli.EnvVars("WOODPECKER_REGISTRY_EXTENSION_ENDPOINT"),
Name: "registry-extension-endpoint",
@@ -980,6 +980,24 @@ Specify a configuration extension endpoint, see [Configuration Extension](../../
---
### DEFAULT_PIPELINE_CONFIGS
- Name: `WOODPECKER_DEFAULT_PIPELINE_CONFIGS`
- Default: `.woodpecker/`, `.woodpecker.yaml`, `.woodpecker.yml`
Specify the default pipeline config paths.
---
### DEFAULT_PIPELINE_CONFIG_EXTENSIONS
- Name: `WOODPECKER_DEFAULT_PIPELINE_CONFIG_EXTENSIONS`
- Default: `.yaml`, `.yml`
Specify the default pipeline config extensions when scanning a pipeline config directory.
---
### CONFIG_EXTENSION_EXCLUSIVE
- Name: `CONFIG_EXTENSION_EXCLUSIVE`
+3
View File
@@ -43,6 +43,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v3/server/services"
"go.woodpecker-ci.org/woodpecker/v3/server/services/permissions"
"go.woodpecker-ci.org/woodpecker/v3/server/store"
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
)
const (
@@ -151,6 +152,8 @@ func newTestManager(s store.Store, mockForge *forge_mocks.MockForge) (services.M
// Forge flags — gitea=true satisfies setupForgeService's type switch.
&cli.BoolFlag{Name: string(TestForgeType), Value: true},
&cli.StringFlag{Name: "forge-url", Value: "https://forge.example.test"},
&cli.StringSliceFlag{Name: "default-pipeline-configs", Value: constant.DefaultConfigOrder},
&cli.StringSliceFlag{Name: "default-pipeline-config-extensions", Value: []string{".yaml", ".yml"}},
},
}
+2 -1
View File
@@ -36,6 +36,7 @@ import (
"go.woodpecker-ci.org/woodpecker/v3/server/model"
"go.woodpecker-ci.org/woodpecker/v3/server/services/config"
"go.woodpecker-ci.org/woodpecker/v3/server/services/utils"
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
)
func TestFetchFromConfigService(t *testing.T) {
@@ -220,7 +221,7 @@ func TestFetchFromConfigService(t *testing.T) {
f.On("Netrc", mock.Anything, mock.Anything).Return(&model.Netrc{Machine: "mock", Login: "mock", Password: "mock"}, nil)
forgeFetcher := config.NewForge(time.Second*3, 3)
forgeFetcher := config.NewForge(time.Second*3, 3, constant.DefaultConfigOrder, []string{".yaml", ".yml"})
configFetcher := config.NewCombined(forgeFetcher, httpFetcher)
files, err := configFetcher.Fetch(
t.Context(),
+29 -20
View File
@@ -18,6 +18,8 @@ import (
"context"
"errors"
"fmt"
"path/filepath"
"slices"
"strings"
"time"
@@ -26,18 +28,21 @@ import (
"go.woodpecker-ci.org/woodpecker/v3/server/forge"
"go.woodpecker-ci.org/woodpecker/v3/server/forge/types"
"go.woodpecker-ci.org/woodpecker/v3/server/model"
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
)
type forgeFetcher struct {
timeout time.Duration
retryCount uint
timeout time.Duration
retryCount uint
configPaths []string
configExtensions []string
}
func NewForge(timeout time.Duration, retries uint) Service {
func NewForge(timeout time.Duration, retries uint, configPaths, configExtensions []string) Service {
return &forgeFetcher{
timeout: timeout,
retryCount: retries,
timeout: timeout,
retryCount: retries,
configPaths: configPaths,
configExtensions: configExtensions,
}
}
@@ -48,11 +53,13 @@ func (f *forgeFetcher) Fetch(ctx context.Context, forge forge.Forge, user *model
}
ffc := &forgeFetcherContext{
forge: forge,
user: user,
repo: repo,
pipeline: pipeline,
timeout: f.timeout,
forge: forge,
user: user,
repo: repo,
pipeline: pipeline,
timeout: f.timeout,
configPaths: f.configPaths,
configExtensions: f.configExtensions,
}
// try to fetch multiple times
@@ -69,11 +76,13 @@ func (f *forgeFetcher) Fetch(ctx context.Context, forge forge.Forge, user *model
}
type forgeFetcherContext struct {
forge forge.Forge
user *model.User
repo *model.Repo
pipeline *model.Pipeline
timeout time.Duration
forge forge.Forge
user *model.User
repo *model.Repo
pipeline *model.Pipeline
timeout time.Duration
configPaths []string
configExtensions []string
}
// fetch attempts to fetch the configuration file(s) for the given config string.
@@ -97,7 +106,7 @@ func (f *forgeFetcherContext) fetch(c context.Context, config string) ([]*types.
log.Trace().Msgf("configFetcher[%s]: user did not define own config, following default procedure", f.repo.FullName)
// for the order see shared/constants/constants.go
fileMetas, err := f.getFirstAvailableConfig(ctx, constant.DefaultConfigOrder[:])
fileMetas, err := f.getFirstAvailableConfig(ctx, f.configPaths)
if err == nil {
return fileMetas, nil
}
@@ -110,11 +119,11 @@ func (f *forgeFetcherContext) fetch(c context.Context, config string) ([]*types.
}
}
func filterPipelineFiles(files []*types.FileMeta) []*types.FileMeta {
func (f *forgeFetcherContext) filterPipelineFiles(files []*types.FileMeta) []*types.FileMeta {
var res []*types.FileMeta
for _, file := range files {
if strings.HasSuffix(file.Name, ".yml") || strings.HasSuffix(file.Name, ".yaml") {
if slices.Contains(f.configExtensions, filepath.Ext(file.Name)) {
res = append(res, file)
}
}
@@ -154,7 +163,7 @@ func (f *forgeFetcherContext) getFirstAvailableConfig(c context.Context, configs
}
continue
}
files = filterPipelineFiles(files)
files = f.filterPipelineFiles(files)
if len(files) != 0 {
log.Trace().Msgf("configFetcher[%s]: found %d files in '%s'", f.repo.FullName, len(files), fileOrFolder)
return files, nil
+3
View File
@@ -27,6 +27,7 @@ import (
forge_types "go.woodpecker-ci.org/woodpecker/v3/server/forge/types"
"go.woodpecker-ci.org/woodpecker/v3/server/model"
"go.woodpecker-ci.org/woodpecker/v3/server/services/config"
"go.woodpecker-ci.org/woodpecker/v3/shared/constant"
)
func TestFetch(t *testing.T) {
@@ -307,6 +308,8 @@ func TestFetch(t *testing.T) {
configFetcher := config.NewForge(
time.Second*3,
3,
constant.DefaultConfigOrder,
[]string{".yaml", ".yml"},
)
files, err := configFetcher.Fetch(
t.Context(),
+1 -1
View File
@@ -76,7 +76,7 @@ func setupConfigService(c *cli.Command, client *utils.Client) (config.Service, e
if retries == 0 {
return nil, fmt.Errorf("WOODPECKER_FORGE_RETRY can not be 0")
}
configFetcher := config.NewForge(timeout, retries)
configFetcher := config.NewForge(timeout, retries, c.StringSlice("default-pipeline-configs"), c.StringSlice("default-pipeline-config-extensions"))
if endpoint := c.String("config-extension-endpoint"); endpoint != "" {
httpFetcher := config.NewHTTP(endpoint, client, c.Bool("config-extension-netrc"))
+2 -2
View File
@@ -16,9 +16,9 @@ package constant
import "time"
// DefaultConfigOrder represent the priority in witch woodpecker search for a pipeline config by default
// DefaultConfigOrder represent the priority in which woodpecker searches for a pipeline config by default
// folders are indicated by supplying a trailing slash.
var DefaultConfigOrder = [...]string{
var DefaultConfigOrder = []string{
".woodpecker/",
".woodpecker.yaml",
".woodpecker.yml",