diff --git a/cli/common/zerologger.go b/cli/common/zerologger.go index 7a1d30e54c..2d3e065cde 100644 --- a/cli/common/zerologger.go +++ b/cli/common/zerologger.go @@ -21,6 +21,6 @@ import ( ) func SetupGlobalLogger(c *cli.Context) error { - common.SetupGlobalLogger(c) + common.SetupGlobalLogger(c, false) return nil } diff --git a/cli/exec/exec.go b/cli/exec/exec.go index dacad27455..de662f7625 100644 --- a/cli/exec/exec.go +++ b/cli/exec/exec.go @@ -33,7 +33,6 @@ import ( "github.com/woodpecker-ci/woodpecker/pipeline/backend/docker" "github.com/woodpecker-ci/woodpecker/pipeline/backend/kubernetes" "github.com/woodpecker-ci/woodpecker/pipeline/backend/local" - "github.com/woodpecker-ci/woodpecker/pipeline/backend/ssh" backendTypes "github.com/woodpecker-ci/woodpecker/pipeline/backend/types" "github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml" "github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/compiler" @@ -49,7 +48,7 @@ var Command = &cli.Command{ Usage: "execute a local pipeline", ArgsUsage: "[path/to/.woodpecker.yaml]", Action: run, - Flags: utils.MergeSlices(common.GlobalFlags, flags, docker.Flags, ssh.Flags, kubernetes.Flags, local.Flags), + Flags: utils.MergeSlices(common.GlobalFlags, flags, docker.Flags, kubernetes.Flags, local.Flags), } func run(c *cli.Context) error { diff --git a/cmd/agent/agent.go b/cmd/agent/agent.go index 9fde7d28f5..aac2a34533 100644 --- a/cmd/agent/agent.go +++ b/cmd/agent/agent.go @@ -49,7 +49,7 @@ import ( ) func run(c *cli.Context) error { - common.SetupGlobalLogger(c) + common.SetupGlobalLogger(c, true) agentConfigPath := c.String("agent-config") hostname := c.String("hostname") diff --git a/cmd/agent/main.go b/cmd/agent/main.go index bed58fc44e..dc4dfd4ac5 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -25,7 +25,6 @@ import ( "github.com/woodpecker-ci/woodpecker/pipeline/backend/docker" "github.com/woodpecker-ci/woodpecker/pipeline/backend/kubernetes" "github.com/woodpecker-ci/woodpecker/pipeline/backend/local" - "github.com/woodpecker-ci/woodpecker/pipeline/backend/ssh" "github.com/woodpecker-ci/woodpecker/shared/utils" "github.com/woodpecker-ci/woodpecker/version" ) @@ -43,7 +42,7 @@ func main() { Action: pinger, }, } - app.Flags = utils.MergeSlices(flags, common.GlobalLoggerFlags, docker.Flags, ssh.Flags, kubernetes.Flags, local.Flags) + app.Flags = utils.MergeSlices(flags, common.GlobalLoggerFlags, docker.Flags, kubernetes.Flags, local.Flags) if err := app.Run(os.Args); err != nil { fmt.Fprintln(os.Stderr, err) diff --git a/cmd/cli/app.go b/cmd/cli/app.go index cda2405266..ae291ba135 100644 --- a/cmd/cli/app.go +++ b/cmd/cli/app.go @@ -41,6 +41,7 @@ func newApp() *cli.App { app.Usage = "command line utility" app.EnableBashCompletion = true app.Flags = common.GlobalFlags + app.Before = common.SetupGlobalLogger app.Commands = []*cli.Command{ pipeline.Command, log.Command, @@ -56,9 +57,5 @@ func newApp() *cli.App { cron.Command, } - for _, command := range app.Commands { - command.Before = common.SetupGlobalLogger - } - return app } diff --git a/cmd/common/logger.go b/cmd/common/logger.go index 242f9343e6..d9b4e9671f 100644 --- a/cmd/common/logger.go +++ b/cmd/common/logger.go @@ -51,7 +51,7 @@ var GlobalLoggerFlags = []cli.Flag{ }, } -func SetupGlobalLogger(c *cli.Context) { +func SetupGlobalLogger(c *cli.Context, printLvl bool) { logLevel := c.String("log-level") pretty := c.Bool("pretty") noColor := c.Bool("nocolor") @@ -96,5 +96,7 @@ func SetupGlobalLogger(c *cli.Context) { log.Logger = log.With().Caller().Logger() } - log.Info().Msgf("LogLevel = %s", zerolog.GlobalLevel().String()) + if printLvl { + log.Info().Msgf("LogLevel = %s", zerolog.GlobalLevel().String()) + } } diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 7ff23cb009..e48fcbb215 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -1471,6 +1471,32 @@ const docTemplate = `{ } } }, + "/repos/repair": { + "post": { + "produces": [ + "text/plain" + ], + "tags": [ + "Repositories" + ], + "summary": "Repair all repositories on the server. Requires admin rights.", + "parameters": [ + { + "type": "string", + "default": "Bearer \u003cpersonal access token\u003e", + "description": "Insert your personal access token", + "name": "Authorization", + "in": "header", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/repos/{repo_id}": { "get": { "produces": [ @@ -2797,8 +2823,8 @@ const docTemplate = `{ } ], "responses": { - "200": { - "description": "OK" + "204": { + "description": "No Content" } } } diff --git a/cmd/server/server.go b/cmd/server/server.go index 7b8d8634f6..6217319869 100644 --- a/cmd/server/server.go +++ b/cmd/server/server.go @@ -55,7 +55,7 @@ import ( ) func run(c *cli.Context) error { - common.SetupGlobalLogger(c) + common.SetupGlobalLogger(c, true) // set gin mode based on log level if zerolog.GlobalLevel() > zerolog.DebugLevel { diff --git a/docs/docs/30-administration/15-agent-config.md b/docs/docs/30-administration/15-agent-config.md index d610764dd9..d9088e3aa3 100644 --- a/docs/docs/30-administration/15-agent-config.md +++ b/docs/docs/30-administration/15-agent-config.md @@ -178,16 +178,12 @@ Configures if the gRPC server certificate should be verified, only valid when `W > Default: `auto-detect` -Configures the backend engine to run pipelines on. Possible values are `auto-detect`, `docker`, `local`, `ssh` or `kubernetes`. +Configures the backend engine to run pipelines on. Possible values are `auto-detect`, `docker`, `local` or `kubernetes`. ### `WOODPECKER_BACKEND_DOCKER_*` See [Docker backend configuration](./22-backends/10-docker.md#configuration) -### `WOODPECKER_BACKEND_SSH_*` - -See [SSH backend configuration](./22-backends/30-ssh.md#configuration) - ### `WOODPECKER_BACKEND_K8S_*` See [Kubernetes backend configuration](./22-backends/40-kubernetes.md#configuration) diff --git a/docs/docs/30-administration/22-backends/30-ssh.md b/docs/docs/30-administration/22-backends/30-ssh.md deleted file mode 100644 index 7d8d5414f5..0000000000 --- a/docs/docs/30-administration/22-backends/30-ssh.md +++ /dev/null @@ -1,46 +0,0 @@ -# SSH backend - -:::danger -The SSH backend will execute the pipelines using SSH on a remote system without any isolation of any kind. -::: - -:::note -This backend is still pretty new and can not be treated as stable. Its implementation and configuration can change at any time. -::: -Since the code run directly on the SSH machine, a malicious pipeline could access and edit files the SSH user has access to and execute every command the remote user is allowed to use. Always restrict the user as far as possible! - -It is recommended to use this backend only for private setups where the code and pipelines can be trusted. You shouldn't use it for a public facing CI where anyone can submit code or add new repositories. - -The backend will use a random directory in $TMPDIR to store the clone code and execute commands. - -## Configuration - -### `WOODPECKER_BACKEND_SSH_ADDRESS` - -> Default: empty - -The SSH host to run steps with `ssh` backend. - -### `WOODPECKER_BACKEND_SSH_USER` - -> Default: empty - -The SSH user to run steps with `ssh` backend. - -### `WOODPECKER_BACKEND_SSH_KEY` - -> Default: empty - -Path to the private SSH key to run steps with `ssh` backend. - -### `WOODPECKER_BACKEND_SSH_KEY_PASSWORD` - -> Default: empty - -The password for the private key to run steps with `ssh` backend. - -### `WOODPECKER_BACKEND_SSH_PASSWORD` - -> Default empty - -The SSH password to run steps with `ssh` backend. diff --git a/docs/docs/91-migrations.md b/docs/docs/91-migrations.md index bcc7f73524..ef7d512235 100644 --- a/docs/docs/91-migrations.md +++ b/docs/docs/91-migrations.md @@ -9,6 +9,7 @@ Some versions need some changes to the server configuration or the pipeline conf - Dropped deprecated `branches:` filter in favor of global [`when.branch`](./20-usage/20-workflow-syntax.md#branch-1) filter - Deprecated `platform:` filter in favor of `labels:`, [read more](./20-usage/20-workflow-syntax.md#filter-by-platform) - Removed `build` alias for `pipeline` command in CLI +- Removed `ssh` backend. Use an agent directly on the SSH machine using the `local` backend. ## 1.0.0 diff --git a/go.mod b/go.mod index 390e87ddf4..6832fce756 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,6 @@ require ( github.com/joho/godotenv v1.5.1 github.com/lib/pq v1.10.9 github.com/mattn/go-sqlite3 v1.14.17 - github.com/melbahja/goph v1.4.0 github.com/moby/moby v23.0.7+incompatible github.com/moby/term v0.5.0 github.com/oklog/ulid/v2 v2.1.0 @@ -105,7 +104,6 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect - github.com/kr/fs v0.1.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/libdns/libdns v0.2.1 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -121,7 +119,6 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/pkg/sftp v1.13.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.44.0 // indirect diff --git a/go.sum b/go.sum index 2ede3c8ee8..417ddfd680 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,6 @@ github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLj github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc= -github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= @@ -66,14 +64,10 @@ github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDror github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/docker/cli v23.0.6+incompatible h1:CScadyCJ2ZKUDpAMZta6vK8I+6/m60VIjGIV7Wg/Eu4= -github.com/docker/cli v23.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v23.0.7+incompatible h1:b+cDxRx/f6P1JR6asBXJOneubySm4nE8CB1B/3g59Sw= github.com/docker/cli v23.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v23.0.6+incompatible h1:aBD4np894vatVX99UTx/GyOUOK4uEcROwA3+bQhEcoU= -github.com/docker/docker v23.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v23.0.7+incompatible h1:6RD6ZfR9LYacFt90L41R/6/SyO+RZ1zWU7+bt6tdRNk= github.com/docker/docker v23.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= @@ -94,8 +88,6 @@ github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYF github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf h1:NrF81UtW8gG2LBGkXFQFqlfNnvMt9WdB46sfdJY4oqc= github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= @@ -258,8 +250,6 @@ github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/q github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -306,14 +296,10 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6 github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/melbahja/goph v1.4.0 h1:z0PgDbBFe66lRYl3v5dGb9aFgPy0kotuQ37QOwSQFqs= -github.com/melbahja/goph v1.4.0/go.mod h1:uG+VfK2Dlhk+O32zFrRlc3kYKTlV6+BtvPWd/kK7U68= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= -github.com/moby/moby v23.0.6+incompatible h1:Ae0U6PR7n9mdIS7oWCXUqM68tzb09ZVQ3IH8iMoChz0= -github.com/moby/moby v23.0.6+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= github.com/moby/moby v23.0.7+incompatible h1:g0V6QLBeYUcZq4tSHdzkTXQCxIs4PvxItxRo27sVqR0= github.com/moby/moby v23.0.7+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= @@ -350,8 +336,6 @@ github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.5 h1:a3RLUqkyjYRtBTZJZ1VRrKbN3zhuPLlUc3sphVz81go= -github.com/pkg/sftp v1.13.5/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= @@ -422,8 +406,6 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/xanzy/go-gitlab v0.93.1 h1:f7J33cw/P9b/8paIOoH0F3H+TFrswvWHs6yUgoTp9LY= -github.com/xanzy/go-gitlab v0.93.1/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= github.com/xanzy/go-gitlab v0.93.2 h1:kNNf3BYNYn/Zkig0B89fma12l36VLcYSGu7OnaRlRDg= github.com/xanzy/go-gitlab v0.93.2/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -479,7 +461,6 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= @@ -537,13 +518,11 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -591,12 +570,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= @@ -630,16 +605,10 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= -k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= -k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= -k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= -k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= diff --git a/pipeline/backend/backend.go b/pipeline/backend/backend.go index 329ca9a20d..4da9306746 100644 --- a/pipeline/backend/backend.go +++ b/pipeline/backend/backend.go @@ -21,7 +21,6 @@ import ( "github.com/woodpecker-ci/woodpecker/pipeline/backend/docker" "github.com/woodpecker-ci/woodpecker/pipeline/backend/kubernetes" "github.com/woodpecker-ci/woodpecker/pipeline/backend/local" - "github.com/woodpecker-ci/woodpecker/pipeline/backend/ssh" "github.com/woodpecker-ci/woodpecker/pipeline/backend/types" ) @@ -34,7 +33,6 @@ func Init(ctx context.Context) { engines = []types.Engine{ docker.New(), local.New(), - ssh.New(), kubernetes.New(ctx), } diff --git a/pipeline/backend/ssh/flags.go b/pipeline/backend/ssh/flags.go deleted file mode 100644 index 630351cba1..0000000000 --- a/pipeline/backend/ssh/flags.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2023 Woodpecker Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package ssh - -import ( - "github.com/urfave/cli/v2" -) - -var Flags = []cli.Flag{ - &cli.StringFlag{ - EnvVars: []string{"WOODPECKER_BACKEND_SSH_ADDRESS"}, - Name: "backend-ssh-address", - Usage: "backend ssh address", - }, - &cli.StringFlag{ - EnvVars: []string{"WOODPECKER_BACKEND_SSH_USER"}, - Name: "backend-ssh-user", - Usage: "backend ssh user", - }, - &cli.StringFlag{ - EnvVars: []string{"WOODPECKER_BACKEND_SSH_KEY"}, - Name: "backend-ssh-key", - Usage: "backend ssh key file", - }, - &cli.StringFlag{ - EnvVars: []string{"WOODPECKER_BACKEND_SSH_KEY_PASSWORD"}, - Name: "backend-ssh-key-password", - Usage: "backend ssh key password", - }, - &cli.StringFlag{ - EnvVars: []string{"WOODPECKER_BACKEND_SSH_PASSWORD"}, - Name: "backend-ssh-password", - Usage: "backend ssh password", - }, -} diff --git a/pipeline/backend/ssh/ssh.go b/pipeline/backend/ssh/ssh.go deleted file mode 100644 index ed83960b32..0000000000 --- a/pipeline/backend/ssh/ssh.go +++ /dev/null @@ -1,166 +0,0 @@ -// 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 ssh - -import ( - "context" - "io" - "strings" - - "github.com/melbahja/goph" - "github.com/rs/zerolog/log" - "github.com/urfave/cli/v2" - - "github.com/woodpecker-ci/woodpecker/pipeline/backend/common" - "github.com/woodpecker-ci/woodpecker/pipeline/backend/types" - "github.com/woodpecker-ci/woodpecker/shared/constant" -) - -type ssh struct { - cmd *goph.Cmd - output io.ReadCloser - client *goph.Client - workingdir string -} - -type readCloser struct { - io.Reader -} - -func (c readCloser) Close() error { - return nil -} - -// New returns a new ssh Engine. -func New() types.Engine { - return &ssh{} -} - -func (e *ssh) Name() string { - return "ssh" -} - -func (e *ssh) IsAvailable(ctx context.Context) bool { - c, ok := ctx.Value(types.CliContext).(*cli.Context) - return ok && c.String("backend-ssh-address") != "" && c.String("backend-ssh-user") != "" && (c.String("backend-ssh-key") != "" || c.String("backend-ssh-password") != "") -} - -func (e *ssh) Load(ctx context.Context) error { - cmd, err := e.client.Command("/bin/env", "mktemp", "-d", "-p", "/tmp", "woodpecker-ssh-XXXXXXXXXX") - if err != nil { - return err - } - - dir, err := cmd.Output() - if err != nil { - return err - } - - e.workingdir = string(dir) - c, ok := ctx.Value(types.CliContext).(*cli.Context) - if !ok { - return types.ErrNoCliContextFound - } - address := c.String("backend-ssh-address") - user := c.String("backend-ssh-user") - var auth goph.Auth - if file := c.String("backend-ssh-key"); file != "" { - keyAuth, err := goph.Key(file, c.String("backend-ssh-key-password")) - if err != nil { - return err - } - auth = append(auth, keyAuth...) - } - if password := c.String("backend-ssh-password"); password != "" { - auth = append(auth, goph.Password(password)...) - } - client, err := goph.New(user, address, auth) - if err != nil { - return err - } - e.client = client - return nil -} - -// SetupWorkflow create the workflow environment. -func (e *ssh) SetupWorkflow(context.Context, *types.Config, string) error { - return nil -} - -// StartStep start the step. -func (e *ssh) StartStep(ctx context.Context, step *types.Step, taskUUID string) error { - log.Trace().Str("taskUUID", taskUUID).Msgf("Start step %s", step.Name) - - // Get environment variables - var command []string - for a, b := range step.Environment { - if a != "HOME" && a != "SHELL" { // Don't override $HOME and $SHELL - command = append(command, a+"="+b) - } - } - - if step.Image == constant.DefaultCloneImage { - // Default clone step - command = append(command, "CI_WORKSPACE="+e.workingdir+"/"+step.Environment["CI_REPO"]) - command = append(command, "plugin-git") - } else { - // Use "image name" as run command - command = append(command, step.Image) - command = append(command, "-c") - - // TODO: use commands directly - script := common.GenerateScript(step.Commands) - // Deleting the initial lines removes netrc support but adds compatibility for more shells like fish - command = append(command, "cd "+e.workingdir+"/"+step.Environment["CI_REPO"]+" && "+script[strings.Index(script, "\n\n")+2:]) - } - - // Prepare command - var err error - e.cmd, err = e.client.CommandContext(ctx, "/bin/env", command...) - if err != nil { - return err - } - - // Get output and redirect Stderr to Stdout - std, _ := e.cmd.StdoutPipe() - e.output = readCloser{std} - e.cmd.Stderr = e.cmd.Stdout - - return e.cmd.Start() -} - -// WaitStep for the pipeline step to complete and returns -// the completion results. -func (e *ssh) WaitStep(context.Context, *types.Step, string) (*types.State, error) { - return &types.State{ - Exited: true, - }, e.cmd.Wait() -} - -// TailStep the pipeline step logs. -func (e *ssh) TailStep(context.Context, *types.Step, string) (io.ReadCloser, error) { - return e.output, nil -} - -// DestroyWorkflow delete the workflow environment. -func (e *ssh) DestroyWorkflow(context.Context, *types.Config, string) error { - e.client.Close() - sftp, err := e.client.NewSftp() - if err != nil { - return err - } - - return sftp.RemoveDirectory(e.workingdir) -} diff --git a/server/api/repo.go b/server/api/repo.go index e4ea4322c3..34a4258505 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -401,70 +401,15 @@ func DeleteRepo(c *gin.Context) { // @Summary Repair a repository // @Router /repos/{repo_id}/repair [post] // @Produce plain -// @Success 200 +// @Success 204 // @Tags Repositories // @Param Authorization header string true "Insert your personal access token" default(Bearer ) // @Param repo_id path int true "the repository id" func RepairRepo(c *gin.Context) { - forge := server.Config.Services.Forge - _store := store.FromContext(c) repo := session.Repo(c) - user := session.User(c) - - // creates the jwt token used to verify the repository - t := token.New(token.HookToken, repo.FullName) - sig, err := t.Sign(repo.Hash) - if err != nil { - c.String(http.StatusInternalServerError, err.Error()) - return - } - - // reconstruct the link - host := server.Config.Server.WebhookHost - link := fmt.Sprintf( - "%s/api/hook?access_token=%s", - host, - sig, - ) - - from, err := forge.Repo(c, user, repo.ForgeRemoteID, repo.Owner, repo.Name) - if err != nil { - log.Error().Err(err).Msgf("get repo '%s/%s' from forge", repo.Owner, repo.Name) - c.AbortWithStatus(http.StatusInternalServerError) - return - } + repairRepo(c, repo, true) - if repo.FullName != from.FullName { - // create a redirection - err = _store.CreateRedirection(&model.Redirection{RepoID: repo.ID, FullName: repo.FullName}) - if err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) - return - } - } - - repo.Update(from) - if err := _store.UpdateRepo(repo); err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) - return - } - repo.Perm.Pull = from.Perm.Pull - repo.Perm.Push = from.Perm.Push - repo.Perm.Admin = from.Perm.Admin - if err := _store.PermUpsert(repo.Perm); err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) - return - } - - if err := forge.Deactivate(c, user, repo, host); err != nil { - log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName) - } - if err := forge.Activate(c, user, repo, link); err != nil { - c.String(http.StatusInternalServerError, err.Error()) - return - } - - c.Status(http.StatusOK) + c.Status(http.StatusNoContent) } // MoveRepo @@ -575,3 +520,91 @@ func GetAllRepos(c *gin.Context) { c.JSON(http.StatusOK, repos) } + +// RepairAllRepos +// +// @Summary Repair all repositories on the server. Requires admin rights. +// @Router /repos/repair [post] +// @Produce plain +// @Success 204 +// @Tags Repositories +// @Param Authorization header string true "Insert your personal access token" default(Bearer ) +func RepairAllRepos(c *gin.Context) { + _store := store.FromContext(c) + + repos, err := _store.RepoListAll(true, &model.ListOptions{All: true}) + if err != nil { + c.String(http.StatusInternalServerError, "Error fetching repository list. %s", err) + return + } + + for _, r := range repos { + repairRepo(c, r, false) + if c.Writer.Written() { + return + } + } + + c.Status(http.StatusNoContent) +} + +func repairRepo(c *gin.Context, repo *model.Repo, withPerms bool) { + forge := server.Config.Services.Forge + _store := store.FromContext(c) + user := session.User(c) + + // creates the jwt token used to verify the repository + t := token.New(token.HookToken, repo.FullName) + sig, err := t.Sign(repo.Hash) + if err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + + // reconstruct the link + host := server.Config.Server.WebhookHost + link := fmt.Sprintf( + "%s/api/hook?access_token=%s", + host, + sig, + ) + + from, err := forge.Repo(c, user, repo.ForgeRemoteID, repo.Owner, repo.Name) + if err != nil { + log.Error().Err(err).Msgf("get repo '%s/%s' from forge", repo.Owner, repo.Name) + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + if repo.FullName != from.FullName { + // create a redirection + err = _store.CreateRedirection(&model.Redirection{RepoID: repo.ID, FullName: repo.FullName}) + if err != nil { + _ = c.AbortWithError(http.StatusInternalServerError, err) + return + } + } + + repo.Update(from) + if err := _store.UpdateRepo(repo); err != nil { + _ = c.AbortWithError(http.StatusInternalServerError, err) + return + } + if withPerms { + repo.Perm.Pull = from.Perm.Pull + repo.Perm.Push = from.Perm.Push + repo.Perm.Admin = from.Perm.Admin + if err := _store.PermUpsert(repo.Perm); err != nil { + _ = c.AbortWithError(http.StatusInternalServerError, err) + return + } + } + + if err := forge.Deactivate(c, user, repo, host); err != nil { + log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName) + } + if err := forge.Activate(c, user, repo, link); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } +} diff --git a/server/forge/bitbucket/bitbucket.go b/server/forge/bitbucket/bitbucket.go index d10583bcb5..5b691f8956 100644 --- a/server/forge/bitbucket/bitbucket.go +++ b/server/forge/bitbucket/bitbucket.go @@ -158,11 +158,11 @@ func (c *config) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRe if remoteID.IsValid() { name = string(remoteID) } - repos, err := c.Repos(ctx, u) - if err != nil { - return nil, err - } - if len(owner) == 0 { + if owner == "" { + repos, err := c.Repos(ctx, u) + if err != nil { + return nil, err + } for _, repo := range repos { if string(repo.ForgeRemoteID) == name { owner = repo.Owner @@ -187,20 +187,26 @@ func (c *config) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRe func (c *config) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) { client := c.newClient(ctx, u) - var all []*model.Repo - - resp, err := client.ListWorkspaces(&internal.ListWorkspacesOpts{ - PageLen: 100, - Role: "member", + workspaces, err := shared_utils.Paginate(func(page int) ([]*internal.Workspace, error) { + resp, err := client.ListWorkspaces(&internal.ListWorkspacesOpts{ + Page: page, + PageLen: 100, + Role: "member", + }) + if err != nil { + return nil, err + } + return resp.Values, nil }) if err != nil { - return all, err + return nil, err } - for _, workspace := range resp.Values { + var all []*model.Repo + for _, workspace := range workspaces { repos, err := client.ListReposAll(workspace.Slug) if err != nil { - return all, err + return nil, err } for _, repo := range repos { perm, err := client.GetPermission(repo.FullName) @@ -305,11 +311,19 @@ func (c *config) Activate(ctx context.Context, u *model.User, r *model.Repo, lin func (c *config) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { client := c.newClient(ctx, u) - hooks, err := client.ListHooks(r.Owner, r.Name, &internal.ListOpts{}) + hooks, err := shared_utils.Paginate(func(page int) ([]*internal.Hook, error) { + hooks, err := client.ListHooks(r.Owner, r.Name, &internal.ListOpts{ + Page: page, + }) + if err != nil { + return nil, err + } + return hooks.Values, nil + }) if err != nil { return err } - hook := matchingHooks(hooks.Values, link) + hook := matchingHooks(hooks, link) if hook != nil { return client.DeleteHook(r.Owner, r.Name, hook.UUID) } diff --git a/server/forge/bitbucket/fixtures/handler.go b/server/forge/bitbucket/fixtures/handler.go index b200bb219d..707a6dd732 100644 --- a/server/forge/bitbucket/fixtures/handler.go +++ b/server/forge/bitbucket/fixtures/handler.go @@ -103,7 +103,11 @@ func getRepoHooks(c *gin.Context) { case "hook_empty": c.String(200, "{}") default: - c.String(200, repoHookPayload) + if c.Query("page") == "" || c.Query("page") == "1" { + c.String(200, repoHookPayload) + } else { + c.String(200, "{\"values\":[]}") + } } } @@ -174,7 +178,11 @@ func getUserRepos(c *gin.Context) { case "Bearer repos_not_found", "Bearer 70efdf2e": c.String(404, "") default: - c.String(200, userRepoPayload) + if c.Query("page") == "" || c.Query("page") == "1" { + c.String(200, userRepoPayload) + } else { + c.String(200, "{\"values\":[]}") + } } } diff --git a/server/forge/bitbucket/internal/client.go b/server/forge/bitbucket/internal/client.go index 04eca60919..7159ad0c59 100644 --- a/server/forge/bitbucket/internal/client.go +++ b/server/forge/bitbucket/internal/client.go @@ -23,6 +23,8 @@ import ( "net/http" "net/url" + shared_utils "github.com/woodpecker-ci/woodpecker/shared/utils" + "golang.org/x/oauth2" "golang.org/x/oauth2/bitbucket" ) @@ -110,21 +112,13 @@ func (c *Client) ListRepos(workspace string, opts *ListOpts) (*RepoResp, error) } func (c *Client) ListReposAll(workspace string) ([]*Repo, error) { - page := 1 - var repos []*Repo - - for { + return shared_utils.Paginate(func(page int) ([]*Repo, error) { resp, err := c.ListRepos(workspace, &ListOpts{Page: page, PageLen: 100}) if err != nil { - return repos, err - } - repos = append(repos, resp.Values...) - if len(resp.Next) == 0 { - break + return nil, err } - page = resp.Page + 1 - } - return repos, nil + return resp.Values, nil + }) } func (c *Client) FindHook(owner, name, id string) (*Hook, error) { diff --git a/server/forge/gitea/fixtures/handler.go b/server/forge/gitea/fixtures/handler.go index 41742fcfa3..6f0dbeb144 100644 --- a/server/forge/gitea/fixtures/handler.go +++ b/server/forge/gitea/fixtures/handler.go @@ -41,7 +41,12 @@ func Handler() http.Handler { } func listRepoHooks(c *gin.Context) { - c.String(200, listRepoHookPayloads) + page := c.Query("page") + if page != "" && page != "1" { + c.String(200, "[]") + } else { + c.String(200, listRepoHookPayloads) + } } func getRepo(c *gin.Context) { diff --git a/server/forge/gitea/gitea.go b/server/forge/gitea/gitea.go index 0d2f218863..7e4a322fda 100644 --- a/server/forge/gitea/gitea.go +++ b/server/forge/gitea/gitea.go @@ -411,7 +411,15 @@ func (c *Gitea) Deactivate(ctx context.Context, u *model.User, r *model.Repo, li return err } - hooks, _, err := client.ListRepoHooks(r.Owner, r.Name, gitea.ListHooksOptions{}) + hooks, err := shared_utils.Paginate(func(page int) ([]*gitea.Hook, error) { + hooks, _, err := client.ListRepoHooks(r.Owner, r.Name, gitea.ListHooksOptions{ + ListOptions: gitea.ListOptions{ + Page: page, + PageSize: c.perPage(ctx), + }, + }) + return hooks, err + }) if err != nil { return err } diff --git a/server/grpc/rpc.go b/server/grpc/rpc.go index 7cbdd9a82a..1d98b97a3f 100644 --- a/server/grpc/rpc.go +++ b/server/grpc/rpc.go @@ -284,11 +284,9 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error { // make sure writes to pubsub are non blocking (https://github.com/woodpecker-ci/woodpecker/blob/c919f32e0b6432a95e1a6d3d0ad662f591adf73f/server/logging/log.go#L9) go func() { - for _, wf := range currentPipeline.Workflows { - for _, step := range wf.Children { - if err := s.logger.Close(c, step.ID); err != nil { - logger.Error().Err(err).Msgf("done: cannot close log stream for step %d", step.ID) - } + for _, step := range workflow.Children { + if err := s.logger.Close(c, step.ID); err != nil { + logger.Error().Err(err).Msgf("done: cannot close log stream for step %d", step.ID) } } }() diff --git a/server/router/api.go b/server/router/api.go index dbec95cce4..0a22f9e9c1 100644 --- a/server/router/api.go +++ b/server/router/api.go @@ -73,6 +73,7 @@ func apiRoutes(e *gin.RouterGroup) { repo.GET("/lookup/*repo_full_name", session.SetRepo(), session.SetPerm(), session.MustPull, api.LookupRepo) repo.POST("", session.MustUser(), api.PostRepo) repo.GET("", session.MustAdmin(), api.GetAllRepos) + repo.POST("/repair", session.MustAdmin(), api.RepairAllRepos) repoBase := repo.Group("/:repo_id") { repoBase.Use(session.SetRepo()) diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json index 03ff4bde08..0b233bbdbb 100644 --- a/web/src/assets/locales/en.json +++ b/web/src/assets/locales/en.json @@ -440,7 +440,11 @@ "none": "There are no repositories yet.", "view": "View repository", "settings": "Repository settings", - "disabled": "Disabled" + "disabled": "Disabled", + "repair": { + "repair": "Repair all", + "success": "Repositories repaired" + } } } }, diff --git a/web/src/components/admin/settings/AdminReposTab.vue b/web/src/components/admin/settings/AdminReposTab.vue index 757e7ffd39..c131d19629 100644 --- a/web/src/components/admin/settings/AdminReposTab.vue +++ b/web/src/components/admin/settings/AdminReposTab.vue @@ -1,5 +1,14 @@