mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-06-05 08:58:50 +00:00
Merge branch 'main' into fix/code-highlight-colors
This commit is contained in:
commit
3662bfc94e
260 changed files with 5689 additions and 3113 deletions
|
@ -10,7 +10,7 @@ repos:
|
|||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/golangci/golangci-lint
|
||||
rev: v1.62.0
|
||||
rev: v1.62.2
|
||||
hooks:
|
||||
- id: golangci-lint
|
||||
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||
|
|
|
@ -99,7 +99,7 @@ steps:
|
|||
release:
|
||||
depends_on:
|
||||
- checksums
|
||||
image: woodpeckerci/plugin-release:0.2.1
|
||||
image: woodpeckerci/plugin-release:0.2.2
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: github_token
|
||||
|
|
|
@ -59,7 +59,7 @@ steps:
|
|||
- event: manual
|
||||
|
||||
deploy-preview:
|
||||
image: docker.io/woodpeckerci/plugin-surge-preview:1.3.2
|
||||
image: docker.io/woodpeckerci/plugin-surge-preview:1.3.3
|
||||
settings:
|
||||
path: 'docs/build/'
|
||||
surge_token:
|
||||
|
|
|
@ -17,14 +17,20 @@ package admin
|
|||
import (
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/admin/loglevel"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/admin/registry"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/admin/secret"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/admin/user"
|
||||
)
|
||||
|
||||
// Command exports the admin command set.
|
||||
var Command = &cli.Command{
|
||||
Name: "admin",
|
||||
Usage: "administer server settings",
|
||||
Usage: "manage server settings",
|
||||
Commands: []*cli.Command{
|
||||
loglevel.Command,
|
||||
registry.Command,
|
||||
secret.Command,
|
||||
user.Command,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import (
|
|||
var Command = &cli.Command{
|
||||
Name: "log-level",
|
||||
ArgsUsage: "[level]",
|
||||
Usage: "get the logging level of the server, or set it with [level]",
|
||||
Usage: "retrieve log level from server, or set it with [level]",
|
||||
Action: logLevel,
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,6 @@ func logLevel(ctx context.Context, c *cli.Command) error {
|
|||
}
|
||||
}
|
||||
|
||||
log.Info().Msgf("logging level: %s", ll.Level)
|
||||
log.Info().Msgf("log level: %s", ll.Level)
|
||||
return nil
|
||||
}
|
|
@ -25,8 +25,8 @@ var Command = &cli.Command{
|
|||
Commands: []*cli.Command{
|
||||
registryCreateCmd,
|
||||
registryDeleteCmd,
|
||||
registryUpdateCmd,
|
||||
registryInfoCmd,
|
||||
registryListCmd,
|
||||
registryShowCmd,
|
||||
registryUpdateCmd,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import (
|
|||
|
||||
var registryCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a registry",
|
||||
Usage: "add a registry",
|
||||
Action: registryCreate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var registryListCmd = &cli.Command{
|
||||
|
@ -42,7 +43,9 @@ func registryList(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
list, err := client.GlobalRegistryList()
|
||||
opt := woodpecker.RegistryListOptions{}
|
||||
|
||||
list, err := client.GlobalRegistryList(opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var registryInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "display registry info",
|
||||
Action: registryInfo,
|
||||
var registryShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show registry information",
|
||||
Action: registryShow,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "hostname",
|
||||
|
@ -39,7 +39,7 @@ var registryInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryInfo(ctx context.Context, c *cli.Command) error {
|
||||
func registryShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
hostname = c.String("hostname")
|
||||
format = c.String("format") + "\n"
|
32
cli/admin/secret/secret.go
Normal file
32
cli/admin/secret/secret.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
// Command exports the secret command.
|
||||
var Command = &cli.Command{
|
||||
Name: "secret",
|
||||
Usage: "manage global secrets",
|
||||
Commands: []*cli.Command{
|
||||
secretCreateCmd,
|
||||
secretDeleteCmd,
|
||||
secretListCmd,
|
||||
secretShowCmd,
|
||||
secretUpdateCmd,
|
||||
},
|
||||
}
|
82
cli/admin/secret/secret_add.go
Normal file
82
cli/admin/secret/secret_add.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "add a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretCreate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "value",
|
||||
Usage: "secret value",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "event",
|
||||
Usage: "secret limited to these events",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "image",
|
||||
Usage: "secret limited to these images",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretCreate(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := &woodpecker.Secret{
|
||||
Name: strings.ToLower(c.String("name")),
|
||||
Value: c.String("value"),
|
||||
Images: c.StringSlice("image"),
|
||||
Events: c.StringSlice("event"),
|
||||
}
|
||||
if len(secret.Events) == 0 {
|
||||
secret.Events = defaultSecretEvents
|
||||
}
|
||||
if strings.HasPrefix(secret.Value, "@") {
|
||||
path := strings.TrimPrefix(secret.Value, "@")
|
||||
out, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
_, err = client.GlobalSecretCreate(secret)
|
||||
return err
|
||||
}
|
||||
|
||||
var defaultSecretEvents = []string{
|
||||
woodpecker.EventPush,
|
||||
woodpecker.EventTag,
|
||||
woodpecker.EventRelease,
|
||||
woodpecker.EventDeploy,
|
||||
}
|
|
@ -33,12 +33,6 @@ var secretListCmd = &cli.Command{
|
|||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretList,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "global",
|
||||
Usage: "global secret",
|
||||
},
|
||||
common.OrgFlag,
|
||||
common.RepoFlag,
|
||||
common.FormatFlag(tmplSecretList, true),
|
||||
},
|
||||
}
|
||||
|
@ -51,30 +45,13 @@ func secretList(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
global, orgID, repoID, err := parseTargetArgs(client, c)
|
||||
opt := woodpecker.SecretListOptions{}
|
||||
|
||||
list, err := client.GlobalSecretList(opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var list []*woodpecker.Secret
|
||||
switch {
|
||||
case global:
|
||||
list, err = client.GlobalSecretList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case orgID != -1:
|
||||
list, err = client.OrgSecretList(orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
list, err = client.SecretList(repoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||
if err != nil {
|
||||
return err
|
47
cli/admin/secret/secret_rm.go
Normal file
47
cli/admin/secret/secret_rm.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var secretDeleteCmd = &cli.Command{
|
||||
Name: "rm",
|
||||
Usage: "remove a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretDelete,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretDelete(ctx context.Context, c *cli.Command) error {
|
||||
secretName := c.String("name")
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.GlobalSecretDelete(secretName)
|
||||
}
|
76
cli/admin/secret/secret_set.go
Normal file
76
cli/admin/secret/secret_set.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretUpdateCmd = &cli.Command{
|
||||
Name: "update",
|
||||
Usage: "update a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretUpdate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "value",
|
||||
Usage: "secret value",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "event",
|
||||
Usage: "secret limited to these events",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "image",
|
||||
Usage: "secret limited to these images",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretUpdate(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := &woodpecker.Secret{
|
||||
Name: strings.ToLower(c.String("name")),
|
||||
Value: c.String("value"),
|
||||
Images: c.StringSlice("image"),
|
||||
Events: c.StringSlice("event"),
|
||||
}
|
||||
if strings.HasPrefix(secret.Value, "@") {
|
||||
path := strings.TrimPrefix(secret.Value, "@")
|
||||
out, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
_, err = client.GlobalSecretUpdate(secret)
|
||||
return err
|
||||
}
|
68
cli/admin/secret/secret_show.go
Normal file
68
cli/admin/secret/secret_show.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var secretShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show secret information",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretShow,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
common.FormatFlag(tmplSecretList, true),
|
||||
},
|
||||
}
|
||||
|
||||
func secretShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
secretName = c.String("name")
|
||||
format = c.String("format") + "\n"
|
||||
)
|
||||
|
||||
if secretName == "" {
|
||||
return fmt.Errorf("secret name is missing")
|
||||
}
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret, err := client.GlobalSecret(secretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, secret)
|
||||
}
|
|
@ -23,9 +23,9 @@ var Command = &cli.Command{
|
|||
Name: "user",
|
||||
Usage: "manage users",
|
||||
Commands: []*cli.Command{
|
||||
userListCmd,
|
||||
userInfoCmd,
|
||||
userAddCmd,
|
||||
userListCmd,
|
||||
userRemoveCmd,
|
||||
userShowCmd,
|
||||
},
|
||||
}
|
|
@ -26,7 +26,7 @@ import (
|
|||
|
||||
var userAddCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a user",
|
||||
Usage: "add a user",
|
||||
ArgsUsage: "<username>",
|
||||
Action: userAdd,
|
||||
}
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var userListCmd = &cli.Command{
|
||||
|
@ -39,7 +40,9 @@ func userList(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
users, err := client.UserList()
|
||||
opt := woodpecker.UserListOptions{}
|
||||
|
||||
users, err := client.UserList(opt)
|
||||
if err != nil || len(users) == 0 {
|
||||
return err
|
||||
}
|
|
@ -26,15 +26,15 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var userInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "show user details",
|
||||
var userShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show user information",
|
||||
ArgsUsage: "<username>",
|
||||
Action: userInfo,
|
||||
Action: userShow,
|
||||
Flags: []cli.Flag{common.FormatFlag(tmplUserInfo)},
|
||||
}
|
||||
|
||||
func userInfo(ctx context.Context, c *cli.Command) error {
|
||||
func userShow(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
|
@ -35,18 +35,18 @@ func Before(ctx context.Context, c *cli.Command) (context.Context, error) {
|
|||
waitForUpdateCheck, cancelWaitForUpdate = context.WithCancelCause(context.Background())
|
||||
defer cancelWaitForUpdate(errors.New("update check finished"))
|
||||
|
||||
log.Debug().Msg("Checking for updates ...")
|
||||
log.Debug().Msg("checking for updates ...")
|
||||
|
||||
newVersion, err := update.CheckForUpdate(waitForUpdateCheck, false) //nolint:contextcheck
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Failed to check for updates")
|
||||
log.Error().Err(err).Msgf("failed to check for updates")
|
||||
return
|
||||
}
|
||||
|
||||
if newVersion != nil {
|
||||
log.Warn().Msgf("A new version of woodpecker-cli is available: %s. Update by running: %s update", newVersion.Version, c.Root().Name)
|
||||
log.Warn().Msgf("new version of woodpecker-cli is available: %s, update with: %s update", newVersion.Version, c.Root().Name)
|
||||
} else {
|
||||
log.Debug().Msgf("No update required")
|
||||
log.Debug().Msgf("no update required")
|
||||
}
|
||||
}(ctx)
|
||||
|
||||
|
@ -59,7 +59,7 @@ func After(_ context.Context, _ *cli.Command) error {
|
|||
case <-waitForUpdateCheck.Done():
|
||||
// When the actual command already finished, we still wait 500ms for the update check to finish
|
||||
case <-time.After(time.Millisecond * 500):
|
||||
log.Debug().Msg("Update check stopped due to timeout")
|
||||
log.Debug().Msg("update check stopped due to timeout")
|
||||
cancelWaitForUpdate(errors.New("update check timeout"))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ func Load(ctx context.Context, c *cli.Command) error {
|
|||
}
|
||||
|
||||
if config.ServerURL == "" || config.Token == "" {
|
||||
log.Info().Msg("The woodpecker-cli is not yet set up. Please run `woodpecker-cli setup` or provide the required environment variables / flags.")
|
||||
log.Info().Msg("woodpecker-cli is not set up, run `woodpecker-cli setup` or provide required environment variables/flags")
|
||||
return errors.New("woodpecker-cli is not configured")
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ func Load(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Debug().Any("config", config).Msg("Loaded config")
|
||||
log.Debug().Any("config", config).Msg("loaded config")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -93,16 +93,16 @@ func Get(_ context.Context, c *cli.Command, _configPath string) (*Config, error)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug().Str("configPath", configPath).Msg("Checking for config file")
|
||||
log.Debug().Str("configPath", configPath).Msg("checking for config file")
|
||||
|
||||
content, err := os.ReadFile(configPath)
|
||||
switch {
|
||||
case err != nil && !os.IsNotExist(err):
|
||||
log.Debug().Err(err).Msg("Failed to read the config file")
|
||||
log.Debug().Err(err).Msg("failed to read the config file")
|
||||
return nil, err
|
||||
|
||||
case err != nil && os.IsNotExist(err):
|
||||
log.Debug().Msg("The config file does not exist")
|
||||
log.Debug().Msg("config file does not exist")
|
||||
|
||||
default:
|
||||
configFromFile := &Config{}
|
||||
|
@ -111,7 +111,7 @@ func Get(_ context.Context, c *cli.Command, _configPath string) (*Config, error)
|
|||
return nil, err
|
||||
}
|
||||
conf.MergeIfNotSet(configFromFile)
|
||||
log.Debug().Msg("Loaded config from file")
|
||||
log.Debug().Msg("loaded config from file")
|
||||
}
|
||||
|
||||
// if server or token are explicitly set, use them
|
||||
|
@ -123,11 +123,11 @@ func Get(_ context.Context, c *cli.Command, _configPath string) (*Config, error)
|
|||
service := c.Root().Name
|
||||
secret, err := keyring.Get(service, conf.ServerURL)
|
||||
if errors.Is(err, keyring.ErrUnsupportedPlatform) {
|
||||
log.Warn().Msg("Keyring is not supported on this platform")
|
||||
log.Warn().Msg("keyring is not supported on this platform")
|
||||
return conf, nil
|
||||
}
|
||||
if errors.Is(err, keyring.ErrNotFound) {
|
||||
log.Warn().Msg("Token not found in keyring")
|
||||
log.Warn().Msg("token not found in keyring")
|
||||
return conf, nil
|
||||
}
|
||||
conf.Token = secret
|
||||
|
|
|
@ -40,12 +40,12 @@ var Command = &cli.Command{
|
|||
&cli.StringSliceFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_PLUGINS_PRIVILEGED"),
|
||||
Name: "plugins-privileged",
|
||||
Usage: "Allow plugins to run in privileged mode, if environment variable is defined but empty there will be none",
|
||||
Usage: "allow plugins to run in privileged mode, if set empty, there is no",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_PLUGINS_TRUSTED_CLONE"),
|
||||
Name: "plugins-trusted-clone",
|
||||
Usage: "Plugins which are trusted to handle Git credentials in clone steps",
|
||||
Usage: "plugins that are trusted to handle Git credentials in cloning steps",
|
||||
Value: constant.TrustedClonePlugins,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/org/registry"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/org/secret"
|
||||
)
|
||||
|
||||
// Command exports the org command set.
|
||||
|
@ -26,5 +27,6 @@ var Command = &cli.Command{
|
|||
Usage: "manage organizations",
|
||||
Commands: []*cli.Command{
|
||||
registry.Command,
|
||||
secret.Command,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ var Command = &cli.Command{
|
|||
Commands: []*cli.Command{
|
||||
registryCreateCmd,
|
||||
registryDeleteCmd,
|
||||
registryUpdateCmd,
|
||||
registryInfoCmd,
|
||||
registryListCmd,
|
||||
registryShowCmd,
|
||||
registryUpdateCmd,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import (
|
|||
|
||||
var registryCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a registry",
|
||||
Usage: "add a registry",
|
||||
ArgsUsage: "[org-id|org-full-name]",
|
||||
Action: registryCreate,
|
||||
Flags: []cli.Flag{
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var registryListCmd = &cli.Command{
|
||||
|
@ -49,7 +50,9 @@ func registryList(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
list, err := client.OrgRegistryList(orgID)
|
||||
opt := woodpecker.RegistryListOptions{}
|
||||
|
||||
list, err := client.OrgRegistryList(orgID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var registryInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "display registry info",
|
||||
var registryShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show registry information",
|
||||
ArgsUsage: "[org-id|org-full-name]",
|
||||
Action: registryInfo,
|
||||
Action: registryShow,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
&cli.StringFlag{
|
||||
|
@ -41,7 +41,7 @@ var registryInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryInfo(ctx context.Context, c *cli.Command) error {
|
||||
func registryShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
hostname = c.String("hostname")
|
||||
format = c.String("format") + "\n"
|
60
cli/org/secret/secret.go
Normal file
60
cli/org/secret/secret.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
// Command exports the secret command.
|
||||
var Command = &cli.Command{
|
||||
Name: "secret",
|
||||
Usage: "manage secrets",
|
||||
Commands: []*cli.Command{
|
||||
secretCreateCmd,
|
||||
secretDeleteCmd,
|
||||
secretListCmd,
|
||||
secretShowCmd,
|
||||
secretUpdateCmd,
|
||||
},
|
||||
}
|
||||
|
||||
func parseTargetArgs(client woodpecker.Client, c *cli.Command) (orgID int64, err error) {
|
||||
orgIDOrName := c.String("organization")
|
||||
if orgIDOrName == "" {
|
||||
orgIDOrName = c.Args().First()
|
||||
}
|
||||
|
||||
if orgIDOrName == "" {
|
||||
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
|
||||
if orgID, err := strconv.ParseInt(orgIDOrName, 10, 64); err == nil {
|
||||
return orgID, nil
|
||||
}
|
||||
|
||||
org, err := client.OrgLookup(orgIDOrName)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return org.ID, nil
|
||||
}
|
|
@ -28,16 +28,11 @@ import (
|
|||
|
||||
var secretCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a secret",
|
||||
Usage: "add a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretCreate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "global",
|
||||
Usage: "global secret",
|
||||
},
|
||||
common.OrgFlag,
|
||||
common.RepoFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
|
@ -81,22 +76,12 @@ func secretCreate(ctx context.Context, c *cli.Command) error {
|
|||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
global, orgID, repoID, err := parseTargetArgs(client, c)
|
||||
orgID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if global {
|
||||
_, err = client.GlobalSecretCreate(secret)
|
||||
return err
|
||||
}
|
||||
|
||||
if orgID != -1 {
|
||||
_, err = client.OrgSecretCreate(orgID, secret)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.SecretCreate(repoID, secret)
|
||||
_, err = client.OrgSecretCreate(orgID, secret)
|
||||
return err
|
||||
}
|
||||
|
87
cli/org/secret/secret_list.go
Normal file
87
cli/org/secret/secret_list.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretListCmd = &cli.Command{
|
||||
Name: "ls",
|
||||
Usage: "list secrets",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretList,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
common.FormatFlag(tmplSecretList, true),
|
||||
},
|
||||
}
|
||||
|
||||
func secretList(ctx context.Context, c *cli.Command) error {
|
||||
format := c.String("format") + "\n"
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
orgID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opt := woodpecker.SecretListOptions{}
|
||||
|
||||
list, err := client.OrgSecretList(orgID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, secret := range list {
|
||||
if err := tmpl.Execute(os.Stdout, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Template for secret list items.
|
||||
var tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + `
|
||||
Events: {{ list .Events }}
|
||||
{{- if .Images }}
|
||||
Images: {{ list .Images }}
|
||||
{{- else }}
|
||||
Images: <any>
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
var secretFuncMap = template.FuncMap{
|
||||
"list": func(s []string) string {
|
||||
return strings.Join(s, ", ")
|
||||
},
|
||||
}
|
54
cli/org/secret/secret_rm.go
Normal file
54
cli/org/secret/secret_rm.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var secretDeleteCmd = &cli.Command{
|
||||
Name: "rm",
|
||||
Usage: "remove a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretDelete,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretDelete(ctx context.Context, c *cli.Command) error {
|
||||
secretName := c.String("name")
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
orgID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.OrgSecretDelete(orgID, secretName)
|
||||
}
|
83
cli/org/secret/secret_set.go
Normal file
83
cli/org/secret/secret_set.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretUpdateCmd = &cli.Command{
|
||||
Name: "update",
|
||||
Usage: "update a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretUpdate,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "value",
|
||||
Usage: "secret value",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "event",
|
||||
Usage: "limit secret to these event",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "image",
|
||||
Usage: "limit secret to these image",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretUpdate(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := &woodpecker.Secret{
|
||||
Name: strings.ToLower(c.String("name")),
|
||||
Value: c.String("value"),
|
||||
Images: c.StringSlice("image"),
|
||||
Events: c.StringSlice("event"),
|
||||
}
|
||||
if strings.HasPrefix(secret.Value, "@") {
|
||||
path := strings.TrimPrefix(secret.Value, "@")
|
||||
out, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
orgID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.OrgSecretUpdate(orgID, secret)
|
||||
return err
|
||||
}
|
74
cli/org/secret/secret_show.go
Normal file
74
cli/org/secret/secret_show.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var secretShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show secret information",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretShow,
|
||||
Flags: []cli.Flag{
|
||||
common.OrgFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
common.FormatFlag(tmplSecretList, true),
|
||||
},
|
||||
}
|
||||
|
||||
func secretShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
secretName = c.String("name")
|
||||
format = c.String("format") + "\n"
|
||||
)
|
||||
|
||||
if secretName == "" {
|
||||
return fmt.Errorf("secret name is missing")
|
||||
}
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
orgID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret, err := client.OrgSecret(orgID, secretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return tmpl.Execute(os.Stdout, secret)
|
||||
}
|
|
@ -147,12 +147,12 @@ func (o *Table) Write(columns []string, obj any) error {
|
|||
colName := strings.ToLower(col)
|
||||
if alias, ok := o.fieldAlias[colName]; ok {
|
||||
if fn, ok := o.fieldMapping[alias]; ok {
|
||||
out = append(out, fn(obj))
|
||||
out = append(out, sanitizeString(fn(obj)))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if fn, ok := o.fieldMapping[colName]; ok {
|
||||
out = append(out, fn(obj))
|
||||
out = append(out, sanitizeString(fn(obj)))
|
||||
continue
|
||||
}
|
||||
if value, ok := dataL[strings.ReplaceAll(colName, "_", "")]; ok {
|
||||
|
@ -165,10 +165,10 @@ func (o *Table) Write(columns []string, obj any) error {
|
|||
continue
|
||||
}
|
||||
if s, ok := value.(string); ok {
|
||||
out = append(out, NA(s))
|
||||
out = append(out, NA(sanitizeString(s)))
|
||||
continue
|
||||
}
|
||||
out = append(out, fmt.Sprintf("%v", value))
|
||||
out = append(out, sanitizeString(value))
|
||||
}
|
||||
}
|
||||
_, _ = fmt.Fprintln(o.w, strings.Join(out, "\t"))
|
||||
|
@ -201,3 +201,9 @@ func fieldName(name string) string {
|
|||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func sanitizeString(value any) string {
|
||||
str := fmt.Sprintf("%v", value)
|
||||
replacer := strings.NewReplacer("\n", " ", "\r", " ")
|
||||
return strings.TrimSpace(replacer.Replace(str))
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ var Command = &cli.Command{
|
|||
&cli.StringSliceFlag{
|
||||
Name: "param",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "custom parameters to be injected into the step environment. Format: KEY=value",
|
||||
Usage: "custom parameters to inject into the step environment. Format: KEY=value",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -80,14 +80,14 @@ func deploy(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
branch = repo.DefaultBranch
|
||||
branch = repo.Branch
|
||||
}
|
||||
|
||||
pipelineArg := c.Args().Get(1)
|
||||
var number int64
|
||||
if pipelineArg == "last" {
|
||||
// Fetch the pipeline number from the last pipeline
|
||||
pipelines, err := client.PipelineList(repoID)
|
||||
pipelines, err := client.PipelineList(repoID, woodpecker.PipelineListOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -121,9 +121,12 @@ func deploy(ctx context.Context, c *cli.Command) error {
|
|||
return fmt.Errorf("please specify the target environment (i.e. production)")
|
||||
}
|
||||
|
||||
params := internal.ParseKeyPair(c.StringSlice("param"))
|
||||
opt := woodpecker.DeployOptions{
|
||||
DeployTo: env,
|
||||
Params: internal.ParseKeyPair(c.StringSlice("param")),
|
||||
}
|
||||
|
||||
deploy, err := client.Deploy(repoID, number, env, params)
|
||||
deploy, err := client.Deploy(repoID, number, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -48,7 +48,7 @@ func pipelineKill(ctx context.Context, c *cli.Command) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
err = client.PipelineKill(repoID, number)
|
||||
err = client.PipelineDelete(repoID, number)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
|
||||
var pipelineLastCmd = &cli.Command{
|
||||
Name: "last",
|
||||
Usage: "show latest pipeline details",
|
||||
Usage: "show latest pipeline information",
|
||||
ArgsUsage: "<repo-id|repo-full-name>",
|
||||
Action: pipelineLast,
|
||||
Flags: append(common.OutputFlags("table"), []cli.Flag{
|
||||
|
@ -49,7 +49,11 @@ func pipelineLast(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
pipeline, err := client.PipelineLast(repoID, c.String("branch"))
|
||||
opt := woodpecker.PipelineLastOptions{
|
||||
Branch: c.String("branch"),
|
||||
}
|
||||
|
||||
pipeline, err := client.PipelineLast(repoID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package pipeline
|
|||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
|
@ -24,6 +25,7 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
//nolint:mnd
|
||||
func buildPipelineListCmd() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "ls",
|
||||
|
@ -46,9 +48,26 @@ func buildPipelineListCmd() *cli.Command {
|
|||
&cli.IntFlag{
|
||||
Name: "limit",
|
||||
Usage: "limit the list size",
|
||||
//nolint:mnd
|
||||
Value: 25,
|
||||
},
|
||||
&cli.TimestampFlag{
|
||||
Name: "before",
|
||||
Usage: "only return pipelines before this date (RFC3339)",
|
||||
Config: cli.TimestampConfig{
|
||||
Layouts: []string{
|
||||
time.RFC3339,
|
||||
},
|
||||
},
|
||||
},
|
||||
&cli.TimestampFlag{
|
||||
Name: "after",
|
||||
Usage: "only return pipelines after this date (RFC3339)",
|
||||
Config: cli.TimestampConfig{
|
||||
Layouts: []string{
|
||||
time.RFC3339,
|
||||
},
|
||||
},
|
||||
},
|
||||
}...),
|
||||
}
|
||||
}
|
||||
|
@ -58,14 +77,14 @@ func List(ctx context.Context, c *cli.Command) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resources, err := pipelineList(ctx, c, client)
|
||||
resources, err := pipelineList(c, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return pipelineOutput(c, resources)
|
||||
}
|
||||
|
||||
func pipelineList(_ context.Context, c *cli.Command, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
|
||||
func pipelineList(c *cli.Command, client woodpecker.Client) ([]woodpecker.Pipeline, error) {
|
||||
resources := make([]woodpecker.Pipeline, 0)
|
||||
|
||||
repoIDOrFullName := c.Args().First()
|
||||
|
@ -74,7 +93,18 @@ func pipelineList(_ context.Context, c *cli.Command, client woodpecker.Client) (
|
|||
return resources, err
|
||||
}
|
||||
|
||||
pipelines, err := client.PipelineList(repoID)
|
||||
opt := woodpecker.PipelineListOptions{}
|
||||
before := c.Timestamp("before")
|
||||
after := c.Timestamp("after")
|
||||
|
||||
if !before.IsZero() {
|
||||
opt.Before = before
|
||||
}
|
||||
if !after.IsZero() {
|
||||
opt.After = after
|
||||
}
|
||||
|
||||
pipelines, err := client.PipelineList(repoID, opt)
|
||||
if err != nil {
|
||||
return resources, err
|
||||
}
|
||||
|
|
|
@ -107,13 +107,13 @@ func TestPipelineList(t *testing.T) {
|
|||
for _, tt := range testtases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockClient := mocks.NewClient(t)
|
||||
mockClient.On("PipelineList", mock.Anything).Return(tt.pipelines, tt.pipelineErr)
|
||||
mockClient.On("PipelineList", mock.Anything, mock.Anything).Return(tt.pipelines, tt.pipelineErr)
|
||||
mockClient.On("RepoLookup", mock.Anything).Return(&woodpecker.Repo{ID: tt.repoID}, nil)
|
||||
|
||||
command := buildPipelineListCmd()
|
||||
command.Writer = io.Discard
|
||||
command.Action = func(ctx context.Context, c *cli.Command) error {
|
||||
pipelines, err := pipelineList(ctx, c, mockClient)
|
||||
command.Action = func(_ context.Context, c *cli.Command) error {
|
||||
pipelines, err := pipelineList(c, mockClient)
|
||||
if tt.wantErr != nil {
|
||||
assert.EqualError(t, err, tt.wantErr.Error())
|
||||
return nil
|
||||
|
|
|
@ -24,5 +24,6 @@ var Command = &cli.Command{
|
|||
Usage: "manage logs",
|
||||
Commands: []*cli.Command{
|
||||
logPurgeCmd,
|
||||
logShowCmd,
|
||||
},
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pipeline
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -27,14 +27,14 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelineLogsCmd = &cli.Command{
|
||||
Name: "logs",
|
||||
var logShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show pipeline logs",
|
||||
ArgsUsage: "<repo-id|repo-full-name> <pipeline> [step-number|step-name]",
|
||||
Action: pipelineLogs,
|
||||
Action: logShow,
|
||||
}
|
||||
|
||||
func pipelineLogs(ctx context.Context, c *cli.Command) error {
|
||||
func logShow(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
|
@ -59,17 +59,17 @@ func pipelineLogs(ctx context.Context, c *cli.Command) error {
|
|||
|
||||
stepArg := c.Args().Get(2) //nolint:mnd
|
||||
if len(stepArg) == 0 {
|
||||
return showPipelineLog(client, repoID, number)
|
||||
return pipelineLog(client, repoID, number)
|
||||
}
|
||||
|
||||
step, err := internal.ParseStep(client, repoID, number, stepArg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid step '%s': %w", stepArg, err)
|
||||
}
|
||||
return showStepLog(client, repoID, number, step)
|
||||
return stepLog(client, repoID, number, step)
|
||||
}
|
||||
|
||||
func showPipelineLog(client woodpecker.Client, repoID, number int64) error {
|
||||
func pipelineLog(client woodpecker.Client, repoID, number int64) error {
|
||||
pipeline, err := client.Pipeline(repoID, number)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -85,7 +85,7 @@ func showPipelineLog(client woodpecker.Client, repoID, number int64) error {
|
|||
if err := tmpl.Execute(os.Stdout, map[string]any{"workflow": workflow, "step": step}); err != nil {
|
||||
return err
|
||||
}
|
||||
err := showStepLog(client, repoID, number, step.ID)
|
||||
err := stepLog(client, repoID, number, step.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ func showPipelineLog(client woodpecker.Client, repoID, number int64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func showStepLog(client woodpecker.Client, repoID, number, step int64) error {
|
||||
func stepLog(client woodpecker.Client, repoID, number, step int64) error {
|
||||
logs, err := client.StepLogEntries(repoID, number, step)
|
||||
if err != nil {
|
||||
return err
|
|
@ -23,6 +23,8 @@ import (
|
|||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/output"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/pipeline/deploy"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/pipeline/log"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
|
@ -31,18 +33,20 @@ var Command = &cli.Command{
|
|||
Name: "pipeline",
|
||||
Usage: "manage pipelines",
|
||||
Commands: []*cli.Command{
|
||||
buildPipelineListCmd(),
|
||||
pipelineLastCmd,
|
||||
pipelineLogsCmd,
|
||||
pipelineInfoCmd,
|
||||
pipelineStopCmd,
|
||||
pipelineStartCmd,
|
||||
pipelineApproveCmd,
|
||||
pipelineDeclineCmd,
|
||||
pipelineQueueCmd,
|
||||
pipelineKillCmd,
|
||||
pipelinePsCmd,
|
||||
pipelineCreateCmd,
|
||||
pipelineDeclineCmd,
|
||||
deploy.Command,
|
||||
pipelineKillCmd,
|
||||
pipelineLastCmd,
|
||||
buildPipelineListCmd(),
|
||||
log.Command,
|
||||
pipelinePsCmd,
|
||||
pipelinePurgeCmd,
|
||||
pipelineQueueCmd,
|
||||
pipelineShowCmd,
|
||||
pipelineStartCmd,
|
||||
pipelineStopCmd,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ func TestPipelineOutput(t *testing.T) {
|
|||
{
|
||||
name: "table output with default columns",
|
||||
args: []string{},
|
||||
expected: "NUMBER STATUS EVENT BRANCH MESSAGE AUTHOR\n1 success push main message John Doe\n",
|
||||
expected: "NUMBER STATUS EVENT BRANCH MESSAGE AUTHOR\n1 success push main message multiline John Doe\n",
|
||||
},
|
||||
{
|
||||
name: "table output with custom columns",
|
||||
|
@ -33,7 +33,7 @@ func TestPipelineOutput(t *testing.T) {
|
|||
{
|
||||
name: "table output with no header",
|
||||
args: []string{"output", "--output-no-headers"},
|
||||
expected: "1 success push main message John Doe\n",
|
||||
expected: "1 success push main message multiline John Doe\n",
|
||||
},
|
||||
{
|
||||
name: "go-template output",
|
||||
|
@ -53,8 +53,8 @@ func TestPipelineOutput(t *testing.T) {
|
|||
Status: "success",
|
||||
Event: "push",
|
||||
Branch: "main",
|
||||
Message: "message",
|
||||
Author: "John Doe",
|
||||
Message: "message\nmultiline",
|
||||
Author: "John Doe\n",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelinePsCmd = &cli.Command{
|
||||
|
@ -51,7 +52,7 @@ func pipelinePs(ctx context.Context, c *cli.Command) error {
|
|||
|
||||
if pipelineArg == "last" || len(pipelineArg) == 0 {
|
||||
// Fetch the pipeline number from the last pipeline
|
||||
pipeline, err := client.PipelineLast(repoID, "")
|
||||
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
157
cli/pipeline/purge.go
Normal file
157
cli/pipeline/purge.go
Normal file
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2022 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 pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
shared_utils "go.woodpecker-ci.org/woodpecker/v2/shared/utils"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
//nolint:mnd
|
||||
var pipelinePurgeCmd = &cli.Command{
|
||||
Name: "purge",
|
||||
Usage: "purge pipelines",
|
||||
ArgsUsage: "<repo-id|repo-full-name>",
|
||||
Action: Purge,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "older-than",
|
||||
Usage: "remove pipelines older than the specified time limit",
|
||||
Required: true,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "keep-min",
|
||||
Usage: "minimum number of pipelines to keep",
|
||||
Value: 10,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "dry-run",
|
||||
Usage: "disable non-read api calls",
|
||||
Value: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func Purge(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return pipelinePurge(c, client)
|
||||
}
|
||||
|
||||
func pipelinePurge(c *cli.Command, client woodpecker.Client) (err error) {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
if len(repoIDOrFullName) == 0 {
|
||||
return fmt.Errorf("missing required argument repo-id / repo-full-name")
|
||||
}
|
||||
repoID, err := internal.ParseRepo(client, repoIDOrFullName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid repo '%s': %w", repoIDOrFullName, err)
|
||||
}
|
||||
|
||||
olderThan := c.String("older-than")
|
||||
keepMin := c.Int("keep-min")
|
||||
dryRun := c.Bool("dry-run")
|
||||
|
||||
duration, err := time.ParseDuration(olderThan)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pipelinesKeep []*woodpecker.Pipeline
|
||||
|
||||
if keepMin > 0 {
|
||||
pipelinesKeep, err = fetchPipelinesToKeep(client, repoID, int(keepMin))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pipelines, err := fetchPipelines(client, repoID, duration)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a map of pipeline IDs to keep
|
||||
keepMap := make(map[int64]struct{})
|
||||
for _, p := range pipelinesKeep {
|
||||
keepMap[p.ID] = struct{}{}
|
||||
}
|
||||
|
||||
// Filter pipelines to only include those not in keepMap
|
||||
var pipelinesToPurge []*woodpecker.Pipeline
|
||||
for _, p := range pipelines {
|
||||
if _, exists := keepMap[p.ID]; !exists {
|
||||
pipelinesToPurge = append(pipelinesToPurge, p)
|
||||
}
|
||||
}
|
||||
|
||||
msgPrefix := ""
|
||||
if dryRun {
|
||||
msgPrefix = "DRY-RUN: "
|
||||
}
|
||||
|
||||
for i, p := range pipelinesToPurge {
|
||||
// cspell:words spurge
|
||||
log.Debug().Msgf("%spurge %v/%v pipelines from repo '%v'", msgPrefix, i+1, len(pipelinesToPurge), repoIDOrFullName)
|
||||
if dryRun {
|
||||
continue
|
||||
}
|
||||
|
||||
err := client.PipelineDelete(repoID, p.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchPipelinesToKeep(client woodpecker.Client, repoID int64, keepMin int) ([]*woodpecker.Pipeline, error) {
|
||||
if keepMin <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return shared_utils.Paginate(func(page int) ([]*woodpecker.Pipeline, error) {
|
||||
return client.PipelineList(repoID,
|
||||
woodpecker.PipelineListOptions{
|
||||
ListOptions: woodpecker.ListOptions{
|
||||
Page: page,
|
||||
},
|
||||
},
|
||||
)
|
||||
}, keepMin)
|
||||
}
|
||||
|
||||
func fetchPipelines(client woodpecker.Client, repoID int64, duration time.Duration) ([]*woodpecker.Pipeline, error) {
|
||||
return shared_utils.Paginate(func(page int) ([]*woodpecker.Pipeline, error) {
|
||||
return client.PipelineList(repoID,
|
||||
woodpecker.PipelineListOptions{
|
||||
ListOptions: woodpecker.ListOptions{
|
||||
Page: page,
|
||||
},
|
||||
After: time.Now().Add(-duration),
|
||||
},
|
||||
)
|
||||
}, -1)
|
||||
}
|
105
cli/pipeline/purge_test.go
Normal file
105
cli/pipeline/purge_test.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker/mocks"
|
||||
)
|
||||
|
||||
func TestPipelinePurge(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
repoID int64
|
||||
args []string
|
||||
pipelinesKeep []*woodpecker.Pipeline
|
||||
pipelines []*woodpecker.Pipeline
|
||||
wantDelete int
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "success with no pipelines to purge",
|
||||
repoID: 1,
|
||||
args: []string{"purge", "--older-than", "1h", "repo/name"},
|
||||
pipelinesKeep: []*woodpecker.Pipeline{
|
||||
{ID: 1},
|
||||
},
|
||||
pipelines: []*woodpecker.Pipeline{},
|
||||
},
|
||||
{
|
||||
name: "success with pipelines to purge",
|
||||
repoID: 1,
|
||||
args: []string{"purge", "--older-than", "1h", "repo/name"},
|
||||
pipelinesKeep: []*woodpecker.Pipeline{
|
||||
{ID: 1},
|
||||
},
|
||||
pipelines: []*woodpecker.Pipeline{
|
||||
{ID: 1},
|
||||
{ID: 2},
|
||||
{ID: 3},
|
||||
},
|
||||
wantDelete: 2,
|
||||
},
|
||||
{
|
||||
name: "error on invalid duration",
|
||||
repoID: 1,
|
||||
args: []string{"purge", "--older-than", "invalid", "repo/name"},
|
||||
wantErr: errors.New("time: invalid duration \"invalid\""),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mockClient := mocks.NewClient(t)
|
||||
mockClient.On("RepoLookup", mock.Anything).Maybe().Return(&woodpecker.Repo{ID: tt.repoID}, nil)
|
||||
|
||||
mockClient.On("PipelineList", mock.Anything, mock.Anything).Return(func(_ int64, opt woodpecker.PipelineListOptions) ([]*woodpecker.Pipeline, error) {
|
||||
// Return keep pipelines for first call
|
||||
if opt.After.IsZero() {
|
||||
if opt.Page == 1 {
|
||||
return tt.pipelinesKeep, nil
|
||||
}
|
||||
return []*woodpecker.Pipeline{}, nil
|
||||
}
|
||||
|
||||
// Return pipelines to purge for calls with After filter
|
||||
if !opt.After.IsZero() {
|
||||
if opt.Page == 1 {
|
||||
return tt.pipelines, nil
|
||||
}
|
||||
return []*woodpecker.Pipeline{}, nil
|
||||
}
|
||||
|
||||
return []*woodpecker.Pipeline{}, nil
|
||||
}).Maybe()
|
||||
|
||||
if tt.wantDelete > 0 {
|
||||
mockClient.On("PipelineDelete", tt.repoID, mock.Anything).Return(nil).Times(tt.wantDelete)
|
||||
}
|
||||
|
||||
command := pipelinePurgeCmd
|
||||
command.Writer = io.Discard
|
||||
command.Action = func(_ context.Context, c *cli.Command) error {
|
||||
err := pipelinePurge(c, mockClient)
|
||||
|
||||
if tt.wantErr != nil {
|
||||
assert.EqualError(t, err, tt.wantErr.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = command.Run(context.Background(), tt.args)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -25,15 +25,15 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelineInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "show pipeline details",
|
||||
var pipelineShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show pipeline information",
|
||||
ArgsUsage: "<repo-id|repo-full-name> [pipeline]",
|
||||
Action: pipelineInfo,
|
||||
Action: pipelineShow,
|
||||
Flags: common.OutputFlags("table"),
|
||||
}
|
||||
|
||||
func pipelineInfo(ctx context.Context, c *cli.Command) error {
|
||||
func pipelineShow(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
|
@ -48,7 +48,7 @@ func pipelineInfo(ctx context.Context, c *cli.Command) error {
|
|||
var number int64
|
||||
if pipelineArg == "last" || len(pipelineArg) == 0 {
|
||||
// Fetch the pipeline number from the last pipeline
|
||||
pipeline, err := client.PipelineLast(repoID, "")
|
||||
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var pipelineStartCmd = &cli.Command{
|
||||
|
@ -34,7 +35,7 @@ var pipelineStartCmd = &cli.Command{
|
|||
&cli.StringSliceFlag{
|
||||
Name: "param",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "custom parameters to be injected into the step environment. Format: KEY=value",
|
||||
Usage: "custom parameters to inject into the step environment. Format: KEY=value",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -54,7 +55,7 @@ func pipelineStart(ctx context.Context, c *cli.Command) (err error) {
|
|||
var number int64
|
||||
if pipelineArg == "last" {
|
||||
// Fetch the pipeline number from the last pipeline
|
||||
pipeline, err := client.PipelineLast(repoID, "")
|
||||
pipeline, err := client.PipelineLast(repoID, woodpecker.PipelineLastOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -69,9 +70,11 @@ func pipelineStart(ctx context.Context, c *cli.Command) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
params := internal.ParseKeyPair(c.StringSlice("param"))
|
||||
opt := woodpecker.PipelineStartOptions{
|
||||
Params: internal.ParseKeyPair(c.StringSlice("param")),
|
||||
}
|
||||
|
||||
pipeline, err := client.PipelineStart(repoID, number, params)
|
||||
pipeline, err := client.PipelineStart(repoID, number, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ var Command = &cli.Command{
|
|||
Commands: []*cli.Command{
|
||||
cronCreateCmd,
|
||||
cronDeleteCmd,
|
||||
cronUpdateCmd,
|
||||
cronInfoCmd,
|
||||
cronListCmd,
|
||||
cronShowCmd,
|
||||
cronUpdateCmd,
|
||||
},
|
||||
}
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var cronListCmd = &cli.Command{
|
||||
|
@ -52,7 +53,8 @@ func cronList(ctx context.Context, c *cli.Command) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
list, err := client.CronList(repoID)
|
||||
opt := woodpecker.CronListOptions{}
|
||||
list, err := client.CronList(repoID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -25,11 +25,11 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var cronInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "display info about a cron job",
|
||||
var cronShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show cron job information",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: cronInfo,
|
||||
Action: cronShow,
|
||||
Flags: []cli.Flag{
|
||||
common.RepoFlag,
|
||||
&cli.StringFlag{
|
||||
|
@ -41,7 +41,7 @@ var cronInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func cronInfo(ctx context.Context, c *cli.Command) error {
|
||||
func cronShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
cronID = c.Int("id")
|
||||
repoIDOrFullName = c.String("repository")
|
|
@ -28,9 +28,9 @@ var Command = &cli.Command{
|
|||
Commands: []*cli.Command{
|
||||
registryCreateCmd,
|
||||
registryDeleteCmd,
|
||||
registryUpdateCmd,
|
||||
registryInfoCmd,
|
||||
registryListCmd,
|
||||
registryShowCmd,
|
||||
registryUpdateCmd,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import (
|
|||
|
||||
var registryCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "adds a registry",
|
||||
Usage: "add a registry",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: registryCreate,
|
||||
Flags: []cli.Flag{
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var registryListCmd = &cli.Command{
|
||||
|
@ -49,7 +50,9 @@ func registryList(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
list, err := client.RegistryList(repoID)
|
||||
opt := woodpecker.RegistryListOptions{}
|
||||
|
||||
list, err := client.RegistryList(repoID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var registryInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "display registry info",
|
||||
var registryShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show registry information",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: registryInfo,
|
||||
Action: registryShow,
|
||||
Flags: []cli.Flag{
|
||||
common.RepoFlag,
|
||||
&cli.StringFlag{
|
||||
|
@ -41,7 +41,7 @@ var registryInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func registryInfo(ctx context.Context, c *cli.Command) error {
|
||||
func registryShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
hostname = c.String("hostname")
|
||||
format = c.String("format") + "\n"
|
|
@ -17,7 +17,9 @@ package repo
|
|||
import (
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/repo/cron"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/repo/registry"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/repo/secret"
|
||||
)
|
||||
|
||||
// Command exports the repository command.
|
||||
|
@ -25,14 +27,16 @@ var Command = &cli.Command{
|
|||
Name: "repo",
|
||||
Usage: "manage repositories",
|
||||
Commands: []*cli.Command{
|
||||
repoListCmd,
|
||||
repoInfoCmd,
|
||||
repoAddCmd,
|
||||
repoUpdateCmd,
|
||||
repoChownCmd,
|
||||
cron.Command,
|
||||
repoListCmd,
|
||||
registry.Command,
|
||||
repoRemoveCmd,
|
||||
repoRepairCmd,
|
||||
repoChownCmd,
|
||||
secret.Command,
|
||||
repoShowCmd,
|
||||
repoSyncCmd,
|
||||
registry.Command,
|
||||
repoUpdateCmd,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var repoAddCmd = &cli.Command{
|
||||
|
@ -43,7 +44,11 @@ func repoAdd(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
repo, err := client.RepoPost(int64(forgeRemoteID))
|
||||
opt := woodpecker.RepoPostOptions{
|
||||
ForgeRemoteID: int64(forgeRemoteID),
|
||||
}
|
||||
|
||||
repo, err := client.RepoPost(opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var repoListCmd = &cli.Command{
|
||||
|
@ -36,6 +37,10 @@ var repoListCmd = &cli.Command{
|
|||
Name: "org",
|
||||
Usage: "filter by organization",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "all",
|
||||
Usage: "query all repos, including inactive ones",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -45,7 +50,11 @@ func repoList(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
repos, err := client.RepoList()
|
||||
opt := woodpecker.RepoListOptions{
|
||||
All: c.Bool("all"),
|
||||
}
|
||||
|
||||
repos, err := client.RepoList(opt)
|
||||
if err != nil || len(repos) == 0 {
|
||||
return err
|
||||
}
|
||||
|
@ -68,4 +77,4 @@ func repoList(ctx context.Context, c *cli.Command) error {
|
|||
}
|
||||
|
||||
// Template for repository list items.
|
||||
var tmplRepoList = "\x1b[33m{{ .FullName }}\x1b[0m (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }})"
|
||||
var tmplRepoList = "\x1b[33m{{ .FullName }}\x1b[0m (id: {{ .ID }}, forgeRemoteID: {{ .ForgeRemoteID }}, isActive: {{ .IsActive }})"
|
||||
|
|
|
@ -25,15 +25,15 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
)
|
||||
|
||||
var repoInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "show repository details",
|
||||
var repoShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show repository information",
|
||||
ArgsUsage: "<repo-id|repo-full-name>",
|
||||
Action: repoInfo,
|
||||
Action: repoShow,
|
||||
Flags: []cli.Flag{common.FormatFlag(tmplRepoInfo)},
|
||||
}
|
||||
|
||||
func repoInfo(ctx context.Context, c *cli.Command) error {
|
||||
func repoShow(ctx context.Context, c *cli.Command) error {
|
||||
repoIDOrFullName := c.Args().First()
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var repoSyncCmd = &cli.Command{
|
||||
|
@ -40,7 +41,11 @@ func repoSync(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
repos, err := client.RepoListOpts(true)
|
||||
opt := woodpecker.RepoListOptions{
|
||||
All: true,
|
||||
}
|
||||
|
||||
repos, err := client.RepoList(opt)
|
||||
if err != nil || len(repos) == 0 {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ var repoUpdateCmd = &cli.Command{
|
|||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Usage: "repository configuration path (e.g. .woodpecker.yml)",
|
||||
Usage: "repository configuration path. Example: .woodpecker.yml",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "pipeline-counter",
|
||||
|
@ -61,7 +61,7 @@ var repoUpdateCmd = &cli.Command{
|
|||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "unsafe",
|
||||
Usage: "validate updating the pipeline-counter is unsafe",
|
||||
Usage: "allow unsafe operations",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
package secret
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
|
@ -32,52 +28,17 @@ var Command = &cli.Command{
|
|||
Commands: []*cli.Command{
|
||||
secretCreateCmd,
|
||||
secretDeleteCmd,
|
||||
secretUpdateCmd,
|
||||
secretInfoCmd,
|
||||
secretListCmd,
|
||||
secretShowCmd,
|
||||
secretUpdateCmd,
|
||||
},
|
||||
}
|
||||
|
||||
func parseTargetArgs(client woodpecker.Client, c *cli.Command) (global bool, orgID, repoID int64, err error) {
|
||||
if c.Bool("global") {
|
||||
return true, -1, -1, nil
|
||||
}
|
||||
|
||||
func parseTargetArgs(client woodpecker.Client, c *cli.Command) (repoID int64, err error) {
|
||||
repoIDOrFullName := c.String("repository")
|
||||
if repoIDOrFullName == "" {
|
||||
repoIDOrFullName = c.Args().First()
|
||||
}
|
||||
|
||||
orgIDOrName := c.String("organization")
|
||||
if orgIDOrName == "" && repoIDOrFullName == "" {
|
||||
if err := cli.ShowSubcommandHelp(c); err != nil {
|
||||
return false, -1, -1, err
|
||||
}
|
||||
|
||||
return false, -1, -1, fmt.Errorf("missing arguments")
|
||||
}
|
||||
|
||||
if orgIDOrName != "" && repoIDOrFullName == "" {
|
||||
if orgID, err := strconv.ParseInt(orgIDOrName, 10, 64); err == nil {
|
||||
return false, orgID, -1, nil
|
||||
}
|
||||
|
||||
org, err := client.OrgLookup(orgIDOrName)
|
||||
if err != nil {
|
||||
return false, -1, -1, err
|
||||
}
|
||||
|
||||
return false, org.ID, -1, nil
|
||||
}
|
||||
|
||||
if orgIDOrName != "" && !strings.Contains(repoIDOrFullName, "/") {
|
||||
repoIDOrFullName = orgIDOrName + "/" + repoIDOrFullName
|
||||
}
|
||||
|
||||
repoID, err = internal.ParseRepo(client, repoIDOrFullName)
|
||||
if err != nil {
|
||||
return false, -1, -1, err
|
||||
}
|
||||
|
||||
return false, -1, repoID, nil
|
||||
return internal.ParseRepo(client, repoIDOrFullName)
|
||||
}
|
93
cli/repo/secret/secret_add.go
Normal file
93
cli/repo/secret/secret_add.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretCreateCmd = &cli.Command{
|
||||
Name: "add",
|
||||
Usage: "add a secret",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretCreate,
|
||||
Flags: []cli.Flag{
|
||||
common.RepoFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
Usage: "secret name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "value",
|
||||
Usage: "secret value",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "event",
|
||||
Usage: "limit secret to these events",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "image",
|
||||
Usage: "limit secret to these images",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func secretCreate(ctx context.Context, c *cli.Command) error {
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secret := &woodpecker.Secret{
|
||||
Name: strings.ToLower(c.String("name")),
|
||||
Value: c.String("value"),
|
||||
Images: c.StringSlice("image"),
|
||||
Events: c.StringSlice("event"),
|
||||
}
|
||||
if len(secret.Events) == 0 {
|
||||
secret.Events = defaultSecretEvents
|
||||
}
|
||||
if strings.HasPrefix(secret.Value, "@") {
|
||||
path := strings.TrimPrefix(secret.Value, "@")
|
||||
out, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.SecretCreate(repoID, secret)
|
||||
return err
|
||||
}
|
||||
|
||||
var defaultSecretEvents = []string{
|
||||
woodpecker.EventPush,
|
||||
woodpecker.EventTag,
|
||||
woodpecker.EventRelease,
|
||||
woodpecker.EventDeploy,
|
||||
}
|
87
cli/repo/secret/secret_list.go
Normal file
87
cli/repo/secret/secret_list.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
// 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 secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"html/template"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v3"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretListCmd = &cli.Command{
|
||||
Name: "ls",
|
||||
Usage: "list secrets",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretList,
|
||||
Flags: []cli.Flag{
|
||||
common.RepoFlag,
|
||||
common.FormatFlag(tmplSecretList, true),
|
||||
},
|
||||
}
|
||||
|
||||
func secretList(ctx context.Context, c *cli.Command) error {
|
||||
format := c.String("format") + "\n"
|
||||
|
||||
client, err := internal.NewClient(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opt := woodpecker.SecretListOptions{}
|
||||
|
||||
list, err := client.SecretList(repoID, opt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, secret := range list {
|
||||
if err := tmpl.Execute(os.Stdout, secret); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Template for secret list items.
|
||||
var tmplSecretList = "\x1b[33m{{ .Name }} \x1b[0m" + `
|
||||
Events: {{ list .Events }}
|
||||
{{- if .Images }}
|
||||
Images: {{ list .Images }}
|
||||
{{- else }}
|
||||
Images: <any>
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
var secretFuncMap = template.FuncMap{
|
||||
"list": func(s []string) string {
|
||||
return strings.Join(s, ", ")
|
||||
},
|
||||
}
|
|
@ -29,11 +29,6 @@ var secretDeleteCmd = &cli.Command{
|
|||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretDelete,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "global",
|
||||
Usage: "global secret",
|
||||
},
|
||||
common.OrgFlag,
|
||||
common.RepoFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
|
@ -50,16 +45,10 @@ func secretDelete(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
global, orgID, repoID, err := parseTargetArgs(client, c)
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if global {
|
||||
return client.GlobalSecretDelete(secretName)
|
||||
}
|
||||
if orgID != -1 {
|
||||
return client.OrgSecretDelete(orgID, secretName)
|
||||
}
|
||||
return client.SecretDelete(repoID, secretName)
|
||||
}
|
|
@ -32,11 +32,6 @@ var secretUpdateCmd = &cli.Command{
|
|||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretUpdate,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "global",
|
||||
Usage: "global secret",
|
||||
},
|
||||
common.OrgFlag,
|
||||
common.RepoFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
|
@ -48,11 +43,11 @@ var secretUpdateCmd = &cli.Command{
|
|||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "event",
|
||||
Usage: "secret limited to these events",
|
||||
Usage: "limit secret to these events",
|
||||
},
|
||||
&cli.StringSliceFlag{
|
||||
Name: "image",
|
||||
Usage: "secret limited to these images",
|
||||
Usage: "limit secret to these images",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -78,19 +73,11 @@ func secretUpdate(ctx context.Context, c *cli.Command) error {
|
|||
secret.Value = string(out)
|
||||
}
|
||||
|
||||
global, orgID, repoID, err := parseTargetArgs(client, c)
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if global {
|
||||
_, err = client.GlobalSecretUpdate(secret)
|
||||
return err
|
||||
}
|
||||
if orgID != -1 {
|
||||
_, err = client.OrgSecretUpdate(orgID, secret)
|
||||
return err
|
||||
}
|
||||
_, err = client.SecretUpdate(repoID, secret)
|
||||
return err
|
||||
}
|
|
@ -24,20 +24,14 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/internal"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/woodpecker-go/woodpecker"
|
||||
)
|
||||
|
||||
var secretInfoCmd = &cli.Command{
|
||||
Name: "info",
|
||||
Usage: "display secret info",
|
||||
var secretShowCmd = &cli.Command{
|
||||
Name: "show",
|
||||
Usage: "show secret information",
|
||||
ArgsUsage: "[repo-id|repo-full-name]",
|
||||
Action: secretInfo,
|
||||
Action: secretShow,
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "global",
|
||||
Usage: "global secret",
|
||||
},
|
||||
common.OrgFlag,
|
||||
common.RepoFlag,
|
||||
&cli.StringFlag{
|
||||
Name: "name",
|
||||
|
@ -47,7 +41,7 @@ var secretInfoCmd = &cli.Command{
|
|||
},
|
||||
}
|
||||
|
||||
func secretInfo(ctx context.Context, c *cli.Command) error {
|
||||
func secretShow(ctx context.Context, c *cli.Command) error {
|
||||
var (
|
||||
secretName = c.String("name")
|
||||
format = c.String("format") + "\n"
|
||||
|
@ -62,28 +56,14 @@ func secretInfo(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
global, orgID, repoID, err := parseTargetArgs(client, c)
|
||||
repoID, err := parseTargetArgs(client, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var secret *woodpecker.Secret
|
||||
switch {
|
||||
case global:
|
||||
secret, err = client.GlobalSecret(secretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case orgID != -1:
|
||||
secret, err = client.OrgSecret(orgID, secretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
secret, err = client.Secret(repoID, secretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secret, err := client.Secret(repoID, secretName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New("_").Funcs(secretFuncMap).Parse(format)
|
|
@ -20,11 +20,11 @@ var Command = &cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "server",
|
||||
Usage: "The URL of the woodpecker server",
|
||||
Usage: "URL of the woodpecker server",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "token",
|
||||
Usage: "The token to authenticate with the woodpecker server",
|
||||
Usage: "token to authenticate with the woodpecker server",
|
||||
},
|
||||
},
|
||||
Action: setup,
|
||||
|
@ -41,7 +41,7 @@ func setup(ctx context.Context, c *cli.Command) error {
|
|||
}
|
||||
|
||||
if !setupAgain {
|
||||
log.Info().Msg("Configuration skipped")
|
||||
log.Info().Msg("configuration skipped")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ func setup(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Info().Msg("The woodpecker-cli has been successfully setup")
|
||||
log.Info().Msg("woodpecker-cli has been successfully setup")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ func receiveTokenFromUI(c context.Context, serverURL string) (string, error) {
|
|||
srv.Handler = setupRouter(tokenReceived)
|
||||
|
||||
go func() {
|
||||
log.Debug().Msgf("Listening for token response on :%d", port)
|
||||
log.Debug().Msgf("listening for token response on :%d", port)
|
||||
_ = srv.ListenAndServe()
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
log.Debug().Msg("Shutting down server")
|
||||
log.Debug().Msg("shutting down server")
|
||||
_ = srv.Shutdown(c)
|
||||
}()
|
||||
|
||||
|
@ -90,7 +90,7 @@ func setupRouter(tokenReceived chan string) *gin.Engine {
|
|||
|
||||
err := c.BindJSON(&data)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("Failed to bind JSON")
|
||||
log.Debug().Err(err).Msg("failed to bind JSON")
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "invalid request",
|
||||
})
|
||||
|
@ -110,7 +110,7 @@ func setupRouter(tokenReceived chan string) *gin.Engine {
|
|||
func openBrowser(url string) error {
|
||||
var err error
|
||||
|
||||
log.Debug().Msgf("Opening browser with URL: %s", url)
|
||||
log.Debug().Msgf("opening browser with URL: %s", url)
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
|
|
|
@ -24,7 +24,7 @@ var Command = &cli.Command{
|
|||
}
|
||||
|
||||
func update(ctx context.Context, c *cli.Command) error {
|
||||
log.Info().Msg("Checking for updates ...")
|
||||
log.Info().Msg("checking for updates ...")
|
||||
|
||||
newVersion, err := CheckForUpdate(ctx, c.Bool("force"))
|
||||
if err != nil {
|
||||
|
@ -32,11 +32,11 @@ func update(ctx context.Context, c *cli.Command) error {
|
|||
}
|
||||
|
||||
if newVersion == nil {
|
||||
fmt.Println("You are using the latest version of woodpecker-cli")
|
||||
fmt.Println("you are using the latest version of woodpecker-cli")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Info().Msgf("New version %s is available! Updating ...", newVersion.Version)
|
||||
log.Info().Msgf("new version %s is available! Updating ...", newVersion.Version)
|
||||
|
||||
var tarFilePath string
|
||||
tarFilePath, err = downloadNewVersion(ctx, newVersion.AssetURL)
|
||||
|
@ -44,14 +44,14 @@ func update(ctx context.Context, c *cli.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Debug().Msgf("New version %s has been downloaded successfully! Installing ...", newVersion.Version)
|
||||
log.Debug().Msgf("new version %s has been downloaded successfully! Installing ...", newVersion.Version)
|
||||
|
||||
binFile, err := extractNewVersion(tarFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug().Msgf("New version %s has been extracted to %s", newVersion.Version, binFile)
|
||||
log.Debug().Msgf("new version %s has been extracted to %s", newVersion.Version, binFile)
|
||||
|
||||
executablePathOrSymlink, err := os.Executable()
|
||||
if err != nil {
|
||||
|
|
|
@ -22,10 +22,10 @@ func CheckForUpdate(ctx context.Context, force bool) (*NewVersion, error) {
|
|||
}
|
||||
|
||||
func checkForUpdate(ctx context.Context, versionURL string, force bool) (*NewVersion, error) {
|
||||
log.Debug().Msgf("Current version: %s", version.String())
|
||||
log.Debug().Msgf("current version: %s", version.String())
|
||||
|
||||
if (version.String() == "dev" || strings.HasPrefix(version.String(), "next-")) && !force {
|
||||
log.Debug().Msgf("Skipping update check for development & next versions")
|
||||
log.Debug().Msgf("skipping update check for development/next versions")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
@ -61,11 +61,11 @@ func checkForUpdate(ctx context.Context, versionURL string, force bool) (*NewVer
|
|||
|
||||
// using the latest release
|
||||
if installedVersion == upstreamVersion && !force {
|
||||
log.Debug().Msgf("No new version available")
|
||||
log.Debug().Msgf("no new version available")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
log.Debug().Msgf("New version available: %s", upstreamVersion)
|
||||
log.Debug().Msgf("new version available: %s", upstreamVersion)
|
||||
|
||||
assetURL := fmt.Sprintf(githubBinaryURL, upstreamVersion, runtime.GOOS, runtime.GOARCH)
|
||||
return &NewVersion{
|
||||
|
@ -75,7 +75,7 @@ func checkForUpdate(ctx context.Context, versionURL string, force bool) (*NewVer
|
|||
}
|
||||
|
||||
func downloadNewVersion(ctx context.Context, downloadURL string) (string, error) {
|
||||
log.Debug().Msgf("Downloading new version from %s ...", downloadURL)
|
||||
log.Debug().Msgf("downloading new version from %s ...", downloadURL)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, downloadURL, nil)
|
||||
if err != nil {
|
||||
|
@ -102,13 +102,13 @@ func downloadNewVersion(ctx context.Context, downloadURL string) (string, error)
|
|||
return "", err
|
||||
}
|
||||
|
||||
log.Debug().Msgf("New version downloaded to %s", file.Name())
|
||||
log.Debug().Msgf("new version downloaded to %s", file.Name())
|
||||
|
||||
return file.Name(), nil
|
||||
}
|
||||
|
||||
func extractNewVersion(tarFilePath string) (string, error) {
|
||||
log.Debug().Msgf("Extracting new version from %s ...", tarFilePath)
|
||||
log.Debug().Msgf("extracting new version from %s ...", tarFilePath)
|
||||
|
||||
tarFile, err := os.Open(tarFilePath)
|
||||
if err != nil {
|
||||
|
@ -132,7 +132,7 @@ func extractNewVersion(tarFilePath string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
log.Debug().Msgf("New version extracted to %s", tmpDir)
|
||||
log.Debug().Msgf("new version extracted to %s", tmpDir)
|
||||
|
||||
return path.Join(tmpDir, "woodpecker-cli"), nil
|
||||
}
|
||||
|
|
|
@ -36,6 +36,9 @@ var flags = []cli.Flag{
|
|||
Sources: cli.NewValueSourceChain(
|
||||
cli.File(os.Getenv("WOODPECKER_AGENT_SECRET_FILE")),
|
||||
cli.EnvVar("WOODPECKER_AGENT_SECRET")),
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_GRPC_SECURE"),
|
||||
|
|
|
@ -19,20 +19,14 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/admin"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/common"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/cron"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/deploy"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/exec"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/info"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/lint"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/log"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/loglevel"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/org"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/pipeline"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/repo"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/secret"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/setup"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/update"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/cli/user"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/version"
|
||||
)
|
||||
|
||||
|
@ -49,18 +43,12 @@ func newApp() *cli.Command {
|
|||
app.Suggest = true
|
||||
app.Commands = []*cli.Command{
|
||||
admin.Command,
|
||||
org.Command,
|
||||
repo.Command,
|
||||
pipeline.Command,
|
||||
log.Command,
|
||||
deploy.Command,
|
||||
exec.Command,
|
||||
info.Command,
|
||||
secret.Command,
|
||||
user.Command,
|
||||
lint.Command,
|
||||
loglevel.Command,
|
||||
cron.Command,
|
||||
org.Command,
|
||||
pipeline.Command,
|
||||
repo.Command,
|
||||
setup.Command,
|
||||
update.Command,
|
||||
}
|
||||
|
|
|
@ -116,6 +116,9 @@ var flags = append([]cli.Flag{
|
|||
Name: "grpc-secret",
|
||||
Usage: "grpc jwt secret",
|
||||
Value: "secret",
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_METRICS_SERVER_ADDR"),
|
||||
|
@ -217,6 +220,9 @@ var flags = append([]cli.Flag{
|
|||
cli.EnvVar("WOODPECKER_AGENT_SECRET")),
|
||||
Name: "agent-secret",
|
||||
Usage: "server-agent shared password",
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_DISABLE_USER_AGENT_REGISTRATION"),
|
||||
|
@ -248,6 +254,9 @@ var flags = append([]cli.Flag{
|
|||
Aliases: []string{"datasource"}, // TODO: remove in v4.0.0
|
||||
Usage: "database driver configuration string",
|
||||
Value: datasourceDefaultValue(),
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.NewValueSourceChain(
|
||||
|
@ -255,6 +264,9 @@ var flags = append([]cli.Flag{
|
|||
cli.EnvVar("WOODPECKER_PROMETHEUS_AUTH_TOKEN")),
|
||||
Name: "prometheus-auth-token",
|
||||
Usage: "token to secure prometheus metrics endpoint",
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_STATUS_CONTEXT", "WOODPECKER_GITHUB_CONTEXT", "WOODPECKER_GITEA_CONTEXT"),
|
||||
|
@ -354,6 +366,9 @@ var flags = append([]cli.Flag{
|
|||
cli.EnvVar("WOODPECKER_BITBUCKET_DC_CLIENT_ID")),
|
||||
Name: "forge-oauth-client",
|
||||
Usage: "oauth2 client id",
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.NewValueSourceChain(
|
||||
|
@ -375,6 +390,9 @@ var flags = append([]cli.Flag{
|
|||
cli.EnvVar("WOODPECKER_BITBUCKET_DC_CLIENT_SECRET")),
|
||||
Name: "forge-oauth-secret",
|
||||
Usage: "oauth2 client secret",
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "forge-skip-verify",
|
||||
|
@ -466,6 +484,9 @@ var flags = append([]cli.Flag{
|
|||
cli.EnvVar("WOODPECKER_BITBUCKET_DC_GIT_USERNAME")),
|
||||
Name: "bitbucket-dc-git-username",
|
||||
Usage: "Bitbucket DataCenter/Server service account username",
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.NewValueSourceChain(
|
||||
|
@ -473,6 +494,9 @@ var flags = append([]cli.Flag{
|
|||
cli.EnvVar("WOODPECKER_BITBUCKET_DC_GIT_PASSWORD")),
|
||||
Name: "bitbucket-dc-git-password",
|
||||
Usage: "Bitbucket DataCenter/Server service account password",
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
//
|
||||
// development flags
|
||||
|
@ -500,6 +524,9 @@ var flags = append([]cli.Flag{
|
|||
cli.EnvVar("WOODPECKER_ENCRYPTION_KEY")),
|
||||
Name: "encryption-raw-key",
|
||||
Usage: "Raw encryption key",
|
||||
Config: cli.StringConfig{
|
||||
TrimSpace: true,
|
||||
},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Sources: cli.EnvVars("WOODPECKER_ENCRYPTION_TINK_KEYSET_FILE"),
|
||||
|
|
|
@ -2966,6 +2966,30 @@ const docTemplate = `{
|
|||
"description": "only return pipelines after this RFC3339 date",
|
||||
"name": "after",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "filter pipelines by branch",
|
||||
"name": "branch",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "filter pipelines by webhook events (comma separated)",
|
||||
"name": "event",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "filter pipelines by strings contained in ref",
|
||||
"name": "ref",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "filter pipelines by status",
|
||||
"name": "status",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
@ -5070,8 +5094,11 @@ const docTemplate = `{
|
|||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"netrc_only_trusted": {
|
||||
"type": "boolean"
|
||||
"netrc_trusted": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"org_id": {
|
||||
"type": "integer"
|
||||
|
@ -5124,8 +5151,11 @@ const docTemplate = `{
|
|||
"description": "TODO: deprecated in favor of RequireApproval =\u003e Remove in next major release",
|
||||
"type": "boolean"
|
||||
},
|
||||
"netrc_only_trusted": {
|
||||
"type": "boolean"
|
||||
"netrc_trusted": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"require_approval": {
|
||||
"type": "string"
|
||||
|
|
|
@ -763,6 +763,25 @@ Woodpecker supports to define multiple workflows for a repository. Those workflo
|
|||
|
||||
Workflows that should run even on failure should set the `runs_on` tag. See [here](./25-workflows.md#flow-control) for an example.
|
||||
|
||||
## Advanced network options for steps
|
||||
|
||||
:::warning
|
||||
Only allowed if 'Trusted Network' option is enabled in repo settings by an admin.
|
||||
:::
|
||||
|
||||
### `dns`
|
||||
|
||||
If the backend engine understands to change the DNS server and lookup domain,
|
||||
this options will be used to alter the default DNS config to a custom one for a specific step.
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- name: build
|
||||
image: plugin/abc
|
||||
dns: 1.2.3.4
|
||||
dns_search: 'internal.company'
|
||||
```
|
||||
|
||||
## Privileged mode
|
||||
|
||||
Woodpecker gives the ability to configure privileged mode in the YAML. You can use this parameter to launch containers with escalated capabilities.
|
||||
|
|
|
@ -39,16 +39,13 @@ Only server admins can set this option. If you are not a server admin this optio
|
|||
|
||||
:::
|
||||
|
||||
## Only inject Git credentials into trusted clone plugins
|
||||
## Custom trusted clone plugins
|
||||
|
||||
The clone step may require Git credentials (e.g. for private repos) which are injected via `netrc`.
|
||||
|
||||
By default, they are only injected into trusted clone plugins listed in the env var `WOODPECKER_PLUGINS_TRUSTED_CLONE`.
|
||||
If this option is disabled, the Git credentials are injected into every clone plugin, regardless of whether it is trusted or not.
|
||||
They are only injected into trusted plugins listed in the env var `WOODPECKER_PLUGINS_TRUSTED_CLONE` or in this repo setting.
|
||||
|
||||
:::note
|
||||
This option has no effect on steps other than the clone step.
|
||||
:::
|
||||
This allows you to use a trusted plugin for in the clone section or as a step to pull or push using your git credentials.
|
||||
|
||||
## Project visibility
|
||||
|
||||
|
|
|
@ -236,25 +236,25 @@ const config: Config = {
|
|||
sidebarPath: require.resolve('./sidebars.js'),
|
||||
editUrl: 'https://github.com/woodpecker-ci/woodpecker/edit/main/docs/',
|
||||
includeCurrentVersion: true,
|
||||
lastVersion: '2.7',
|
||||
lastVersion: '2.8',
|
||||
onlyIncludeVersions:
|
||||
process.env.NODE_ENV === 'development' ? ['current', '2.7'] : ['current', '2.7', '2.6', '2.5', '1.0'],
|
||||
process.env.NODE_ENV === 'development' ? ['current', '2.8'] : ['current', '2.8', '2.7', '2.6', '1.0'],
|
||||
versions: {
|
||||
current: {
|
||||
label: 'Next 🚧',
|
||||
banner: 'unreleased',
|
||||
},
|
||||
'2.8': {
|
||||
label: '2.8.x',
|
||||
},
|
||||
'2.7': {
|
||||
label: '2.7.x',
|
||||
banner: 'unmaintained',
|
||||
},
|
||||
'2.6': {
|
||||
label: '2.6.x 💀',
|
||||
banner: 'unmaintained',
|
||||
},
|
||||
'2.5': {
|
||||
label: '2.5.x 💀',
|
||||
banner: 'unmaintained',
|
||||
},
|
||||
'1.0': {
|
||||
label: '1.0.x 💀',
|
||||
banner: 'unmaintained',
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
"@docusaurus/core": "^3.6.3",
|
||||
"@docusaurus/plugin-content-blog": "^3.6.3",
|
||||
"@docusaurus/preset-classic": "^3.6.3",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.45.0",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.46.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"clsx": "^2.1.1",
|
||||
|
|
|
@ -23,8 +23,8 @@ importers:
|
|||
specifier: ^3.6.3
|
||||
version: 3.6.3(@algolia/client-search@5.15.0)(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(@types/react@18.3.12)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.7.2)
|
||||
'@easyops-cn/docusaurus-search-local':
|
||||
specifier: ^0.45.0
|
||||
version: 0.45.0(@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
specifier: ^0.46.0
|
||||
version: 0.46.1(@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@mdx-js/react':
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0(@types/react@18.3.12)(react@18.3.1)
|
||||
|
@ -67,7 +67,7 @@ importers:
|
|||
version: 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@types/node':
|
||||
specifier: ^22.9.3
|
||||
version: 22.9.3
|
||||
version: 22.10.1
|
||||
'@types/react':
|
||||
specifier: ^18.3.12
|
||||
version: 18.3.12
|
||||
|
@ -110,19 +110,19 @@ importers:
|
|||
version: 2.0.3
|
||||
'@types/node':
|
||||
specifier: ^22.9.3
|
||||
version: 22.9.3
|
||||
version: 22.10.1
|
||||
axios:
|
||||
specifier: ^1.7.7
|
||||
version: 1.7.7
|
||||
version: 1.7.8
|
||||
concurrently:
|
||||
specifier: ^9.1.0
|
||||
version: 9.1.0
|
||||
isomorphic-dompurify:
|
||||
specifier: ^2.16.0
|
||||
version: 2.16.0
|
||||
version: 2.18.0
|
||||
marked:
|
||||
specifier: ^15.0.2
|
||||
version: 15.0.2
|
||||
version: 15.0.3
|
||||
tslib:
|
||||
specifier: ^2.8.1
|
||||
version: 2.8.1
|
||||
|
@ -1273,8 +1273,8 @@ packages:
|
|||
'@easyops-cn/autocomplete.js@0.38.1':
|
||||
resolution: {integrity: sha512-drg76jS6syilOUmVNkyo1c7ZEBPcPuK+aJA7AksM5ZIIbV57DMHCywiCr+uHyv8BE5jUTU98j/H7gVrkHrWW3Q==}
|
||||
|
||||
'@easyops-cn/docusaurus-search-local@0.45.0':
|
||||
resolution: {integrity: sha512-ccJjeYmBHrv2v8Y9eQnH79S0PEKcogACKkEatEKPcad7usQj/14jA9POUUUYW/yougLSXghwe+uIncbuUBuBFg==}
|
||||
'@easyops-cn/docusaurus-search-local@0.46.1':
|
||||
resolution: {integrity: sha512-kgenn5+pctVlJg8s1FOAm9KuZLRZvkBTMMGJvTTcvNTmnFIHVVYzYfA2Eg+yVefzsC8/cSZGKKJ0kLf8I+mQyw==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
'@docusaurus/theme-common': ^2 || ^3
|
||||
|
@ -1750,10 +1750,6 @@ packages:
|
|||
'@types/debug@4.1.12':
|
||||
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
||||
|
||||
'@types/dompurify@3.2.0':
|
||||
resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==}
|
||||
deprecated: This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.
|
||||
|
||||
'@types/eslint-scope@3.7.7':
|
||||
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
|
||||
|
||||
|
@ -1769,8 +1765,8 @@ packages:
|
|||
'@types/express-serve-static-core@4.19.6':
|
||||
resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==}
|
||||
|
||||
'@types/express-serve-static-core@5.0.1':
|
||||
resolution: {integrity: sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==}
|
||||
'@types/express-serve-static-core@5.0.2':
|
||||
resolution: {integrity: sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==}
|
||||
|
||||
'@types/express@4.17.21':
|
||||
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
|
||||
|
@ -1826,8 +1822,8 @@ packages:
|
|||
'@types/node@17.0.45':
|
||||
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
|
||||
|
||||
'@types/node@22.9.3':
|
||||
resolution: {integrity: sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==}
|
||||
'@types/node@22.10.1':
|
||||
resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==}
|
||||
|
||||
'@types/parse-json@4.0.2':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
|
@ -2104,8 +2100,8 @@ packages:
|
|||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
axios@1.7.7:
|
||||
resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==}
|
||||
axios@1.7.8:
|
||||
resolution: {integrity: sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==}
|
||||
|
||||
babel-loader@9.2.1:
|
||||
resolution: {integrity: sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==}
|
||||
|
@ -2228,8 +2224,8 @@ packages:
|
|||
caniuse-api@3.0.0:
|
||||
resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==}
|
||||
|
||||
caniuse-lite@1.0.30001683:
|
||||
resolution: {integrity: sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==}
|
||||
caniuse-lite@1.0.30001684:
|
||||
resolution: {integrity: sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==}
|
||||
|
||||
ccount@2.0.1:
|
||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||
|
@ -2343,6 +2339,9 @@ packages:
|
|||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
comlink@4.4.2:
|
||||
resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==}
|
||||
|
||||
comma-separated-tokens@2.0.3:
|
||||
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
|
||||
|
||||
|
@ -2754,8 +2753,8 @@ packages:
|
|||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
dompurify@3.2.1:
|
||||
resolution: {integrity: sha512-NBHEsc0/kzRYQd+AY6HR6B/IgsqzBABrqJbpCDQII/OK6h7B7LXzweZTDsqSW2LkTRpoxf18YUP+YjGySk6B3w==}
|
||||
dompurify@3.2.2:
|
||||
resolution: {integrity: sha512-YMM+erhdZ2nkZ4fTNRTSI94mb7VG7uVF5vj5Zde7tImgnhZE3R6YW/IACGIHb2ux+QkEXMhe591N+5jWOmL4Zw==}
|
||||
|
||||
domutils@2.8.0:
|
||||
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
|
||||
|
@ -3234,8 +3233,12 @@ packages:
|
|||
gopd@1.0.1:
|
||||
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
|
||||
|
||||
got@14.4.4:
|
||||
resolution: {integrity: sha512-tqiF7eSgTBwQkxb1LxsEpva8TaMYVisbhplrFVmw9GQE3855Z+MH/mnsXLLOkDxR6hZJRFMj5VTAZ8lmTF8ZOA==}
|
||||
gopd@1.1.0:
|
||||
resolution: {integrity: sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
got@14.4.5:
|
||||
resolution: {integrity: sha512-sq+uET8TnNKRNnjEOPJzMcxeI0irT8BBNmf+GtZcJpmhYsQM1DSKmCROUjPWKsXZ5HzwD5Cf5/RV+QD9BSTxJg==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
graceful-fs@4.2.10:
|
||||
|
@ -3581,8 +3584,9 @@ packages:
|
|||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-finalizationregistry@1.0.2:
|
||||
resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==}
|
||||
is-finalizationregistry@1.1.0:
|
||||
resolution: {integrity: sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-fullwidth-code-point@3.0.0:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
|
@ -3658,6 +3662,10 @@ packages:
|
|||
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-regex@1.2.0:
|
||||
resolution: {integrity: sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-regexp@1.0.0:
|
||||
resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -3732,8 +3740,8 @@ packages:
|
|||
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
isomorphic-dompurify@2.16.0:
|
||||
resolution: {integrity: sha512-cXhX2owp8rPxafCr0ywqy2CGI/4ceLNgWkWBEvUz64KTbtg3oRL2ZRqq/zW0pzt4YtDjkHLbwcp/lozpKzAQjg==}
|
||||
isomorphic-dompurify@2.18.0:
|
||||
resolution: {integrity: sha512-e0AaROtWPy6ofSTCnUuBvXFidt1eFmrwEbi+Acpz0du6v2H+fq+3svPBn0g/AfBXz24FTWA9ccle7HSFT3HG7A==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
jest-util@29.7.0:
|
||||
|
@ -3920,8 +3928,8 @@ packages:
|
|||
markdown-table@3.0.4:
|
||||
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
|
||||
|
||||
marked@15.0.2:
|
||||
resolution: {integrity: sha512-85RUkoYKIVB21PbMKrnD6aCl9ws+XKEyhJNMbLn206NyD3jbBo7Ec7Wi4Jrsn4dV1a2ng7K/jfkmIN0DNoS41w==}
|
||||
marked@15.0.3:
|
||||
resolution: {integrity: sha512-Ai0cepvl2NHnTcO9jYDtcOEtVBNVYR31XnEA3BndO7f5As1wzpcOceSUM8FDkNLJNIODcLpDTWay/qQhqbuMvg==}
|
||||
engines: {node: '>= 18'}
|
||||
hasBin: true
|
||||
|
||||
|
@ -4319,8 +4327,8 @@ packages:
|
|||
peerDependencies:
|
||||
webpack: ^4.0.0 || ^5.0.0
|
||||
|
||||
nwsapi@2.2.13:
|
||||
resolution: {integrity: sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==}
|
||||
nwsapi@2.2.16:
|
||||
resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==}
|
||||
|
||||
oas-kit-common@1.0.8:
|
||||
resolution: {integrity: sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==}
|
||||
|
@ -5163,8 +5171,8 @@ packages:
|
|||
'@docusaurus/theme-common': ^3.0.0
|
||||
'@docusaurus/utils': ^3.0.0
|
||||
|
||||
reflect.getprototypeof@1.0.6:
|
||||
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
|
||||
reflect.getprototypeof@1.0.7:
|
||||
resolution: {integrity: sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
reftools@1.1.9:
|
||||
|
@ -5702,11 +5710,11 @@ packages:
|
|||
tiny-warning@1.0.3:
|
||||
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
||||
|
||||
tldts-core@6.1.63:
|
||||
resolution: {integrity: sha512-H1XCt54xY+QPbwhTgmxLkepX0MVHu3USfMmejiCOdkMbRcP22Pn2FVF127r/GWXVDmXTRezyF3Ckvhn4Fs6j7Q==}
|
||||
tldts-core@6.1.65:
|
||||
resolution: {integrity: sha512-Uq5t0N0Oj4nQSbU8wFN1YYENvMthvwU13MQrMJRspYCGLSAZjAfoBOJki5IQpnBM/WFskxxC/gIOTwaedmHaSg==}
|
||||
|
||||
tldts@6.1.63:
|
||||
resolution: {integrity: sha512-YWwhsjyn9sB/1rOkSRYxvkN/wl5LFM1QDv6F2pVR+pb/jFne4EOBxHfkKVWvDIBEAw9iGOwwubHtQTm0WRT5sQ==}
|
||||
tldts@6.1.65:
|
||||
resolution: {integrity: sha512-xU9gLTfAGsADQ2PcWee6Hg8RFAv0DnjMGVJmDnUmI8a9+nYmapMQix4afwrdaCtT+AqP4MaxEzu7cCrYmBPbzQ==}
|
||||
hasBin: true
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
|
@ -5760,8 +5768,8 @@ packages:
|
|||
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==}
|
||||
engines: {node: '>=12.20'}
|
||||
|
||||
type-fest@4.27.0:
|
||||
resolution: {integrity: sha512-3IMSWgP7C5KSQqmo1wjhKrwsvXAtF33jO3QY+Uy++ia7hqvgSK6iXbbg5PbDBc1P2ZbNEDgejOrN4YooXvhwCw==}
|
||||
type-fest@4.28.0:
|
||||
resolution: {integrity: sha512-jXMwges/FVbFRe5lTMJZVEZCrO9kI9c8k0PA/z7nF3bo0JSCCLysvokFjNPIUK/itEMas10MQM+AiHoHt/T/XA==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
type-is@1.6.18:
|
||||
|
@ -5795,8 +5803,8 @@ packages:
|
|||
unbox-primitive@1.0.2:
|
||||
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
|
||||
|
||||
undici-types@6.19.8:
|
||||
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
|
||||
undici-types@6.20.0:
|
||||
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
|
||||
|
||||
undici@6.21.0:
|
||||
resolution: {integrity: sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==}
|
||||
|
@ -6025,8 +6033,8 @@ packages:
|
|||
which-boxed-primitive@1.0.2:
|
||||
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
||||
|
||||
which-builtin-type@1.1.4:
|
||||
resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==}
|
||||
which-builtin-type@1.2.0:
|
||||
resolution: {integrity: sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
which-collection@1.0.2:
|
||||
|
@ -7589,7 +7597,7 @@ snapshots:
|
|||
'@docusaurus/core': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/logger': 3.6.3
|
||||
'@docusaurus/mdx-loader': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/types': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@docusaurus/utils': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
|
@ -7629,48 +7637,6 @@ snapshots:
|
|||
- webpack-cli
|
||||
|
||||
'@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)':
|
||||
dependencies:
|
||||
'@docusaurus/core': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/logger': 3.6.3
|
||||
'@docusaurus/mdx-loader': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/module-type-aliases': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/types': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@docusaurus/utils': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/utils-common': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@docusaurus/utils-validation': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@types/react-router-config': 5.0.11
|
||||
combine-promises: 1.2.0
|
||||
fs-extra: 11.2.0
|
||||
js-yaml: 4.1.0
|
||||
lodash: 4.17.21
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
tslib: 2.8.1
|
||||
utility-types: 3.11.0
|
||||
webpack: 5.96.1
|
||||
transitivePeerDependencies:
|
||||
- '@docusaurus/faster'
|
||||
- '@mdx-js/react'
|
||||
- '@parcel/css'
|
||||
- '@rspack/core'
|
||||
- '@swc/core'
|
||||
- '@swc/css'
|
||||
- acorn
|
||||
- bufferutil
|
||||
- csso
|
||||
- debug
|
||||
- esbuild
|
||||
- eslint
|
||||
- lightningcss
|
||||
- supports-color
|
||||
- typescript
|
||||
- uglify-js
|
||||
- utf-8-validate
|
||||
- vue-template-compiler
|
||||
- webpack-cli
|
||||
|
||||
'@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)':
|
||||
dependencies:
|
||||
'@docusaurus/core': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/logger': 3.6.3
|
||||
|
@ -7902,7 +7868,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@docusaurus/core': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-debug': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-google-analytics': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
|
@ -7951,7 +7917,7 @@ snapshots:
|
|||
'@docusaurus/mdx-loader': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/module-type-aliases': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@docusaurus/plugin-content-blog': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-pages': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/theme-translations': 3.6.3
|
||||
|
@ -7995,37 +7961,11 @@ snapshots:
|
|||
- vue-template-compiler
|
||||
- webpack-cli
|
||||
|
||||
'@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)':
|
||||
dependencies:
|
||||
'@docusaurus/mdx-loader': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/module-type-aliases': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/utils': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/utils-common': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@types/history': 4.7.11
|
||||
'@types/react': 18.3.12
|
||||
'@types/react-router-config': 5.0.11
|
||||
clsx: 2.1.1
|
||||
parse-numeric-range: 1.3.0
|
||||
prism-react-renderer: 2.4.0(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
tslib: 2.8.1
|
||||
utility-types: 3.11.0
|
||||
transitivePeerDependencies:
|
||||
- '@swc/core'
|
||||
- acorn
|
||||
- esbuild
|
||||
- supports-color
|
||||
- typescript
|
||||
- uglify-js
|
||||
- webpack-cli
|
||||
|
||||
'@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)':
|
||||
dependencies:
|
||||
'@docusaurus/mdx-loader': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/module-type-aliases': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/utils': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/utils-common': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@types/history': 4.7.11
|
||||
|
@ -8052,7 +7992,7 @@ snapshots:
|
|||
'@docsearch/react': 3.8.0(@algolia/client-search@5.15.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)
|
||||
'@docusaurus/core': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/logger': 3.6.3
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/theme-translations': 3.6.3
|
||||
'@docusaurus/utils': 3.6.3(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
|
@ -8193,7 +8133,7 @@ snapshots:
|
|||
cssesc: 3.0.0
|
||||
immediate: 3.3.0
|
||||
|
||||
'@easyops-cn/docusaurus-search-local@0.45.0(@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)':
|
||||
'@easyops-cn/docusaurus-search-local@0.46.1(@docusaurus/theme-common@3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)':
|
||||
dependencies:
|
||||
'@docusaurus/plugin-content-docs': 3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(debug@4.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
'@docusaurus/theme-common': 3.6.3(@docusaurus/plugin-content-docs@3.6.3(@mdx-js/react@3.1.0(@types/react@18.3.12)(react@18.3.1))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2))(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.2)
|
||||
|
@ -8205,6 +8145,7 @@ snapshots:
|
|||
'@node-rs/jieba': 1.10.4
|
||||
cheerio: 1.0.0
|
||||
clsx: 1.2.1
|
||||
comlink: 4.4.2
|
||||
debug: 4.3.7
|
||||
fs-extra: 10.1.0
|
||||
klaw-sync: 6.0.0
|
||||
|
@ -8344,7 +8285,7 @@ snapshots:
|
|||
'@jest/schemas': 29.6.3
|
||||
'@types/istanbul-lib-coverage': 2.0.6
|
||||
'@types/istanbul-reports': 3.0.4
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
'@types/yargs': 17.0.33
|
||||
chalk: 4.1.2
|
||||
|
||||
|
@ -8663,29 +8604,25 @@ snapshots:
|
|||
'@types/body-parser@1.19.5':
|
||||
dependencies:
|
||||
'@types/connect': 3.4.38
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/bonjour@3.5.13':
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/connect-history-api-fallback@1.5.4':
|
||||
dependencies:
|
||||
'@types/express-serve-static-core': 5.0.1
|
||||
'@types/node': 22.9.3
|
||||
'@types/express-serve-static-core': 5.0.2
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/connect@3.4.38':
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
dependencies:
|
||||
'@types/ms': 0.7.34
|
||||
|
||||
'@types/dompurify@3.2.0':
|
||||
dependencies:
|
||||
dompurify: 3.2.1
|
||||
|
||||
'@types/eslint-scope@3.7.7':
|
||||
dependencies:
|
||||
'@types/eslint': 9.6.1
|
||||
|
@ -8704,14 +8641,14 @@ snapshots:
|
|||
|
||||
'@types/express-serve-static-core@4.19.6':
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
'@types/qs': 6.9.17
|
||||
'@types/range-parser': 1.2.7
|
||||
'@types/send': 0.17.4
|
||||
|
||||
'@types/express-serve-static-core@5.0.1':
|
||||
'@types/express-serve-static-core@5.0.2':
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
'@types/qs': 6.9.17
|
||||
'@types/range-parser': 1.2.7
|
||||
'@types/send': 0.17.4
|
||||
|
@ -8739,7 +8676,7 @@ snapshots:
|
|||
|
||||
'@types/http-proxy@1.17.15':
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/istanbul-lib-coverage@2.0.6': {}
|
||||
|
||||
|
@ -8765,13 +8702,13 @@ snapshots:
|
|||
|
||||
'@types/node-forge@1.3.11':
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/node@17.0.45': {}
|
||||
|
||||
'@types/node@22.9.3':
|
||||
'@types/node@22.10.1':
|
||||
dependencies:
|
||||
undici-types: 6.19.8
|
||||
undici-types: 6.20.0
|
||||
|
||||
'@types/parse-json@4.0.2': {}
|
||||
|
||||
|
@ -8813,12 +8750,12 @@ snapshots:
|
|||
|
||||
'@types/sax@1.2.7':
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/send@0.17.4':
|
||||
dependencies:
|
||||
'@types/mime': 1.3.5
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/serve-index@1.9.4':
|
||||
dependencies:
|
||||
|
@ -8827,12 +8764,12 @@ snapshots:
|
|||
'@types/serve-static@1.15.7':
|
||||
dependencies:
|
||||
'@types/http-errors': 2.0.4
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
'@types/send': 0.17.4
|
||||
|
||||
'@types/sockjs@0.3.36':
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/stylis@4.2.5': {}
|
||||
|
||||
|
@ -8845,7 +8782,7 @@ snapshots:
|
|||
|
||||
'@types/ws@8.5.13':
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
|
||||
'@types/yargs-parser@21.0.3': {}
|
||||
|
||||
|
@ -9107,7 +9044,7 @@ snapshots:
|
|||
autoprefixer@10.4.20(postcss@8.4.49):
|
||||
dependencies:
|
||||
browserslist: 4.24.2
|
||||
caniuse-lite: 1.0.30001683
|
||||
caniuse-lite: 1.0.30001684
|
||||
fraction.js: 4.3.7
|
||||
normalize-range: 0.1.2
|
||||
picocolors: 1.1.1
|
||||
|
@ -9118,7 +9055,7 @@ snapshots:
|
|||
dependencies:
|
||||
possible-typed-array-names: 1.0.0
|
||||
|
||||
axios@1.7.7:
|
||||
axios@1.7.8:
|
||||
dependencies:
|
||||
follow-redirects: 1.15.9(debug@4.3.7)
|
||||
form-data: 4.0.1
|
||||
|
@ -9232,7 +9169,7 @@ snapshots:
|
|||
|
||||
browserslist@4.24.2:
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001683
|
||||
caniuse-lite: 1.0.30001684
|
||||
electron-to-chromium: 1.5.64
|
||||
node-releases: 2.0.18
|
||||
update-browserslist-db: 1.1.1(browserslist@4.24.2)
|
||||
|
@ -9281,11 +9218,11 @@ snapshots:
|
|||
caniuse-api@3.0.0:
|
||||
dependencies:
|
||||
browserslist: 4.24.2
|
||||
caniuse-lite: 1.0.30001683
|
||||
caniuse-lite: 1.0.30001684
|
||||
lodash.memoize: 4.1.2
|
||||
lodash.uniq: 4.5.0
|
||||
|
||||
caniuse-lite@1.0.30001683: {}
|
||||
caniuse-lite@1.0.30001684: {}
|
||||
|
||||
ccount@2.0.1: {}
|
||||
|
||||
|
@ -9407,6 +9344,8 @@ snapshots:
|
|||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
|
||||
comlink@4.4.2: {}
|
||||
|
||||
comma-separated-tokens@2.0.3: {}
|
||||
|
||||
commander@10.0.1: {}
|
||||
|
@ -9862,7 +9801,7 @@ snapshots:
|
|||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
|
||||
dompurify@3.2.1:
|
||||
dompurify@3.2.2:
|
||||
optionalDependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
|
||||
|
@ -9939,7 +9878,7 @@ snapshots:
|
|||
is-boolean-object: 1.1.2
|
||||
is-callable: 1.2.7
|
||||
is-number-object: 1.0.7
|
||||
is-regex: 1.1.4
|
||||
is-regex: 1.2.0
|
||||
is-string: 1.0.7
|
||||
is-subset: 0.1.1
|
||||
lodash.escape: 4.0.1
|
||||
|
@ -10158,7 +10097,7 @@ snapshots:
|
|||
|
||||
eval@0.1.8:
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
require-like: 0.1.2
|
||||
|
||||
eventemitter3@4.0.7: {}
|
||||
|
@ -10483,7 +10422,11 @@ snapshots:
|
|||
dependencies:
|
||||
get-intrinsic: 1.2.4
|
||||
|
||||
got@14.4.4:
|
||||
gopd@1.1.0:
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.4
|
||||
|
||||
got@14.4.5:
|
||||
dependencies:
|
||||
'@sindresorhus/is': 7.0.1
|
||||
'@szmarczak/http-timer': 5.0.1
|
||||
|
@ -10495,7 +10438,7 @@ snapshots:
|
|||
lowercase-keys: 3.0.0
|
||||
p-cancelable: 4.0.1
|
||||
responselike: 3.0.0
|
||||
type-fest: 4.27.0
|
||||
type-fest: 4.28.0
|
||||
|
||||
graceful-fs@4.2.10: {}
|
||||
|
||||
|
@ -10911,7 +10854,7 @@ snapshots:
|
|||
|
||||
is-extglob@2.1.1: {}
|
||||
|
||||
is-finalizationregistry@1.0.2:
|
||||
is-finalizationregistry@1.1.0:
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
|
||||
|
@ -10967,6 +10910,13 @@ snapshots:
|
|||
call-bind: 1.0.7
|
||||
has-tostringtag: 1.0.2
|
||||
|
||||
is-regex@1.2.0:
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
gopd: 1.1.0
|
||||
has-tostringtag: 1.0.2
|
||||
hasown: 2.0.2
|
||||
|
||||
is-regexp@1.0.0: {}
|
||||
|
||||
is-root@2.1.0: {}
|
||||
|
@ -11022,10 +10972,9 @@ snapshots:
|
|||
|
||||
isobject@3.0.1: {}
|
||||
|
||||
isomorphic-dompurify@2.16.0:
|
||||
isomorphic-dompurify@2.18.0:
|
||||
dependencies:
|
||||
'@types/dompurify': 3.2.0
|
||||
dompurify: 3.2.1
|
||||
dompurify: 3.2.2
|
||||
jsdom: 25.0.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
|
@ -11036,7 +10985,7 @@ snapshots:
|
|||
jest-util@29.7.0:
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.9.0
|
||||
graceful-fs: 4.2.11
|
||||
|
@ -11044,13 +10993,13 @@ snapshots:
|
|||
|
||||
jest-worker@27.5.1:
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
|
||||
jest-worker@29.7.0:
|
||||
dependencies:
|
||||
'@types/node': 22.9.3
|
||||
'@types/node': 22.10.1
|
||||
jest-util: 29.7.0
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
|
@ -11088,7 +11037,7 @@ snapshots:
|
|||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.5
|
||||
is-potential-custom-element-name: 1.0.1
|
||||
nwsapi: 2.2.13
|
||||
nwsapi: 2.2.16
|
||||
parse5: 7.2.1
|
||||
rrweb-cssom: 0.7.1
|
||||
saxes: 6.0.0
|
||||
|
@ -11222,7 +11171,7 @@ snapshots:
|
|||
|
||||
markdown-table@3.0.4: {}
|
||||
|
||||
marked@15.0.2: {}
|
||||
marked@15.0.3: {}
|
||||
|
||||
marked@4.3.0: {}
|
||||
|
||||
|
@ -11869,7 +11818,7 @@ snapshots:
|
|||
schema-utils: 3.3.0
|
||||
webpack: 5.96.1
|
||||
|
||||
nwsapi@2.2.13: {}
|
||||
nwsapi@2.2.16: {}
|
||||
|
||||
oas-kit-common@1.0.8:
|
||||
dependencies:
|
||||
|
@ -12001,7 +11950,7 @@ snapshots:
|
|||
|
||||
package-json@8.1.1:
|
||||
dependencies:
|
||||
got: 14.4.4
|
||||
got: 14.4.5
|
||||
registry-auth-token: 5.0.2
|
||||
registry-url: 6.0.1
|
||||
semver: 7.6.3
|
||||
|
@ -12820,7 +12769,7 @@ snapshots:
|
|||
classnames: 2.5.1
|
||||
core-js: 3.39.0
|
||||
decko: 1.2.0
|
||||
dompurify: 3.2.1
|
||||
dompurify: 3.2.2
|
||||
eventemitter3: 5.0.1
|
||||
json-pointer: 0.6.2
|
||||
lunr: 2.3.9
|
||||
|
@ -12866,15 +12815,15 @@ snapshots:
|
|||
- supports-color
|
||||
- webpack
|
||||
|
||||
reflect.getprototypeof@1.0.6:
|
||||
reflect.getprototypeof@1.0.7:
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
define-properties: 1.2.1
|
||||
es-abstract: 1.23.5
|
||||
es-errors: 1.3.0
|
||||
get-intrinsic: 1.2.4
|
||||
globalthis: 1.0.4
|
||||
which-builtin-type: 1.1.4
|
||||
gopd: 1.0.1
|
||||
which-builtin-type: 1.2.0
|
||||
|
||||
reftools@1.1.9: {}
|
||||
|
||||
|
@ -13523,11 +13472,11 @@ snapshots:
|
|||
|
||||
tiny-warning@1.0.3: {}
|
||||
|
||||
tldts-core@6.1.63: {}
|
||||
tldts-core@6.1.65: {}
|
||||
|
||||
tldts@6.1.63:
|
||||
tldts@6.1.65:
|
||||
dependencies:
|
||||
tldts-core: 6.1.63
|
||||
tldts-core: 6.1.65
|
||||
|
||||
to-regex-range@5.0.1:
|
||||
dependencies:
|
||||
|
@ -13539,7 +13488,7 @@ snapshots:
|
|||
|
||||
tough-cookie@5.0.0:
|
||||
dependencies:
|
||||
tldts: 6.1.63
|
||||
tldts: 6.1.65
|
||||
|
||||
tr46@0.0.3: {}
|
||||
|
||||
|
@ -13563,7 +13512,7 @@ snapshots:
|
|||
|
||||
type-fest@2.19.0: {}
|
||||
|
||||
type-fest@4.27.0: {}
|
||||
type-fest@4.28.0: {}
|
||||
|
||||
type-is@1.6.18:
|
||||
dependencies:
|
||||
|
@ -13592,7 +13541,7 @@ snapshots:
|
|||
gopd: 1.0.1
|
||||
has-proto: 1.0.3
|
||||
is-typed-array: 1.1.13
|
||||
reflect.getprototypeof: 1.0.6
|
||||
reflect.getprototypeof: 1.0.7
|
||||
|
||||
typed-array-length@1.0.7:
|
||||
dependencies:
|
||||
|
@ -13601,7 +13550,7 @@ snapshots:
|
|||
gopd: 1.0.1
|
||||
is-typed-array: 1.1.13
|
||||
possible-typed-array-names: 1.0.0
|
||||
reflect.getprototypeof: 1.0.6
|
||||
reflect.getprototypeof: 1.0.7
|
||||
|
||||
typedarray-to-buffer@3.1.5:
|
||||
dependencies:
|
||||
|
@ -13616,7 +13565,7 @@ snapshots:
|
|||
has-symbols: 1.0.3
|
||||
which-boxed-primitive: 1.0.2
|
||||
|
||||
undici-types@6.19.8: {}
|
||||
undici-types@6.20.0: {}
|
||||
|
||||
undici@6.21.0: {}
|
||||
|
||||
|
@ -13930,13 +13879,14 @@ snapshots:
|
|||
is-string: 1.0.7
|
||||
is-symbol: 1.0.4
|
||||
|
||||
which-builtin-type@1.1.4:
|
||||
which-builtin-type@1.2.0:
|
||||
dependencies:
|
||||
call-bind: 1.0.7
|
||||
function.prototype.name: 1.1.6
|
||||
has-tostringtag: 1.0.2
|
||||
is-async-function: 2.0.0
|
||||
is-date-object: 1.0.5
|
||||
is-finalizationregistry: 1.0.2
|
||||
is-finalizationregistry: 1.1.0
|
||||
is-generator-function: 1.0.10
|
||||
is-regex: 1.1.4
|
||||
is-weakref: 1.0.2
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Awesome Woodpecker
|
||||
|
||||
A curated list of awesome things related to Woodpecker CI.
|
||||
A curated list of assets (tools, projects, blog posts) related to Woodpecker CI.
|
||||
|
||||
If you have some missing resources, please feel free to [open a pull-request](https://github.com/woodpecker-ci/woodpecker/edit/main/docs/docs/92-awesome.md) and add them.
|
||||
If you want to add a new entry, open a [pull-request](https://github.com/woodpecker-ci/woodpecker/edit/main/docs/docs/92-awesome.md).
|
||||
|
||||
## Official Resources
|
||||
|
||||
|
@ -52,7 +52,7 @@ If you have some missing resources, please feel free to [open a pull-request](ht
|
|||
- [Quest For CICD - WoodpeckerCI](https://omaramin.me/posts/woodpecker/)
|
||||
- [Getting started with Woodpecker CI](https://systeemkabouter.eu/getting-started-with-woodpecker-ci.html)
|
||||
- [Installing gitea and woodpecker using binary packages](https://neelex.com/2023/03/26/Installing-gitea-using-binary-packages/)
|
||||
- [Deploying mdbook to codeberg pages using woodpecker CI](https://www.markpitblado.me/blog/deploying-mdbook-to-codeberg-pages-using-woodpecker-ci/)
|
||||
- [Deploying mdbook to codeberg pages using Woodpecker CI](https://www.markpitblado.me/blog/deploying-mdbook-to-codeberg-pages-using-woodpecker-ci/)
|
||||
- [Deploy a Fly app with Woodpecker CI](https://joeroe.io/2024/01/09/deploy-fly-woodpecker-ci.html)
|
||||
- [Ansible - using Woodpecker as an alternative to Semaphore](https://pat-s.me/ansible-using-woodpecker-as-an-alternative-to-semaphore/)
|
||||
- [Simple selfhosted CI/CD with Woodpecker](https://xyquadrat.ch/blog/simple-ci-with-woodpecker/)
|
||||
|
|
|
@ -33,6 +33,17 @@ This will be the next version of Woodpecker.
|
|||
- Removed old API routes: `registry/` -> `registries`, `/authorize/token`
|
||||
- Replaced `registry` command with `repo registry` in cli
|
||||
- Deprecated `secrets`, use `environment` with `from_secret`
|
||||
- CLI commands got restructured to provide a simplified structure:
|
||||
- `woodpecker-cli secret [add|rm|...] --global` is now `woodpecker-cli admin secret [add|rm|...]`
|
||||
- `woodpecker-cli user` is now `woodpecker-cli admin user`
|
||||
- `woodpecker-cli log-level` is now `woodpecker-cli admin log-level`
|
||||
- `woodpecker-cli secret [add|rm|...] --organization` is now `woodpecker-cli org secret [add|rm|...]`
|
||||
- `woodpecker-cli deploy` is now `woodpecker-cli pipeline deploy`
|
||||
- `woodpecker-cli log` is now `woodpecker-cli pipeline log`
|
||||
- `woodpecker-cli cron` is now `woodpecker-cli repo cron`
|
||||
- `woodpecker-cli secret [add|rm|...] --repository` is now `woodpecker-cli repo secret [add|rm|...]`
|
||||
- `woodpecker-cli pipeline logs` is now `woodpecker-cli pipeline log show`
|
||||
- `woodpecker-cli [registry|secret|...] info` is now `woodpecker-cli [registry|secret|...] show`
|
||||
|
||||
## Admin migrations
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ Here you can find documentation for previous versions of Woodpecker.
|
|||
|
||||
| | | |
|
||||
| ------- | ---------- | ------------------------------------------------------------------------------------- |
|
||||
| 2.7.3 | 2024-11-28 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.7.3/docs/docs/) |
|
||||
| 2.7.2 | 2024-11-03 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.7.2/docs/docs/) |
|
||||
| 2.7.1 | 2024-09-07 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.7.1/docs/docs/) |
|
||||
| 2.7.0 | 2024-07-18 | [Documentation](https://github.com/woodpecker-ci/woodpecker/tree/v2.7.0/docs/docs/) |
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
# Welcome to Woodpecker
|
||||
|
||||
Woodpecker is a simple, yet powerful CI/CD engine with great extensibility. It focuses on executing pipelines inside [containers](https://opencontainers.org/).
|
||||
If you are already using containers in your daily workflow, you'll for sure love Woodpecker.
|
||||
|
||||

|
||||
|
||||
## `.woodpecker.yaml`
|
||||
|
||||
- Place your pipeline in a file named `.woodpecker.yaml` in your repository
|
||||
- Pipeline steps can be named as you like
|
||||
- Run any command in the commands section
|
||||
|
||||
```yaml title=".woodpecker.yaml"
|
||||
steps:
|
||||
- name: build
|
||||
image: debian
|
||||
commands:
|
||||
- echo "This is the build step"
|
||||
- name: a-test-step
|
||||
image: debian
|
||||
commands:
|
||||
- echo "Testing.."
|
||||
```
|
||||
|
||||
### Steps are containers
|
||||
|
||||
- Define any container image as context
|
||||
- either use your own and install the needed tools in a custom image
|
||||
- or search for available images that are already tailored for your needs in image registries like [Docker Hub](https://hub.docker.com/search?type=image)
|
||||
- List the commands that should be executed in the container
|
||||
|
||||
```diff
|
||||
steps:
|
||||
- name: build
|
||||
- image: debian
|
||||
+ image: mycompany/image-with-awscli
|
||||
commands:
|
||||
- aws help
|
||||
```
|
||||
|
||||
### File changes are incremental
|
||||
|
||||
- Woodpecker clones the source code in the beginning
|
||||
- File changes are persisted throughout individual steps as the same volume is being mounted in all steps
|
||||
|
||||
```yaml title=".woodpecker.yaml"
|
||||
steps:
|
||||
- name: build
|
||||
image: debian
|
||||
commands:
|
||||
- touch myfile
|
||||
- name: a-test-step
|
||||
image: debian
|
||||
commands:
|
||||
- cat myfile
|
||||
```
|
||||
|
||||
## Plugins are straightforward
|
||||
|
||||
- If you copy the same shell script from project to project
|
||||
- Pack it into a plugin instead
|
||||
- And make the yaml declarative
|
||||
- Plugins are Docker images with your script as an entrypoint
|
||||
|
||||
```dockerfile title="Dockerfile"
|
||||
FROM laszlocloud/kubectl
|
||||
COPY deploy /usr/local/deploy
|
||||
ENTRYPOINT ["/usr/local/deploy"]
|
||||
```
|
||||
|
||||
```bash title="deploy"
|
||||
kubectl apply -f $PLUGIN_TEMPLATE
|
||||
```
|
||||
|
||||
```yaml title=".woodpecker.yaml"
|
||||
steps:
|
||||
- name: deploy-to-k8s
|
||||
image: laszlocloud/my-k8s-plugin
|
||||
settings:
|
||||
template: config/k8s/service.yaml
|
||||
```
|
||||
|
||||
See [plugin docs](./20-usage/51-plugins/51-overview.md).
|
||||
|
||||
## Continue reading
|
||||
|
||||
- [Create a Woodpecker pipeline for your repository](./20-usage/10-intro.md)
|
||||
- [Setup your own Woodpecker instance](./30-administration/00-deployment/00-overview.md)
|
|
@ -1,72 +0,0 @@
|
|||
# Getting started
|
||||
|
||||
## Repository Activation
|
||||
|
||||
To activate your project navigate to your account settings. You will see a list of repositories which can be activated with a simple toggle. When you activate your repository, Woodpecker automatically adds webhooks to your forge (e.g. GitHub, Gitea, ...).
|
||||
|
||||
Webhooks are used to trigger pipeline executions. When you push code to your repository, open a pull request, or create a tag, your forge will automatically send a webhook to Woodpecker which will in turn trigger the pipeline execution.
|
||||
|
||||

|
||||
|
||||
## Required Permissions
|
||||
|
||||
The user who enables a repo in Woodpecker must have `Admin` rights on that repo, so that Woodpecker can add the webhook.
|
||||
|
||||
:::note
|
||||
Note that manually creating webhooks yourself is not possible.
|
||||
This is because webhooks are signed using a per-repository secret key which is not exposed to end users.
|
||||
:::
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure your pipeline you must create a `.woodpecker.yaml` file in the root of your repository. The `.woodpecker.yaml` file is used to define your pipeline steps.
|
||||
|
||||
:::note
|
||||
We support most of YAML 1.2, but preserve some behavior from 1.1 for backward compatibility.
|
||||
Read more at: [https://github.com/go-yaml/yaml](https://github.com/go-yaml/yaml/tree/v3)
|
||||
:::
|
||||
|
||||
Example pipeline configuration:
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- name: build
|
||||
image: golang
|
||||
commands:
|
||||
- go get
|
||||
- go build
|
||||
- go test
|
||||
|
||||
services:
|
||||
- name: postgres
|
||||
image: postgres:9.4.5
|
||||
environment:
|
||||
- POSTGRES_USER=myapp
|
||||
```
|
||||
|
||||
Example pipeline configuration with multiple, serial steps:
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- name: backend
|
||||
image: golang
|
||||
commands:
|
||||
- go get
|
||||
- go build
|
||||
- go test
|
||||
|
||||
- name: frontend
|
||||
image: node:6
|
||||
commands:
|
||||
- npm install
|
||||
- npm test
|
||||
|
||||
- name: notify
|
||||
image: plugins/slack
|
||||
channel: developers
|
||||
username: woodpecker
|
||||
```
|
||||
|
||||
## Execution
|
||||
|
||||
To trigger your first pipeline execution you can push code to your repository, open a pull request, or push a tag. Any of these events triggers a webhook from your forge and execute your pipeline.
|
Binary file not shown.
Before Width: | Height: | Size: 165 KiB |
Binary file not shown.
Before Width: | Height: | Size: 21 KiB |
|
@ -1,90 +0,0 @@
|
|||
# Deployment
|
||||
|
||||
A Woodpecker deployment consists of two parts:
|
||||
|
||||
- A server which is the heart of Woodpecker and ships the web interface.
|
||||
- Next to one server, you can deploy any number of agents which will run the pipelines.
|
||||
|
||||
Each agent is able to process one pipeline step by default.
|
||||
If you have four agents installed and connected to the Woodpecker server, your system will process four workflows in parallel.
|
||||
|
||||
:::tip
|
||||
You can add more agents to increase the number of parallel workflows or set the agent's `WOODPECKER_MAX_WORKFLOWS=1` environment variable to increase the number of parallel workflows for that agent.
|
||||
:::
|
||||
|
||||
## Which version of Woodpecker should I use?
|
||||
|
||||
Woodpecker is having two different kinds of releases: **stable** and **next**.
|
||||
|
||||
### Stable releases
|
||||
|
||||
We release a new version every four weeks and will release the current state of the `main` branch.
|
||||
If there are security fixes or critical bug fixes, we'll release them directly.
|
||||
There are no backports or similar.
|
||||
|
||||
#### Versioning
|
||||
|
||||
We use [Semantic Versioning](https://semver.org/) to be able,
|
||||
to communicate when admins have to do manual migration steps and when they can just bump versions up.
|
||||
|
||||
#### Breaking changes
|
||||
|
||||
As of semver guidelines, breaking changes will be released as a major version. We will hold back
|
||||
breaking changes to not release many majors each containing just a few breaking changes.
|
||||
Prior to the release of a major version, a release candidate (RC) will be published to allow easy testing,
|
||||
the actual release will be about a week later.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
Below are minimal resources requirements for Woodpecker components itself:
|
||||
|
||||
| Component | Memory | CPU |
|
||||
| --------- | ------ | --- |
|
||||
| Server | 200 MB | 1 |
|
||||
| Agent | 32 MB | 1 |
|
||||
|
||||
Note, that those values do not include the operating system or workload (pipelines execution) resources consumption.
|
||||
|
||||
In addition you need at least some kind of database which requires additional resources depending on the selected database system.
|
||||
|
||||
## Installation
|
||||
|
||||
You can install Woodpecker on multiple ways:
|
||||
|
||||
- Using [docker-compose](./10-docker-compose.md) with the official [container images](./10-docker-compose.md#docker-images)
|
||||
- Using [Kubernetes](./20-kubernetes.md) via the Woodpecker Helm chart
|
||||
- Using binaries, DEBs or RPMs you can download from [latest release](https://github.com/woodpecker-ci/woodpecker/releases/latest)
|
||||
|
||||
## Authentication
|
||||
|
||||
Authentication is done using OAuth and is delegated to your forge which is configured using environment variables.
|
||||
|
||||
See the complete reference for all supported forges [here](../11-forges/11-overview.md).
|
||||
|
||||
## Database
|
||||
|
||||
By default Woodpecker uses a SQLite database which requires zero installation or configuration. See the [database settings](../30-database.md) page to further configure it or use MySQL or Postgres.
|
||||
|
||||
## SSL
|
||||
|
||||
Woodpecker supports SSL configuration by using Let's encrypt or by using own certificates. See the [SSL guide](../60-ssl.md). You can also put it behind a [reverse proxy](#behind-a-proxy)
|
||||
|
||||
## Metrics
|
||||
|
||||
A [Prometheus endpoint](../90-prometheus.md) is exposed.
|
||||
|
||||
## Behind a proxy
|
||||
|
||||
See the [proxy guide](../70-proxy.md) if you want to see a setup behind Apache, Nginx, Caddy or ngrok.
|
||||
|
||||
In the case you need to use Woodpecker with a URL path prefix (like: <https://example.org/woodpecker/>), add the root path to [`WOODPECKER_HOST`](../10-server-config.md#woodpecker_host).
|
||||
|
||||
## Third-party installation methods
|
||||
|
||||
:::info
|
||||
These installation methods are not officially supported. If you experience issues with them, please open issues in the specific repositories.
|
||||
:::
|
||||
|
||||
- Using [NixOS](./30-nixos.md) via the [NixOS module](https://search.nixos.org/options?channel=unstable&size=200&sort=relevance&query=woodpecker)
|
||||
- [Using YunoHost](https://apps.yunohost.org/app/woodpecker)
|
||||
- [On Cloudron](https://www.cloudron.io/store/org.woodpecker_ci.cloudronapp.html)
|
|
@ -1,13 +0,0 @@
|
|||
# Forges
|
||||
|
||||
## Supported features
|
||||
|
||||
| Feature | [GitHub](20-github.md) | [Gitea / Forgejo](30-gitea.md) | [Gitlab](40-gitlab.md) | [Bitbucket](50-bitbucket.md) | [Bitbucket Datacenter](60-bitbucket_datacenter.md) |
|
||||
| ------------------------------------------------------------- | :--------------------: | :----------------------------: | :--------------------: | :--------------------------: | :------------------------------------------------: |
|
||||
| Event: Push | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Event: Tag | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Event: Pull-Request | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| Event: Release | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: |
|
||||
| Event: Deploy | :white_check_mark: | :x: | :x: | :x: | :x: |
|
||||
| [Multiple workflows](../../20-usage/25-workflows.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||
| [when.path filter](../../20-usage/20-workflow-syntax.md#path) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: |
|
26
docs/versioned_docs/version-2.8/10-intro/index.md
Normal file
26
docs/versioned_docs/version-2.8/10-intro/index.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Welcome to Woodpecker
|
||||
|
||||
Woodpecker is a CI/CD tool. It is designed to be lightweight, simple to use and fast. Before we dive into the details, let's have a look at some of the basics.
|
||||
|
||||
## Have you ever heard of CI/CD or pipelines?
|
||||
|
||||
Don't worry if you haven't. We'll guide you through the basics. CI/CD stands for Continuous Integration and Continuous Deployment. It's basically like a conveyor belt that moves your code from development to production doing all kinds of
|
||||
checks, tests and routines along the way. A typical pipeline might include the following steps:
|
||||
|
||||
1. Running tests
|
||||
2. Building your application
|
||||
3. Deploying your application
|
||||
|
||||
[Have a deeper look into the idea of CI/CD](https://www.redhat.com/en/topics/devops/what-is-ci-cd)
|
||||
|
||||
## Do you know containers?
|
||||
|
||||
If you are already using containers in your daily workflow, you'll for sure love Woodpecker. If not yet, you'll be amazed how easy it is to get started with [containers](https://opencontainers.org/).
|
||||
|
||||
## Already have access to a Woodpecker instace?
|
||||
|
||||
Then you might want to jump directly into it and [start creating your first pipelines](../20-usage/10-intro.md).
|
||||
|
||||
## Want to start from scratch and deploy your own Woodpecker instance?
|
||||
|
||||
Woodpecker is [pretty lightweight](../30-administration/00-getting-started.md#hardware-requirements) and will even run on your Raspberry Pi. You can follow the [deployment guide](../30-administration/00-getting-started.md) to set up your own Woodpecker instance.
|
109
docs/versioned_docs/version-2.8/20-usage/10-intro.md
Normal file
109
docs/versioned_docs/version-2.8/20-usage/10-intro.md
Normal file
|
@ -0,0 +1,109 @@
|
|||
# Your first pipeline
|
||||
|
||||
Let's get started and create your first pipeline.
|
||||
|
||||
## 1. Repository Activation
|
||||
|
||||
To activate your repository in Woodpecker navigate to the repository list and `New repository`. You will see a list of repositories from your forge (GitHub, Gitlab, ...) which can be activated with a simple click.
|
||||
|
||||

|
||||
|
||||
To enable a repository in Woodpecker you must have `Admin` rights on that repository, so that Woodpecker can add something
|
||||
that is called a webhook (Woodpecker needs it to know about actions like pushes, pull requests, tags, etc.).
|
||||
|
||||
## 2. Define first workflow
|
||||
|
||||
After enabling a repository Woodpecker will listen for changes in your repository. When a change is detected, Woodpecker will check for a pipeline configuration. So let's create a file at `.woodpecker/my-first-workflow.yaml` inside your repository:
|
||||
|
||||
```yaml title=".woodpecker/my-first-workflow.yaml"
|
||||
when:
|
||||
- event: push
|
||||
branch: main
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: debian
|
||||
commands:
|
||||
- echo "This is the build step"
|
||||
- echo "binary-data-123" > executable
|
||||
- name: a-test-step
|
||||
image: golang:1.16
|
||||
commands:
|
||||
- echo "Testing ..."
|
||||
- ./executable
|
||||
```
|
||||
|
||||
**So what did we do here?**
|
||||
|
||||
1. We defined your first workflow file `my-first-workflow.yaml`.
|
||||
2. This workflow will be executed when a push event happens on the `main` branch,
|
||||
because we added a filter using the `when` section:
|
||||
|
||||
```diff
|
||||
+ when:
|
||||
+ - event: push
|
||||
+ branch: main
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
3. We defined two steps: `build` and `a-test-step`
|
||||
|
||||
The steps are executed in the order they are defined, so `build` will be executed first and then `a-test-step`.
|
||||
|
||||
In the `build` step we use the `debian` image and build a "binary file" called `executable`.
|
||||
|
||||
In the `a-test-step` we use the `golang:1.16` image and run the `executable` file to test it.
|
||||
|
||||
You can use any image from registries like the [Docker Hub](https://hub.docker.com/search?type=image) you have access to:
|
||||
|
||||
```diff
|
||||
steps:
|
||||
- name: build
|
||||
- image: debian
|
||||
+ image: mycompany/image-with-awscli
|
||||
commands:
|
||||
- aws help
|
||||
```
|
||||
|
||||
## 3. Push the file and trigger first pipeline
|
||||
|
||||
If you push this file to your repository now, Woodpecker will already execute your first pipeline.
|
||||
|
||||
You can check the pipeline execution in the Woodpecker UI by navigating to the `Pipelines` section of your repository.
|
||||
|
||||

|
||||
|
||||
As you probably noticed, there is another step in called `clone` which is executed before your steps. This step clones your repository into a folder called `workspace` which is available throughout all steps.
|
||||
|
||||
This for example allows the first step to build your application using your source code and as the second step will receive
|
||||
the same workspace it can use the previously built binary and test it.
|
||||
|
||||
## 4. Use a plugin for reusable tasks
|
||||
|
||||
Sometimes you have some tasks that you need to do in every project. For example, deploying to Kubernetes or sending a Slack message. Therefore you can use one of the [official and community plugins](/plugins) or simply [create your own](./51-plugins/20-creating-plugins.md).
|
||||
|
||||
If you want to get a Slack notification after your pipeline has finished, you can add a Slack plugin to your pipeline:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: notify me on Slack
|
||||
image: plugins/slack
|
||||
settings:
|
||||
channel: developers
|
||||
username: woodpecker
|
||||
password:
|
||||
from_secret: slack_token
|
||||
when:
|
||||
status: [success, failure] # This will execute the step on success and failure
|
||||
```
|
||||
|
||||
To configure a plugin you can use the `settings` section.
|
||||
|
||||
Sometime you need to provide secrets to the plugin. You can do this by using the `from_secret` key. The secret must be defined in the Woodpecker UI. You can find more information about secrets [here](./40-secrets.md).
|
||||
|
||||
Similar to the `when` section at the top of the file which is for the complete workflow, you can use the `when` section for each step to define when a step should be executed.
|
||||
|
||||
Learn more about [plugins](./51-plugins/51-overview.md).
|
||||
|
||||
As you now have a basic understanding of how to create a pipeline, you can dive deeper into the [workflow syntax](./20-workflow-syntax.md) and [plugins](./51-plugins/51-overview.md).
|
|
@ -0,0 +1,37 @@
|
|||
# Troubleshooting
|
||||
|
||||
## How to debug clone issues
|
||||
|
||||
(And what to do with an error message like `fatal: could not read Username for 'https://<url>': No such device or address`)
|
||||
|
||||
This error can have multiple causes. If you use internal repositories you might have to enable `WOODPECKER_AUTHENTICATE_PUBLIC_REPOS`:
|
||||
|
||||
```ini
|
||||
WOODPECKER_AUTHENTICATE_PUBLIC_REPOS=true
|
||||
```
|
||||
|
||||
If that does not work, try to make sure the container can reach your git server. In order to do that disable git checkout and make the container "hang":
|
||||
|
||||
```yaml
|
||||
skip_clone: true
|
||||
|
||||
steps:
|
||||
build:
|
||||
image: debian:stable-backports
|
||||
commands:
|
||||
- apt update
|
||||
- apt install -y inetutils-ping wget
|
||||
- ping -c 4 git.example.com
|
||||
- wget git.example.com
|
||||
- sleep 9999999
|
||||
```
|
||||
|
||||
Get the container id using `docker ps` and copy the id from the first column. Enter the container with: `docker exec -it 1234asdf bash` (replace `1234asdf` with the docker id). Then try to clone the git repository with the commands from the failing pipeline:
|
||||
|
||||
```bash
|
||||
git init
|
||||
git remote add origin https://git.example.com/username/repo.git
|
||||
git fetch --no-tags origin +refs/heads/branch:
|
||||
```
|
||||
|
||||
(replace the url AND the branch with the correct values, use your username and password as log in values)
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
@ -1,13 +1,5 @@
|
|||
# Terminology
|
||||
|
||||
## Woodpecker architecture
|
||||
|
||||

|
||||
|
||||
## Pipeline, workflow & step
|
||||
|
||||

|
||||
|
||||
## Glossary
|
||||
|
||||
- **Woodpecker CI**: The project name around Woodpecker.
|
||||
|
@ -33,6 +25,14 @@
|
|||
- **Status**: Status refers to the outcome of a step or [workflow][Workflow] after it has been executed, determined by the internal command exit code. At the end of a [workflow][Workflow], its status is sent to the [forge][Forge].
|
||||
- **Service extension**: Some parts of Woodpecker internal services like secrets storage or config fetcher can be replaced through service extensions.
|
||||
|
||||
## Woodpecker architecture
|
||||
|
||||

|
||||
|
||||
## Pipeline, workflow & step
|
||||
|
||||

|
||||
|
||||
## Pipeline events
|
||||
|
||||
- `push`: A push event is triggered when a commit is pushed to a branch.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue