From 37e04a4c836967ae8540401fc34b739995e517b4 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Wed, 24 Jan 2024 15:29:04 +0100 Subject: [PATCH 01/44] Add go plugins --- cmd/server/flags.go | 5 ++ cmd/server/setup.go | 16 ++++-- go.mod | 4 ++ go.sum | 56 ++++++++++++++++--- server/forge/configFetcher.go | 5 +- server/pipeline/restart.go | 3 +- server/plugins/config/extension.go | 6 +- server/plugins/config/http.go | 6 +- shared/addon/hashicorp/configservice/args.go | 21 +++++++ .../addon/hashicorp/configservice/client.go | 37 ++++++++++++ .../hashicorp/configservice/interface.go | 30 ++++++++++ shared/addon/hashicorp/configservice/load.go | 8 +++ .../addon/hashicorp/configservice/server.go | 25 +++++++++ .../addon/hashicorp/examples/configservice.go | 24 ++++++++ shared/addon/hashicorp/load.go | 41 ++++++++++++++ shared/addon/hashicorp/pluginaddon.go | 9 +++ shared/addon/hashicorp/serve.go | 14 +++++ 17 files changed, 287 insertions(+), 23 deletions(-) create mode 100644 shared/addon/hashicorp/configservice/args.go create mode 100644 shared/addon/hashicorp/configservice/client.go create mode 100644 shared/addon/hashicorp/configservice/interface.go create mode 100644 shared/addon/hashicorp/configservice/load.go create mode 100644 shared/addon/hashicorp/configservice/server.go create mode 100644 shared/addon/hashicorp/examples/configservice.go create mode 100644 shared/addon/hashicorp/load.go create mode 100644 shared/addon/hashicorp/pluginaddon.go create mode 100644 shared/addon/hashicorp/serve.go diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 8d79986cf2..39ac6312d2 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -261,6 +261,11 @@ var flags = append([]cli.Flag{ Name: "addons", Usage: "list of addon files", }, + &cli.StringSliceFlag{ + EnvVars: []string{"WOODPECKER_ADDON_CONFIG_SERVICE"}, + Name: "addons-config-service", + Usage: "list of addon files", + }, // // backend options for pipeline compiler // diff --git a/cmd/server/setup.go b/cmd/server/setup.go index b7ebb8aeb4..fa529bc4f3 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -51,6 +51,8 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/server/store/datastore" "go.woodpecker-ci.org/woodpecker/v2/server/store/types" "go.woodpecker-ci.org/woodpecker/v2/shared/addon" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/configservice" addonTypes "go.woodpecker-ci.org/woodpecker/v2/shared/addon/types" ) @@ -321,12 +323,14 @@ func setupSignatureKeys(_store store.Store) (crypto.PrivateKey, crypto.PublicKey } func setupConfigService(c *cli.Context) (config.Extension, error) { - addonExt, err := addon.Load[config.Extension](c.StringSlice("addons"), addonTypes.TypeConfigService) - if err != nil { - return nil, err - } - if addonExt != nil { - return addonExt.Value, nil + if addon := c.String("addons-config-service"); addon != "" { + addonExt, err := hashicorp.Load(addon, configservice.Addon) + if err != nil { + return nil, err + } + if addonExt != nil { + return addonExt.Value, nil + } } if endpoint := c.String("config-service-endpoint"); endpoint != "" { diff --git a/go.mod b/go.mod index 4bfdc32553..3ff9aeb1b9 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/google/go-github/v58 v58.0.0 github.com/google/tink/go v1.7.0 github.com/gorilla/securecookie v1.1.2 + github.com/hashicorp/go-plugin v1.4.3 github.com/jellydator/ttlcache/v3 v3.1.1 github.com/joho/godotenv v1.5.1 github.com/kinbiko/jsonassert v1.1.1 @@ -107,6 +108,7 @@ require ( github.com/hashicorp/go-hclog v1.2.0 // indirect github.com/hashicorp/go-retryablehttp v0.7.5 // indirect github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -121,10 +123,12 @@ require ( github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mholt/acmez v1.2.0 // indirect github.com/miekg/dns v1.1.57 // indirect + github.com/mitchellh/go-testing-interface v1.0.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oklog/run v1.0.0 // indirect 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.1.1 // indirect diff --git a/go.sum b/go.sum index c2ca7726dc..67ef91ddcd 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= code.gitea.io/sdk/gitea v0.17.1 h1:3jCPOG2ojbl8AcfaUCRYLT5MUcBMFwS0OSK2mA5Zok8= code.gitea.io/sdk/gitea v0.17.1/go.mod h1:aCnBqhHpoEWA180gMbaCtdX9Pl6BWBAuuP2miadoTNM= codeberg.org/6543/go-yaml2json v1.0.0 h1:heGqo9VEi7gY2yNqjj7X4ADs5nzlFIbGsJtgYDLrnig= @@ -36,6 +37,7 @@ github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4 github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= @@ -48,6 +50,7 @@ github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLI github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -85,6 +88,8 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/expr-lang/expr v1.15.8 h1:FL8+d3rSSP4tmK9o+vKfSMqqpGL8n15pEPiHcnBpxoI= github.com/expr-lang/expr v1.15.8/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -147,7 +152,12 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -185,12 +195,17 @@ github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pw github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-plugin v1.4.3 h1:DXmvivbWD5qdiBts9TpBC7BYL1Aia5sxbRgQB+v6UZM= +github.com/hashicorp/go-plugin v1.4.3/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= @@ -237,6 +252,8 @@ github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= @@ -308,6 +325,9 @@ 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.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/moby/moby v24.0.7+incompatible h1:RrVT5IXBn85mRtFKP+gFwVLCcnNPZIgN3NVRJG9Le+4= github.com/moby/moby v24.0.7+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= @@ -324,6 +344,8 @@ github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -349,6 +371,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= @@ -417,8 +440,6 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= -github.com/xanzy/go-gitlab v0.95.2 h1:4p0IirHqEp5f0baK/aQqr4TR57IsD+8e4fuyAA1yi88= -github.com/xanzy/go-gitlab v0.95.2/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xanzy/go-gitlab v0.96.0 h1:LGkZ+wSNMRtHIBaYE4Hq3dZVjprwHv3Y1+rhKU3WETs= github.com/xanzy/go-gitlab v0.96.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -478,6 +499,10 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= @@ -487,7 +512,11 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -503,9 +532,11 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -513,6 +544,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -566,8 +598,11 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -588,10 +623,19 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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 v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 h1:/jFB8jK5R3Sq3i/lmeZO0cATSzFfZaJq1J2Euan3XKU= google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= @@ -621,17 +665,13 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 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.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= -k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= k8s.io/api v0.29.1 h1:DAjwWX/9YT7NQD4INu49ROJuZAAAP/Ijki48GUPzxqw= k8s.io/api v0.29.1/go.mod h1:7Kl10vBRUXhnQQI8YR/R327zXC8eJ7887/+Ybta+RoQ= -k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= -k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= k8s.io/apimachinery v0.29.1 h1:KY4/E6km/wLBguvCZv8cKTeOwwOBqFNjwJIdMkMbbRc= k8s.io/apimachinery v0.29.1/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= -k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= -k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= k8s.io/client-go v0.29.1 h1:19B/+2NGEwnFLzt0uB5kNJnfTsbV8w6TgQRz9l7ti7A= k8s.io/client-go v0.29.1/go.mod h1:TDG/psL9hdet0TI9mGyHJSgRkW3H9JZk2dNEUS7bRks= k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= diff --git a/server/forge/configFetcher.go b/server/forge/configFetcher.go index ef989b34c5..8571448d8b 100644 --- a/server/forge/configFetcher.go +++ b/server/forge/configFetcher.go @@ -64,16 +64,13 @@ func (cf *ConfigFetcher) Fetch(ctx context.Context) (files []*types.FileMeta, er } if cf.configExtension != nil { - fetchCtx, cancel := context.WithTimeout(ctx, cf.timeout) - defer cancel() // ok here as we only try http fetching once, returning on fail and success - log.Trace().Msgf("configFetcher[%s]: getting config from external http service", cf.repo.FullName) netrc, err := cf.forge.Netrc(cf.user, cf.repo) if err != nil { return nil, fmt.Errorf("could not get Netrc data from forge: %w", err) } - newConfigs, useOld, err := cf.configExtension.FetchConfig(fetchCtx, cf.repo, cf.pipeline, files, netrc) + newConfigs, useOld, err := cf.configExtension.FetchConfig(cf.repo, cf.pipeline, files, netrc, cf.timeout) if err != nil { log.Error().Err(err).Msg("could not fetch config via http") return nil, fmt.Errorf("could not fetch config via http: %w", err) diff --git a/server/pipeline/restart.go b/server/pipeline/restart.go index 73933ceeb3..ac4df606ed 100644 --- a/server/pipeline/restart.go +++ b/server/pipeline/restart.go @@ -18,6 +18,7 @@ import ( "context" "errors" "fmt" + "time" "github.com/rs/zerolog/log" @@ -55,7 +56,7 @@ func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipelin currentFileMeta[i] = &forge_types.FileMeta{Name: cfg.Name, Data: cfg.Data} } - newConfig, useOld, err := server.Config.Services.ConfigService.FetchConfig(ctx, repo, lastPipeline, currentFileMeta, netrc) + newConfig, useOld, err := server.Config.Services.ConfigService.FetchConfig(repo, lastPipeline, currentFileMeta, netrc, time.Minute /*TODO use config*/) if err != nil { return nil, &ErrBadRequest{ Msg: fmt.Sprintf("On fetching external pipeline config: %s", err), diff --git a/server/plugins/config/extension.go b/server/plugins/config/extension.go index 9b9778af60..52a06e1048 100644 --- a/server/plugins/config/extension.go +++ b/server/plugins/config/extension.go @@ -15,12 +15,12 @@ package config import ( - "context" + "time" - forge_types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" + forgetypes "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" "go.woodpecker-ci.org/woodpecker/v2/server/model" ) type Extension interface { - FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forge_types.FileMeta, netrc *model.Netrc) (configData []*forge_types.FileMeta, useOld bool, err error) + FetchConfig(repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forgetypes.FileMeta, netrc *model.Netrc, timeout time.Duration) (configData []*forgetypes.FileMeta, useOld bool, err error) } diff --git a/server/plugins/config/http.go b/server/plugins/config/http.go index 5dbc2909bc..dab8e03b63 100644 --- a/server/plugins/config/http.go +++ b/server/plugins/config/http.go @@ -18,6 +18,7 @@ import ( "context" "crypto" "fmt" + "time" forge_types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" "go.woodpecker-ci.org/woodpecker/v2/server/model" @@ -50,7 +51,10 @@ func NewHTTP(endpoint string, privateKey crypto.PrivateKey) Extension { return &http{endpoint, privateKey} } -func (cp *http) FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forge_types.FileMeta, netrc *model.Netrc) (configData []*forge_types.FileMeta, useOld bool, err error) { +func (cp *http) FetchConfig(repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forge_types.FileMeta, netrc *model.Netrc, timeout time.Duration) (configData []*forge_types.FileMeta, useOld bool, err error) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + currentConfigs := make([]*config, len(currentFileMeta)) for i, pipe := range currentFileMeta { currentConfigs[i] = &config{Name: pipe.Name, Data: string(pipe.Data)} diff --git a/shared/addon/hashicorp/configservice/args.go b/shared/addon/hashicorp/configservice/args.go new file mode 100644 index 0000000000..84e65e1831 --- /dev/null +++ b/shared/addon/hashicorp/configservice/args.go @@ -0,0 +1,21 @@ +package configservice + +import ( + "time" + + forgetypes "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type arguments struct { + Repo *model.Repo `json:"repo"` + Pipeline *model.Pipeline `json:"pipeline"` + CurrentFileMeta []*forgetypes.FileMeta `json:"current_file_meta"` + Netrc *model.Netrc `json:"netrc"` + Timeout time.Duration `json:"timeout"` +} + +type response struct { + ConfigData []*forgetypes.FileMeta `json:"config_data"` + UseOld bool `json:"use_old"` +} diff --git a/shared/addon/hashicorp/configservice/client.go b/shared/addon/hashicorp/configservice/client.go new file mode 100644 index 0000000000..407b18cf78 --- /dev/null +++ b/shared/addon/hashicorp/configservice/client.go @@ -0,0 +1,37 @@ +package configservice + +import ( + "encoding/json" + "net/rpc" + "time" + + forgetypes "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type ExtensionRPC struct{ client *rpc.Client } + +func (g *ExtensionRPC) FetchConfig(repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forgetypes.FileMeta, netrc *model.Netrc, timeout time.Duration) ([]*forgetypes.FileMeta, bool, error) { + args, err := json.Marshal(&arguments{ + Repo: repo, + Pipeline: pipeline, + CurrentFileMeta: currentFileMeta, + Netrc: netrc, + Timeout: timeout, + }) + if err != nil { + return nil, false, err + } + var jsonResp []byte + err = g.client.Call("Plugin.FetchConfig", args, &jsonResp) + if err != nil { + return nil, false, err + } + + var resp response + err = json.Unmarshal(jsonResp, &resp) + if err != nil { + return nil, false, err + } + return resp.ConfigData, resp.UseOld, err +} diff --git a/shared/addon/hashicorp/configservice/interface.go b/shared/addon/hashicorp/configservice/interface.go new file mode 100644 index 0000000000..bc4dd192e1 --- /dev/null +++ b/shared/addon/hashicorp/configservice/interface.go @@ -0,0 +1,30 @@ +package configservice + +import ( + "net/rpc" + + "github.com/hashicorp/go-plugin" + + "go.woodpecker-ci.org/woodpecker/v2/server/plugins/config" +) + +type ExtensionPlugin struct { + Impl config.Extension +} + +func (p *ExtensionPlugin) Key() string { + return "configservice" +} + +func (p *ExtensionPlugin) WithImpl(t config.Extension) plugin.Plugin { + p.Impl = t + return p +} + +func (p *ExtensionPlugin) Server(*plugin.MuxBroker) (any, error) { + return &ExtensionRPCServer{Impl: p.Impl}, nil +} + +func (*ExtensionPlugin) Client(_ *plugin.MuxBroker, c *rpc.Client) (any, error) { + return &ExtensionRPC{client: c}, nil +} diff --git a/shared/addon/hashicorp/configservice/load.go b/shared/addon/hashicorp/configservice/load.go new file mode 100644 index 0000000000..37620ea8df --- /dev/null +++ b/shared/addon/hashicorp/configservice/load.go @@ -0,0 +1,8 @@ +package configservice + +import ( + "go.woodpecker-ci.org/woodpecker/v2/server/plugins/config" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" +) + +var Addon hashicorp.Plugin[config.Extension] = &ExtensionPlugin{} diff --git a/shared/addon/hashicorp/configservice/server.go b/shared/addon/hashicorp/configservice/server.go new file mode 100644 index 0000000000..5e1973afa9 --- /dev/null +++ b/shared/addon/hashicorp/configservice/server.go @@ -0,0 +1,25 @@ +package configservice + +import ( + "encoding/json" + + "go.woodpecker-ci.org/woodpecker/v2/server/plugins/config" +) + +type ExtensionRPCServer struct { + Impl config.Extension +} + +func (s *ExtensionRPCServer) FetchConfig(args []byte, resp *[]byte) error { + var a arguments + err := json.Unmarshal(args, &a) + configs, useOld, err := s.Impl.FetchConfig(a.Repo, a.Pipeline, a.CurrentFileMeta, a.Netrc, a.Timeout) + if err != nil { + return err + } + *resp, err = json.Marshal(response{ + ConfigData: configs, + UseOld: useOld, + }) + return err +} diff --git a/shared/addon/hashicorp/examples/configservice.go b/shared/addon/hashicorp/examples/configservice.go new file mode 100644 index 0000000000..c507545a52 --- /dev/null +++ b/shared/addon/hashicorp/examples/configservice.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + "time" + + forgetypes "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" + "go.woodpecker-ci.org/woodpecker/v2/server/model" + "go.woodpecker-ci.org/woodpecker/v2/server/plugins/config" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/configservice" +) + +type ExtensionImpl struct { +} + +func (g *ExtensionImpl) FetchConfig(repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forgetypes.FileMeta, netrc *model.Netrc, timeout time.Duration) (configData []*forgetypes.FileMeta, useOld bool, err error) { + fmt.Println("hello world from hashicorp addon") + return currentFileMeta[:len(currentFileMeta)-1], false, nil +} + +func main() { + hashicorp.Serve[config.Extension](configservice.Addon, &ExtensionImpl{}) +} diff --git a/shared/addon/hashicorp/load.go b/shared/addon/hashicorp/load.go new file mode 100644 index 0000000000..a1fbe60803 --- /dev/null +++ b/shared/addon/hashicorp/load.go @@ -0,0 +1,41 @@ +package hashicorp + +import ( + "os/exec" + + "github.com/hashicorp/go-plugin" +) + +type Addon[T any] struct { + Value T +} + +func Load[T any](file string, a Plugin[T]) (*Addon[T], error) { + client := plugin.NewClient(&plugin.ClientConfig{ + HandshakeConfig: HandshakeConfig, + Plugins: map[string]plugin.Plugin{ + a.Key(): a, + }, + Cmd: exec.Command(file), + }) + // TODO defer client.Kill() + + rpcClient, err := client.Client() + if err != nil { + return nil, err + } + + raw, err := rpcClient.Dispense(a.Key()) + if err != nil { + return nil, err + } + + extension, _ := raw.(T) + return &Addon[T]{Value: extension}, nil +} + +var HandshakeConfig = plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "WOODPECKER_PLUGIN", + MagicCookieValue: "woodpecker-plugin-magic-cookie-value", +} diff --git a/shared/addon/hashicorp/pluginaddon.go b/shared/addon/hashicorp/pluginaddon.go new file mode 100644 index 0000000000..a074f52dd0 --- /dev/null +++ b/shared/addon/hashicorp/pluginaddon.go @@ -0,0 +1,9 @@ +package hashicorp + +import "github.com/hashicorp/go-plugin" + +type Plugin[T any] interface { + plugin.Plugin + Key() string + WithImpl(T) plugin.Plugin +} diff --git a/shared/addon/hashicorp/serve.go b/shared/addon/hashicorp/serve.go new file mode 100644 index 0000000000..29ea9d4877 --- /dev/null +++ b/shared/addon/hashicorp/serve.go @@ -0,0 +1,14 @@ +package hashicorp + +import ( + "github.com/hashicorp/go-plugin" +) + +func Serve[T any](addon Plugin[T], impl T) { + plugin.Serve(&plugin.ServeConfig{ + HandshakeConfig: HandshakeConfig, + Plugins: map[string]plugin.Plugin{ + addon.Key(): addon.WithImpl(impl), + }, + }) +} From 2c7e26ce4f0152159fd1364b6ad827c085c5308f Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 28 Jan 2024 13:03:56 +0100 Subject: [PATCH 02/44] Support registry service --- cmd/server/flags.go | 7 +- cmd/server/setup.go | 19 +++-- .../addon/hashicorp/registryservice/args.go | 20 +++++ .../addon/hashicorp/registryservice/client.go | 82 +++++++++++++++++++ .../hashicorp/registryservice/interface.go | 30 +++++++ .../addon/hashicorp/registryservice/load.go | 8 ++ .../addon/hashicorp/registryservice/server.go | 69 ++++++++++++++++ 7 files changed, 226 insertions(+), 9 deletions(-) create mode 100644 shared/addon/hashicorp/registryservice/args.go create mode 100644 shared/addon/hashicorp/registryservice/client.go create mode 100644 shared/addon/hashicorp/registryservice/interface.go create mode 100644 shared/addon/hashicorp/registryservice/load.go create mode 100644 shared/addon/hashicorp/registryservice/server.go diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 39ac6312d2..9bd947b1e9 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -264,7 +264,12 @@ var flags = append([]cli.Flag{ &cli.StringSliceFlag{ EnvVars: []string{"WOODPECKER_ADDON_CONFIG_SERVICE"}, Name: "addons-config-service", - Usage: "list of addon files", + Usage: "config service addon", + }, + &cli.StringSliceFlag{ + EnvVars: []string{"WOODPECKER_ADDON_REGISTRY_SERVICE"}, + Name: "addons-registry-service", + Usage: "registry service addon", }, // // backend options for pipeline compiler diff --git a/cmd/server/setup.go b/cmd/server/setup.go index fa529bc4f3..25f6398584 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -53,6 +53,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/shared/addon" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/configservice" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/registryservice" addonTypes "go.woodpecker-ci.org/woodpecker/v2/shared/addon/types" ) @@ -126,12 +127,14 @@ func setupSecretService(c *cli.Context, s model.SecretStore) (model.SecretServic } func setupRegistryService(c *cli.Context, s store.Store) (model.RegistryService, error) { - addonService, err := addon.Load[model.RegistryService](c.StringSlice("addons"), addonTypes.TypeRegistryService) - if err != nil { - return nil, err - } - if addonService != nil { - return addonService.Value, nil + if a := c.String("addons-registry-service"); a != "" { + addonExt, err := hashicorp.Load(a, registryservice.Addon) + if err != nil { + return nil, err + } + if addonExt != nil { + return addonExt.Value, nil + } } if c.String("docker-config") != "" { @@ -323,8 +326,8 @@ func setupSignatureKeys(_store store.Store) (crypto.PrivateKey, crypto.PublicKey } func setupConfigService(c *cli.Context) (config.Extension, error) { - if addon := c.String("addons-config-service"); addon != "" { - addonExt, err := hashicorp.Load(addon, configservice.Addon) + if a := c.String("addons-config-service"); a != "" { + addonExt, err := hashicorp.Load(a, configservice.Addon) if err != nil { return nil, err } diff --git a/shared/addon/hashicorp/registryservice/args.go b/shared/addon/hashicorp/registryservice/args.go new file mode 100644 index 0000000000..f1662bb8df --- /dev/null +++ b/shared/addon/hashicorp/registryservice/args.go @@ -0,0 +1,20 @@ +package registryservice + +import ( + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type argumentsFindDelete struct { + Repo *model.Repo `json:"repo"` + Name string `json:"name"` +} + +type argumentsCreateUpdate struct { + Repo *model.Repo `json:"repo"` + Registry *model.Registry `json:"registry"` +} + +type argumentsList struct { + Repo *model.Repo `json:"repo"` + ListOptions *model.ListOptions `json:"list_options"` +} diff --git a/shared/addon/hashicorp/registryservice/client.go b/shared/addon/hashicorp/registryservice/client.go new file mode 100644 index 0000000000..33bbb147cb --- /dev/null +++ b/shared/addon/hashicorp/registryservice/client.go @@ -0,0 +1,82 @@ +package registryservice + +import ( + "encoding/json" + "net/rpc" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type RPC struct{ client *rpc.Client } + +func (g *RPC) RegistryFind(repo *model.Repo, name string) (*model.Registry, error) { + args, err := json.Marshal(&argumentsFindDelete{ + Repo: repo, + Name: name, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.RegistryFind", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp *model.Registry + return resp, json.Unmarshal(jsonResp, resp) +} + +func (g *RPC) RegistryList(repo *model.Repo, listOptions *model.ListOptions) ([]*model.Registry, error) { + args, err := json.Marshal(&argumentsList{ + Repo: repo, + ListOptions: listOptions, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.RegistryList", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp []*model.Registry + return resp, json.Unmarshal(jsonResp, resp) +} + +func (g *RPC) RegistryDelete(repo *model.Repo, name string) error { + args, err := json.Marshal(&argumentsFindDelete{ + Repo: repo, + Name: name, + }) + if err != nil { + return err + } + var jsonResp []byte + return g.client.Call("Plugin.RegistryDelete", args, &jsonResp) +} + +func (g *RPC) RegistryCreate(repo *model.Repo, registry *model.Registry) error { + args, err := json.Marshal(&argumentsCreateUpdate{ + Repo: repo, + Registry: registry, + }) + if err != nil { + return err + } + var jsonResp []byte + return g.client.Call("Plugin.RegistryCreate", args, &jsonResp) +} + +func (g *RPC) RegistryUpdate(repo *model.Repo, registry *model.Registry) error { + args, err := json.Marshal(&argumentsCreateUpdate{ + Repo: repo, + Registry: registry, + }) + if err != nil { + return err + } + var jsonResp []byte + return g.client.Call("Plugin.RegistryUpdate", args, &jsonResp) +} diff --git a/shared/addon/hashicorp/registryservice/interface.go b/shared/addon/hashicorp/registryservice/interface.go new file mode 100644 index 0000000000..2874d5bb49 --- /dev/null +++ b/shared/addon/hashicorp/registryservice/interface.go @@ -0,0 +1,30 @@ +package registryservice + +import ( + "net/rpc" + + "github.com/hashicorp/go-plugin" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type Plugin struct { + Impl model.RegistryService +} + +func (p *Plugin) Key() string { + return "configservice" +} + +func (p *Plugin) WithImpl(t model.RegistryService) plugin.Plugin { + p.Impl = t + return p +} + +func (p *Plugin) Server(*plugin.MuxBroker) (any, error) { + return &RPCServer{Impl: p.Impl}, nil +} + +func (*Plugin) Client(_ *plugin.MuxBroker, c *rpc.Client) (any, error) { + return &RPC{client: c}, nil +} diff --git a/shared/addon/hashicorp/registryservice/load.go b/shared/addon/hashicorp/registryservice/load.go new file mode 100644 index 0000000000..7300bcf5a6 --- /dev/null +++ b/shared/addon/hashicorp/registryservice/load.go @@ -0,0 +1,8 @@ +package registryservice + +import ( + "go.woodpecker-ci.org/woodpecker/v2/server/model" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" +) + +var Addon hashicorp.Plugin[model.RegistryService] = &Plugin{} diff --git a/shared/addon/hashicorp/registryservice/server.go b/shared/addon/hashicorp/registryservice/server.go new file mode 100644 index 0000000000..02105c1635 --- /dev/null +++ b/shared/addon/hashicorp/registryservice/server.go @@ -0,0 +1,69 @@ +package registryservice + +import ( + "encoding/json" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type RPCServer struct { + Impl model.RegistryService +} + +func (s *RPCServer) RegistryFind(args []byte, resp *[]byte) error { + var a argumentsFindDelete + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + registry, err := s.Impl.RegistryFind(a.Repo, a.Name) + if err != nil { + return err + } + *resp, err = json.Marshal(registry) + return err +} + +func (s *RPCServer) RegistryDelete(args []byte, resp *[]byte) error { + var a argumentsFindDelete + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.RegistryDelete(a.Repo, a.Name) +} + +func (s *RPCServer) RegistryCreate(args []byte, resp *[]byte) error { + var a argumentsCreateUpdate + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.RegistryCreate(a.Repo, a.Registry) +} + +func (s *RPCServer) RegistryUpdate(args []byte, resp *[]byte) error { + var a argumentsCreateUpdate + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.RegistryUpdate(a.Repo, a.Registry) +} + +func (s *RPCServer) RegistryList(args []byte, resp *[]byte) error { + var a argumentsList + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + registries, err := s.Impl.RegistryList(a.Repo, a.ListOptions) + if err != nil { + return err + } + *resp, err = json.Marshal(registries) + return err +} From 734daa37bd9f731ca257d742f98c21b985ca429b Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 28 Jan 2024 13:08:31 +0100 Subject: [PATCH 03/44] Support env service --- cmd/server/flags.go | 5 ++++ cmd/server/setup.go | 15 ++++++---- .../addon/hashicorp/environservice/client.go | 25 ++++++++++++++++ .../hashicorp/environservice/interface.go | 30 +++++++++++++++++++ shared/addon/hashicorp/environservice/load.go | 8 +++++ .../addon/hashicorp/environservice/server.go | 25 ++++++++++++++++ .../addon/hashicorp/registryservice/client.go | 2 +- 7 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 shared/addon/hashicorp/environservice/client.go create mode 100644 shared/addon/hashicorp/environservice/interface.go create mode 100644 shared/addon/hashicorp/environservice/load.go create mode 100644 shared/addon/hashicorp/environservice/server.go diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 9bd947b1e9..3c7e511d07 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -271,6 +271,11 @@ var flags = append([]cli.Flag{ Name: "addons-registry-service", Usage: "registry service addon", }, + &cli.StringSliceFlag{ + EnvVars: []string{"WOODPECKER_ADDON_ENVIRONMENT_SERVICE"}, + Name: "addons-environ-service", + Usage: "environment service addon", + }, // // backend options for pipeline compiler // diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 25f6398584..82b7a557c0 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -53,6 +53,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/shared/addon" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/configservice" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/environservice" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/registryservice" addonTypes "go.woodpecker-ci.org/woodpecker/v2/shared/addon/types" ) @@ -147,12 +148,14 @@ func setupRegistryService(c *cli.Context, s store.Store) (model.RegistryService, } func setupEnvironService(c *cli.Context, _ store.Store) (model.EnvironService, error) { - addonService, err := addon.Load[model.EnvironService](c.StringSlice("addons"), addonTypes.TypeEnvironmentService) - if err != nil { - return nil, err - } - if addonService != nil { - return addonService.Value, nil + if a := c.String("addons-environ-service"); a != "" { + addonExt, err := hashicorp.Load(a, environservice.Addon) + if err != nil { + return nil, err + } + if addonExt != nil { + return addonExt.Value, nil + } } return environments.Parse(c.StringSlice("environment")), nil diff --git a/shared/addon/hashicorp/environservice/client.go b/shared/addon/hashicorp/environservice/client.go new file mode 100644 index 0000000000..828755735a --- /dev/null +++ b/shared/addon/hashicorp/environservice/client.go @@ -0,0 +1,25 @@ +package environservice + +import ( + "encoding/json" + "net/rpc" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type RPC struct{ client *rpc.Client } + +func (g *RPC) EnvironList(repo *model.Repo) ([]*model.Environ, error) { + args, err := json.Marshal(repo) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.EnvironList", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp []*model.Environ + return resp, json.Unmarshal(jsonResp, &resp) +} diff --git a/shared/addon/hashicorp/environservice/interface.go b/shared/addon/hashicorp/environservice/interface.go new file mode 100644 index 0000000000..c825c4304c --- /dev/null +++ b/shared/addon/hashicorp/environservice/interface.go @@ -0,0 +1,30 @@ +package environservice + +import ( + "net/rpc" + + "github.com/hashicorp/go-plugin" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type Plugin struct { + Impl model.EnvironService +} + +func (p *Plugin) Key() string { + return "configservice" +} + +func (p *Plugin) WithImpl(t model.EnvironService) plugin.Plugin { + p.Impl = t + return p +} + +func (p *Plugin) Server(*plugin.MuxBroker) (any, error) { + return &RPCServer{Impl: p.Impl}, nil +} + +func (*Plugin) Client(_ *plugin.MuxBroker, c *rpc.Client) (any, error) { + return &RPC{client: c}, nil +} diff --git a/shared/addon/hashicorp/environservice/load.go b/shared/addon/hashicorp/environservice/load.go new file mode 100644 index 0000000000..1fa11963ee --- /dev/null +++ b/shared/addon/hashicorp/environservice/load.go @@ -0,0 +1,8 @@ +package environservice + +import ( + "go.woodpecker-ci.org/woodpecker/v2/server/model" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" +) + +var Addon hashicorp.Plugin[model.EnvironService] = &Plugin{} diff --git a/shared/addon/hashicorp/environservice/server.go b/shared/addon/hashicorp/environservice/server.go new file mode 100644 index 0000000000..3cd8d895b0 --- /dev/null +++ b/shared/addon/hashicorp/environservice/server.go @@ -0,0 +1,25 @@ +package environservice + +import ( + "encoding/json" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type RPCServer struct { + Impl model.EnvironService +} + +func (s *RPCServer) EnvironList(args []byte, resp *[]byte) error { + var r *model.Repo + err := json.Unmarshal(args, r) + if err != nil { + return err + } + env, err := s.Impl.EnvironList(r) + if err != nil { + return err + } + *resp, err = json.Marshal(env) + return err +} diff --git a/shared/addon/hashicorp/registryservice/client.go b/shared/addon/hashicorp/registryservice/client.go index 33bbb147cb..152498b2d4 100644 --- a/shared/addon/hashicorp/registryservice/client.go +++ b/shared/addon/hashicorp/registryservice/client.go @@ -42,7 +42,7 @@ func (g *RPC) RegistryList(repo *model.Repo, listOptions *model.ListOptions) ([] } var resp []*model.Registry - return resp, json.Unmarshal(jsonResp, resp) + return resp, json.Unmarshal(jsonResp, &resp) } func (g *RPC) RegistryDelete(repo *model.Repo, name string) error { From cb6b9d0b4d69fe71b8397d92b2a951473efcf44e Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 28 Jan 2024 13:09:09 +0100 Subject: [PATCH 04/44] Remove old types --- shared/addon/types/types.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/shared/addon/types/types.go b/shared/addon/types/types.go index 158df423b1..5355b6d2a1 100644 --- a/shared/addon/types/types.go +++ b/shared/addon/types/types.go @@ -3,10 +3,7 @@ package types type Type string const ( - TypeForge Type = "forge" - TypeBackend Type = "backend" - TypeConfigService Type = "config_service" - TypeSecretService Type = "secret_service" - TypeEnvironmentService Type = "environment_service" - TypeRegistryService Type = "registry_service" + TypeForge Type = "forge" + TypeBackend Type = "backend" + TypeSecretService Type = "secret_service" ) From 248947133631792d2b3aebe339379cfd8ba97891 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 28 Jan 2024 13:11:54 +0100 Subject: [PATCH 05/44] reformat --- shared/addon/hashicorp/examples/configservice.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shared/addon/hashicorp/examples/configservice.go b/shared/addon/hashicorp/examples/configservice.go index c507545a52..454981fdff 100644 --- a/shared/addon/hashicorp/examples/configservice.go +++ b/shared/addon/hashicorp/examples/configservice.go @@ -11,8 +11,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/configservice" ) -type ExtensionImpl struct { -} +type ExtensionImpl struct{} func (g *ExtensionImpl) FetchConfig(repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*forgetypes.FileMeta, netrc *model.Netrc, timeout time.Duration) (configData []*forgetypes.FileMeta, useOld bool, err error) { fmt.Println("hello world from hashicorp addon") From 6f6e72a55660996664e72ce9c8a41b2f58689359 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 28 Jan 2024 14:05:53 +0100 Subject: [PATCH 06/44] Add secret service --- cmd/server/flags.go | 5 + cmd/server/setup.go | 15 +- shared/addon/hashicorp/secretservice/args.go | 41 +++ .../addon/hashicorp/secretservice/client.go | 276 ++++++++++++++++++ .../hashicorp/secretservice/interface.go | 30 ++ shared/addon/hashicorp/secretservice/load.go | 8 + .../addon/hashicorp/secretservice/server.go | 189 ++++++++++++ shared/addon/types/types.go | 5 +- 8 files changed, 560 insertions(+), 9 deletions(-) create mode 100644 shared/addon/hashicorp/secretservice/args.go create mode 100644 shared/addon/hashicorp/secretservice/client.go create mode 100644 shared/addon/hashicorp/secretservice/interface.go create mode 100644 shared/addon/hashicorp/secretservice/load.go create mode 100644 shared/addon/hashicorp/secretservice/server.go diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 3c7e511d07..41f7959705 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -276,6 +276,11 @@ var flags = append([]cli.Flag{ Name: "addons-environ-service", Usage: "environment service addon", }, + &cli.StringSliceFlag{ + EnvVars: []string{"WOODPECKER_ADDON_SECRET_SERVICE"}, + Name: "addons-secret-service", + Usage: "secret service addon", + }, // // backend options for pipeline compiler // diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 82b7a557c0..eb0ebd2e2f 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -55,6 +55,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/configservice" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/environservice" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/registryservice" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/secretservice" addonTypes "go.woodpecker-ci.org/woodpecker/v2/shared/addon/types" ) @@ -116,12 +117,14 @@ func setupQueue(c *cli.Context, s store.Store) queue.Queue { } func setupSecretService(c *cli.Context, s model.SecretStore) (model.SecretService, error) { - addonService, err := addon.Load[model.SecretService](c.StringSlice("addons"), addonTypes.TypeSecretService) - if err != nil { - return nil, err - } - if addonService != nil { - return addonService.Value, nil + if a := c.String("addons-secret-service"); a != "" { + addonExt, err := hashicorp.Load(a, secretservice.Addon) + if err != nil { + return nil, err + } + if addonExt != nil { + return addonExt.Value, nil + } } return secrets.New(c.Context, s), nil diff --git a/shared/addon/hashicorp/secretservice/args.go b/shared/addon/hashicorp/secretservice/args.go new file mode 100644 index 0000000000..d7df15c519 --- /dev/null +++ b/shared/addon/hashicorp/secretservice/args.go @@ -0,0 +1,41 @@ +package secretservice + +import ( + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type argumentsFindDelete struct { + Repo *model.Repo `json:"repo"` + Name string `json:"name"` +} + +type argumentsCreateUpdate struct { + Repo *model.Repo `json:"repo"` + Secret *model.Secret `json:"secret"` +} + +type argumentsList struct { + Repo *model.Repo `json:"repo"` + ListOptions *model.ListOptions `json:"list_options"` +} + +type argumentsListPipeline struct { + Repo *model.Repo `json:"repo"` + Pipeline *model.Pipeline `json:"pipeline"` + ListOptions *model.ListOptions `json:"list_options"` +} + +type argumentsOrgFindDelete struct { + OrgID int64 `json:"org_id"` + Name string `json:"name"` +} + +type argumentsOrgCreateUpdate struct { + OrgID int64 `json:"org_id"` + Secret *model.Secret `json:"secret"` +} + +type argumentsOrgList struct { + OrgID int64 `json:"org_id"` + ListOptions *model.ListOptions `json:"list_options"` +} diff --git a/shared/addon/hashicorp/secretservice/client.go b/shared/addon/hashicorp/secretservice/client.go new file mode 100644 index 0000000000..b709cad50d --- /dev/null +++ b/shared/addon/hashicorp/secretservice/client.go @@ -0,0 +1,276 @@ +package secretservice + +import ( + "encoding/json" + "net/rpc" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type RPC struct{ client *rpc.Client } + +func (g *RPC) SecretListPipeline(repo *model.Repo, pipeline *model.Pipeline, listOptions *model.ListOptions) ([]*model.Secret, error) { + args, err := json.Marshal(&argumentsListPipeline{ + Repo: repo, + Pipeline: pipeline, + ListOptions: listOptions, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.SecretListPipeline", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp []*model.Secret + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) SecretFind(repo *model.Repo, name string) (*model.Secret, error) { + args, err := json.Marshal(&argumentsFindDelete{ + Repo: repo, + Name: name, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.SecretFind", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp *model.Secret + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) SecretList(repo *model.Repo, listOptions *model.ListOptions) ([]*model.Secret, error) { + args, err := json.Marshal(&argumentsList{ + Repo: repo, + ListOptions: listOptions, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.SecretList", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp []*model.Secret + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) SecretCreate(repo *model.Repo, secret *model.Secret) error { + args, err := json.Marshal(&argumentsCreateUpdate{ + Repo: repo, + Secret: secret, + }) + if err != nil { + return err + } + var jsonResp []byte + err = g.client.Call("Plugin.SecretCreate", args, &jsonResp) + if err != nil { + return err + } + + var resp []byte + return json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) SecretUpdate(repo *model.Repo, secret *model.Secret) error { + args, err := json.Marshal(&argumentsCreateUpdate{ + Repo: repo, + Secret: secret, + }) + if err != nil { + return err + } + var jsonResp []byte + err = g.client.Call("Plugin.SecretUpdate", args, &jsonResp) + if err != nil { + return err + } + + var resp []byte + return json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) SecretDelete(repo *model.Repo, name string) error { + args, err := json.Marshal(&argumentsFindDelete{ + Repo: repo, + Name: name, + }) + if err != nil { + return err + } + var jsonResp []byte + err = g.client.Call("Plugin.SecretDelete", args, &jsonResp) + if err != nil { + return err + } + + var resp []byte + return json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) OrgSecretFind(orgID int64, name string) (*model.Secret, error) { + args, err := json.Marshal(&argumentsOrgFindDelete{ + OrgID: orgID, + Name: name, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.OrgSecretFind", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp *model.Secret + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) OrgSecretList(orgID int64, listOptions *model.ListOptions) ([]*model.Secret, error) { + args, err := json.Marshal(&argumentsOrgList{ + OrgID: orgID, + ListOptions: listOptions, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.OrgSecretList", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp []*model.Secret + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) OrgSecretCreate(orgID int64, secret *model.Secret) error { + args, err := json.Marshal(&argumentsOrgCreateUpdate{ + OrgID: orgID, + Secret: secret, + }) + if err != nil { + return err + } + var jsonResp []byte + err = g.client.Call("Plugin.OrgSecretCreate", args, &jsonResp) + if err != nil { + return err + } + + var resp []byte + return json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) OrgSecretUpdate(orgID int64, secret *model.Secret) error { + args, err := json.Marshal(&argumentsOrgCreateUpdate{ + OrgID: orgID, + Secret: secret, + }) + if err != nil { + return err + } + var jsonResp []byte + err = g.client.Call("Plugin.OrgSecretUpdate", args, &jsonResp) + if err != nil { + return err + } + + var resp []byte + return json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) OrgSecretDelete(orgID int64, name string) error { + args, err := json.Marshal(&argumentsOrgFindDelete{ + OrgID: orgID, + Name: name, + }) + if err != nil { + return err + } + var jsonResp []byte + err = g.client.Call("Plugin.OrgSecretDelete", args, &jsonResp) + if err != nil { + return err + } + + var resp []byte + return json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) GlobalSecretFind(name string) (*model.Secret, error) { + var jsonResp []byte + err := g.client.Call("Plugin.GlobalSecretFind", name, &jsonResp) + if err != nil { + return nil, err + } + + var resp *model.Secret + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) GlobalSecretList(options *model.ListOptions) ([]*model.Secret, error) { + args, err := json.Marshal(options) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.GlobalSecretList", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp []*model.Secret + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) GlobalSecretCreate(secret *model.Secret) error { + args, err := json.Marshal(secret) + if err != nil { + return err + } + var jsonResp []byte + err = g.client.Call("Plugin.GlobalSecretCreate", args, &jsonResp) + if err != nil { + return err + } + + var resp []byte + return json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) GlobalSecretUpdate(secret *model.Secret) error { + args, err := json.Marshal(secret) + if err != nil { + return err + } + var jsonResp []byte + err = g.client.Call("Plugin.GlobalSecretUpdate", args, &jsonResp) + if err != nil { + return err + } + + var resp []byte + return json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) GlobalSecretDelete(name string) error { + var jsonResp []byte + err := g.client.Call("Plugin.GlobalSecretDelete", name, &jsonResp) + if err != nil { + return err + } + + var resp []byte + return json.Unmarshal(jsonResp, &resp) +} diff --git a/shared/addon/hashicorp/secretservice/interface.go b/shared/addon/hashicorp/secretservice/interface.go new file mode 100644 index 0000000000..f6c6fd8e53 --- /dev/null +++ b/shared/addon/hashicorp/secretservice/interface.go @@ -0,0 +1,30 @@ +package secretservice + +import ( + "net/rpc" + + "github.com/hashicorp/go-plugin" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type Plugin struct { + Impl model.SecretService +} + +func (p *Plugin) Key() string { + return "configservice" +} + +func (p *Plugin) WithImpl(t model.SecretService) plugin.Plugin { + p.Impl = t + return p +} + +func (p *Plugin) Server(*plugin.MuxBroker) (any, error) { + return &RPCServer{Impl: p.Impl}, nil +} + +func (*Plugin) Client(_ *plugin.MuxBroker, c *rpc.Client) (any, error) { + return &RPC{client: c}, nil +} diff --git a/shared/addon/hashicorp/secretservice/load.go b/shared/addon/hashicorp/secretservice/load.go new file mode 100644 index 0000000000..baf8fdb4fd --- /dev/null +++ b/shared/addon/hashicorp/secretservice/load.go @@ -0,0 +1,8 @@ +package secretservice + +import ( + "go.woodpecker-ci.org/woodpecker/v2/server/model" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" +) + +var Addon hashicorp.Plugin[model.SecretService] = &Plugin{} diff --git a/shared/addon/hashicorp/secretservice/server.go b/shared/addon/hashicorp/secretservice/server.go new file mode 100644 index 0000000000..bc736736b4 --- /dev/null +++ b/shared/addon/hashicorp/secretservice/server.go @@ -0,0 +1,189 @@ +package secretservice + +import ( + "encoding/json" + + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type RPCServer struct { + Impl model.SecretService +} + +func (s *RPCServer) SecretListPipeline(args []byte, resp *[]byte) error { + var a argumentsListPipeline + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + secrets, err := s.Impl.SecretListPipeline(a.Repo, a.Pipeline, a.ListOptions) + if err != nil { + return err + } + *resp, err = json.Marshal(secrets) + return err +} + +func (s *RPCServer) SecretFind(args []byte, resp *[]byte) error { + var a argumentsFindDelete + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + secret, err := s.Impl.SecretFind(a.Repo, a.Name) + if err != nil { + return err + } + *resp, err = json.Marshal(secret) + return err +} + +func (s *RPCServer) SecretList(args []byte, resp *[]byte) error { + var a argumentsList + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + secrets, err := s.Impl.SecretList(a.Repo, a.ListOptions) + if err != nil { + return err + } + *resp, err = json.Marshal(secrets) + return err +} + +func (s *RPCServer) SecretDelete(args []byte, resp *[]byte) error { + var a argumentsFindDelete + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.SecretDelete(a.Repo, a.Name) +} + +func (s *RPCServer) SecretCreate(args []byte, resp *[]byte) error { + var a argumentsCreateUpdate + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.SecretCreate(a.Repo, a.Secret) +} + +func (s *RPCServer) SecretUpdate(args []byte, resp *[]byte) error { + var a argumentsCreateUpdate + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.SecretUpdate(a.Repo, a.Secret) +} + +func (s *RPCServer) OrgSecretFind(args []byte, resp *[]byte) error { + var a argumentsOrgFindDelete + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + secret, err := s.Impl.OrgSecretFind(a.OrgID, a.Name) + if err != nil { + return err + } + *resp, err = json.Marshal(secret) + return err +} + +func (s *RPCServer) OrgSecretList(args []byte, resp *[]byte) error { + var a argumentsOrgList + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + secrets, err := s.Impl.OrgSecretList(a.OrgID, a.ListOptions) + if err != nil { + return err + } + *resp, err = json.Marshal(secrets) + return err +} + +func (s *RPCServer) OrgSecretDelete(args []byte, resp *[]byte) error { + var a argumentsOrgFindDelete + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.OrgSecretDelete(a.OrgID, a.Name) +} + +func (s *RPCServer) OrgSecretCreate(args []byte, resp *[]byte) error { + var a argumentsOrgCreateUpdate + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.OrgSecretCreate(a.OrgID, a.Secret) +} + +func (s *RPCServer) OrgSecretUpdate(args []byte, resp *[]byte) error { + var a argumentsOrgCreateUpdate + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.OrgSecretUpdate(a.OrgID, a.Secret) +} + +func (s *RPCServer) GlobalSecretFind(args string, resp *[]byte) error { + secret, err := s.Impl.GlobalSecretFind(args) + if err != nil { + return err + } + *resp, err = json.Marshal(secret) + return err +} + +func (s *RPCServer) GlobalSecretList(args []byte, resp *[]byte) error { + var opts *model.ListOptions + err := json.Unmarshal(args, opts) + if err != nil { + return err + } + secrets, err := s.Impl.GlobalSecretList(opts) + if err != nil { + return err + } + *resp, err = json.Marshal(secrets) + return err +} + +func (s *RPCServer) GlobalSecretDelete(args string, resp *[]byte) error { + *resp = []byte{} + return s.Impl.GlobalSecretDelete(args) +} + +func (s *RPCServer) GlobalSecretCreate(args []byte, resp *[]byte) error { + var secret *model.Secret + err := json.Unmarshal(args, secret) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.GlobalSecretCreate(secret) +} + +func (s *RPCServer) GlobalSecretUpdate(args []byte, resp *[]byte) error { + var secret *model.Secret + err := json.Unmarshal(args, secret) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.GlobalSecretUpdate(secret) +} diff --git a/shared/addon/types/types.go b/shared/addon/types/types.go index 5355b6d2a1..1a70daffeb 100644 --- a/shared/addon/types/types.go +++ b/shared/addon/types/types.go @@ -3,7 +3,6 @@ package types type Type string const ( - TypeForge Type = "forge" - TypeBackend Type = "backend" - TypeSecretService Type = "secret_service" + TypeForge Type = "forge" + TypeBackend Type = "backend" ) From 2ae103a594b19887c538d13c9a4332ee0a3112cf Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 28 Jan 2024 14:41:24 +0100 Subject: [PATCH 07/44] Move pipeline error types to own package --- cli/lint/lint.go | 2 +- pipeline/errors/error.go | 35 +++-------- pipeline/errors/error_test.go | 37 +++++------ pipeline/errors/types/errors.go | 23 +++++++ pipeline/frontend/yaml/linter/error.go | 7 ++- pipeline/frontend/yaml/linter/linter.go | 17 ++--- pipeline/frontend/yaml/matrix/matrix.go | 6 +- server/model/pipeline.go | 62 +++++++++---------- server/pipeline/stepbuilder/stepBuilder.go | 3 +- ...7_convert_to_new_pipeline_errors_format.go | 10 +-- 10 files changed, 105 insertions(+), 97 deletions(-) create mode 100644 pipeline/errors/types/errors.go diff --git a/cli/lint/lint.go b/cli/lint/lint.go index 7d2a59d74a..a11927d770 100644 --- a/cli/lint/lint.go +++ b/cli/lint/lint.go @@ -114,7 +114,7 @@ func lintFile(_ *cli.Context, file string) error { hasErrors = true } - if data := err.GetLinterData(); data != nil { + if data := pipeline_errors.GetLinterData(err); data != nil { line = fmt.Sprintf("%s %s\t%s", line, output.String(data.Field).Bold(), err.Message) } else { line = fmt.Sprintf("%s %s", line, err.Message) diff --git a/pipeline/errors/error.go b/pipeline/errors/error.go index 3de2422056..f8bba4c67f 100644 --- a/pipeline/errors/error.go +++ b/pipeline/errors/error.go @@ -2,27 +2,12 @@ package errors import ( "errors" - "fmt" "go.uber.org/multierr" -) - -type PipelineErrorType string -const ( - PipelineErrorTypeLinter PipelineErrorType = "linter" // some error with the config syntax - PipelineErrorTypeDeprecation PipelineErrorType = "deprecation" // using some deprecated feature - PipelineErrorTypeCompiler PipelineErrorType = "compiler" // some error with the config semantics - PipelineErrorTypeGeneric PipelineErrorType = "generic" // some generic error + "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" ) -type PipelineError struct { - Type PipelineErrorType `json:"type"` - Message string `json:"message"` - IsWarning bool `json:"is_warning"` - Data any `json:"data"` -} - type LinterErrorData struct { File string `json:"file"` Field string `json:"field"` @@ -34,12 +19,8 @@ type DeprecationErrorData struct { Docs string `json:"docs"` } -func (e *PipelineError) Error() string { - return fmt.Sprintf("[%s] %s", e.Type, e.Message) -} - -func (e *PipelineError) GetLinterData() *LinterErrorData { - if e.Type != PipelineErrorTypeLinter { +func GetLinterData(e *types.PipelineError) *LinterErrorData { + if e.Type != types.PipelineErrorTypeLinter { return nil } @@ -50,16 +31,16 @@ func (e *PipelineError) GetLinterData() *LinterErrorData { return nil } -func GetPipelineErrors(err error) []*PipelineError { - var pipelineErrors []*PipelineError +func GetPipelineErrors(err error) []*types.PipelineError { + var pipelineErrors []*types.PipelineError for _, _err := range multierr.Errors(err) { - var err *PipelineError + var err *types.PipelineError if errors.As(_err, &err) { pipelineErrors = append(pipelineErrors, err) } else { - pipelineErrors = append(pipelineErrors, &PipelineError{ + pipelineErrors = append(pipelineErrors, &types.PipelineError{ Message: _err.Error(), - Type: PipelineErrorTypeGeneric, + Type: types.PipelineErrorTypeGeneric, }) } } diff --git a/pipeline/errors/error_test.go b/pipeline/errors/error_test.go index b6b328e7ef..8648c4048c 100644 --- a/pipeline/errors/error_test.go +++ b/pipeline/errors/error_test.go @@ -8,6 +8,7 @@ import ( "go.uber.org/multierr" pipeline_errors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors" + "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" ) func TestGetPipelineErrors(t *testing.T) { @@ -16,7 +17,7 @@ func TestGetPipelineErrors(t *testing.T) { tests := []struct { title string err error - expected []*pipeline_errors.PipelineError + expected []*types.PipelineError }{ { title: "nil error", @@ -25,10 +26,10 @@ func TestGetPipelineErrors(t *testing.T) { }, { title: "warning", - err: &pipeline_errors.PipelineError{ + err: &types.PipelineError{ IsWarning: true, }, - expected: []*pipeline_errors.PipelineError{ + expected: []*types.PipelineError{ { IsWarning: true, }, @@ -36,10 +37,10 @@ func TestGetPipelineErrors(t *testing.T) { }, { title: "pipeline error", - err: &pipeline_errors.PipelineError{ + err: &types.PipelineError{ IsWarning: false, }, - expected: []*pipeline_errors.PipelineError{ + expected: []*types.PipelineError{ { IsWarning: false, }, @@ -48,14 +49,14 @@ func TestGetPipelineErrors(t *testing.T) { { title: "multiple warnings", err: multierr.Combine( - &pipeline_errors.PipelineError{ + &types.PipelineError{ IsWarning: true, }, - &pipeline_errors.PipelineError{ + &types.PipelineError{ IsWarning: true, }, ), - expected: []*pipeline_errors.PipelineError{ + expected: []*types.PipelineError{ { IsWarning: true, }, @@ -67,15 +68,15 @@ func TestGetPipelineErrors(t *testing.T) { { title: "multiple errors and warnings", err: multierr.Combine( - &pipeline_errors.PipelineError{ + &types.PipelineError{ IsWarning: true, }, - &pipeline_errors.PipelineError{ + &types.PipelineError{ IsWarning: false, }, errors.New("some error"), ), - expected: []*pipeline_errors.PipelineError{ + expected: []*types.PipelineError{ { IsWarning: true, }, @@ -83,7 +84,7 @@ func TestGetPipelineErrors(t *testing.T) { IsWarning: false, }, { - Type: pipeline_errors.PipelineErrorTypeGeneric, + Type: types.PipelineErrorTypeGeneric, IsWarning: false, Message: "some error", }, @@ -111,14 +112,14 @@ func TestHasBlockingErrors(t *testing.T) { }, { title: "warning", - err: &pipeline_errors.PipelineError{ + err: &types.PipelineError{ IsWarning: true, }, expected: false, }, { title: "pipeline error", - err: &pipeline_errors.PipelineError{ + err: &types.PipelineError{ IsWarning: false, }, expected: true, @@ -126,10 +127,10 @@ func TestHasBlockingErrors(t *testing.T) { { title: "multiple warnings", err: multierr.Combine( - &pipeline_errors.PipelineError{ + &types.PipelineError{ IsWarning: true, }, - &pipeline_errors.PipelineError{ + &types.PipelineError{ IsWarning: true, }, ), @@ -138,10 +139,10 @@ func TestHasBlockingErrors(t *testing.T) { { title: "multiple errors and warnings", err: multierr.Combine( - &pipeline_errors.PipelineError{ + &types.PipelineError{ IsWarning: true, }, - &pipeline_errors.PipelineError{ + &types.PipelineError{ IsWarning: false, }, errors.New("some error"), diff --git a/pipeline/errors/types/errors.go b/pipeline/errors/types/errors.go new file mode 100644 index 0000000000..42e7dde0db --- /dev/null +++ b/pipeline/errors/types/errors.go @@ -0,0 +1,23 @@ +package types + +import "fmt" + +type PipelineErrorType string + +const ( + PipelineErrorTypeLinter PipelineErrorType = "linter" // some error with the config syntax + PipelineErrorTypeDeprecation PipelineErrorType = "deprecation" // using some deprecated feature + PipelineErrorTypeCompiler PipelineErrorType = "compiler" // some error with the config semantics + PipelineErrorTypeGeneric PipelineErrorType = "generic" // some generic error +) + +type PipelineError struct { + Type PipelineErrorType `json:"type"` + Message string `json:"message"` + IsWarning bool `json:"is_warning"` + Data any `json:"data"` +} + +func (e *PipelineError) Error() string { + return fmt.Sprintf("[%s] %s", e.Type, e.Message) +} diff --git a/pipeline/frontend/yaml/linter/error.go b/pipeline/frontend/yaml/linter/error.go index c28a44ae86..09e2430164 100644 --- a/pipeline/frontend/yaml/linter/error.go +++ b/pipeline/frontend/yaml/linter/error.go @@ -16,11 +16,12 @@ package linter import ( "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors" + errorTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" ) -func newLinterError(message, file, field string, isWarning bool) *errors.PipelineError { - return &errors.PipelineError{ - Type: errors.PipelineErrorTypeLinter, +func newLinterError(message, file, field string, isWarning bool) *errorTypes.PipelineError { + return &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeLinter, Message: message, Data: &errors.LinterErrorData{File: file, Field: field}, IsWarning: isWarning, diff --git a/pipeline/frontend/yaml/linter/linter.go b/pipeline/frontend/yaml/linter/linter.go index 78a5a07115..91eca4f26b 100644 --- a/pipeline/frontend/yaml/linter/linter.go +++ b/pipeline/frontend/yaml/linter/linter.go @@ -21,6 +21,7 @@ import ( "go.uber.org/multierr" "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors" + errorTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/linter/schema" "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/types" ) @@ -210,8 +211,8 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { } if parsed.PipelineDoNotUseIt.ContainerList != nil { - err = multierr.Append(err, &errors.PipelineError{ - Type: errors.PipelineErrorTypeDeprecation, + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeDeprecation, Message: "Please use 'steps:' instead of deprecated 'pipeline:' list", Data: errors.DeprecationErrorData{ File: config.File, @@ -223,8 +224,8 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { } if parsed.PlatformDoNotUseIt != "" { - err = multierr.Append(err, &errors.PipelineError{ - Type: errors.PipelineErrorTypeDeprecation, + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeDeprecation, Message: "Please use labels instead of deprecated 'platform' filters", Data: errors.DeprecationErrorData{ File: config.File, @@ -236,8 +237,8 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { } if parsed.BranchesDoNotUseIt != nil { - err = multierr.Append(err, &errors.PipelineError{ - Type: errors.PipelineErrorTypeDeprecation, + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeDeprecation, Message: "Please use global when instead of deprecated 'branches' filter", Data: errors.DeprecationErrorData{ File: config.File, @@ -250,8 +251,8 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { for _, step := range parsed.Steps.ContainerList { if step.Group != "" { - err = multierr.Append(err, &errors.PipelineError{ - Type: errors.PipelineErrorTypeDeprecation, + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeDeprecation, Message: "Please use depends_on instead of deprecated 'group' setting", Data: errors.DeprecationErrorData{ File: config.File, diff --git a/pipeline/frontend/yaml/matrix/matrix.go b/pipeline/frontend/yaml/matrix/matrix.go index b89dfc5d93..373c7bec93 100644 --- a/pipeline/frontend/yaml/matrix/matrix.go +++ b/pipeline/frontend/yaml/matrix/matrix.go @@ -19,7 +19,7 @@ import ( "codeberg.org/6543/xyaml" - "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors" + errorTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" ) const ( @@ -116,7 +116,7 @@ func parse(raw []byte) (Matrix, error) { Matrix map[string][]string }{} if err := xyaml.Unmarshal(raw, &data); err != nil { - return nil, &errors.PipelineError{Message: err.Error(), Type: errors.PipelineErrorTypeCompiler} + return nil, &errorTypes.PipelineError{Message: err.Error(), Type: errorTypes.PipelineErrorTypeCompiler} } return data.Matrix, nil } @@ -129,7 +129,7 @@ func parseList(raw []byte) ([]Axis, error) { }{} if err := xyaml.Unmarshal(raw, &data); err != nil { - return nil, &errors.PipelineError{Message: err.Error(), Type: errors.PipelineErrorTypeCompiler} + return nil, &errorTypes.PipelineError{Message: err.Error(), Type: errorTypes.PipelineErrorTypeCompiler} } return data.Matrix.Include, nil } diff --git a/server/model/pipeline.go b/server/model/pipeline.go index e1eaabc99f..4400c4d7b3 100644 --- a/server/model/pipeline.go +++ b/server/model/pipeline.go @@ -16,40 +16,40 @@ package model import ( - "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors" + "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" ) type Pipeline struct { - ID int64 `json:"id" xorm:"pk autoincr 'pipeline_id'"` - RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'pipeline_repo_id'"` - Number int64 `json:"number" xorm:"UNIQUE(s) 'pipeline_number'"` - Author string `json:"author" xorm:"INDEX 'pipeline_author'"` - Parent int64 `json:"parent" xorm:"pipeline_parent"` - Event WebhookEvent `json:"event" xorm:"pipeline_event"` - Status StatusValue `json:"status" xorm:"INDEX 'pipeline_status'"` - Errors []*errors.PipelineError `json:"errors" xorm:"json 'pipeline_errors'"` - Created int64 `json:"created_at" xorm:"pipeline_created"` - Updated int64 `json:"updated_at" xorm:"updated NOT NULL DEFAULT 0 'updated'"` - Started int64 `json:"started_at" xorm:"pipeline_started"` - Finished int64 `json:"finished_at" xorm:"pipeline_finished"` - Deploy string `json:"deploy_to" xorm:"pipeline_deploy"` - Commit string `json:"commit" xorm:"pipeline_commit"` - Branch string `json:"branch" xorm:"pipeline_branch"` - Ref string `json:"ref" xorm:"pipeline_ref"` - Refspec string `json:"refspec" xorm:"pipeline_refspec"` - Title string `json:"title" xorm:"pipeline_title"` - Message string `json:"message" xorm:"TEXT 'pipeline_message'"` - Timestamp int64 `json:"timestamp" xorm:"pipeline_timestamp"` - Sender string `json:"sender" xorm:"pipeline_sender"` // uses reported user for webhooks and name of cron for cron pipelines - Avatar string `json:"author_avatar" xorm:"pipeline_avatar"` - Email string `json:"author_email" xorm:"pipeline_email"` - ForgeURL string `json:"forge_url" xorm:"pipeline_forge_url"` - Reviewer string `json:"reviewed_by" xorm:"pipeline_reviewer"` - Reviewed int64 `json:"reviewed_at" xorm:"pipeline_reviewed"` - Workflows []*Workflow `json:"workflows,omitempty" xorm:"-"` - ChangedFiles []string `json:"changed_files,omitempty" xorm:"LONGTEXT 'changed_files'"` - AdditionalVariables map[string]string `json:"variables,omitempty" xorm:"json 'additional_variables'"` - PullRequestLabels []string `json:"pr_labels,omitempty" xorm:"json 'pr_labels'"` + ID int64 `json:"id" xorm:"pk autoincr 'pipeline_id'"` + RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'pipeline_repo_id'"` + Number int64 `json:"number" xorm:"UNIQUE(s) 'pipeline_number'"` + Author string `json:"author" xorm:"INDEX 'pipeline_author'"` + Parent int64 `json:"parent" xorm:"pipeline_parent"` + Event WebhookEvent `json:"event" xorm:"pipeline_event"` + Status StatusValue `json:"status" xorm:"INDEX 'pipeline_status'"` + Errors []*types.PipelineError `json:"errors" xorm:"json 'pipeline_errors'"` + Created int64 `json:"created_at" xorm:"pipeline_created"` + Updated int64 `json:"updated_at" xorm:"updated NOT NULL DEFAULT 0 'updated'"` + Started int64 `json:"started_at" xorm:"pipeline_started"` + Finished int64 `json:"finished_at" xorm:"pipeline_finished"` + Deploy string `json:"deploy_to" xorm:"pipeline_deploy"` + Commit string `json:"commit" xorm:"pipeline_commit"` + Branch string `json:"branch" xorm:"pipeline_branch"` + Ref string `json:"ref" xorm:"pipeline_ref"` + Refspec string `json:"refspec" xorm:"pipeline_refspec"` + Title string `json:"title" xorm:"pipeline_title"` + Message string `json:"message" xorm:"TEXT 'pipeline_message'"` + Timestamp int64 `json:"timestamp" xorm:"pipeline_timestamp"` + Sender string `json:"sender" xorm:"pipeline_sender"` // uses reported user for webhooks and name of cron for cron pipelines + Avatar string `json:"author_avatar" xorm:"pipeline_avatar"` + Email string `json:"author_email" xorm:"pipeline_email"` + ForgeURL string `json:"forge_url" xorm:"pipeline_forge_url"` + Reviewer string `json:"reviewed_by" xorm:"pipeline_reviewer"` + Reviewed int64 `json:"reviewed_at" xorm:"pipeline_reviewed"` + Workflows []*Workflow `json:"workflows,omitempty" xorm:"-"` + ChangedFiles []string `json:"changed_files,omitempty" xorm:"LONGTEXT 'changed_files'"` + AdditionalVariables map[string]string `json:"variables,omitempty" xorm:"json 'additional_variables'"` + PullRequestLabels []string `json:"pr_labels,omitempty" xorm:"json 'pr_labels'"` } // @name Pipeline // TableName return database table name for xorm diff --git a/server/pipeline/stepbuilder/stepBuilder.go b/server/pipeline/stepbuilder/stepBuilder.go index f0bdadb6ae..6673db4b78 100644 --- a/server/pipeline/stepbuilder/stepBuilder.go +++ b/server/pipeline/stepbuilder/stepBuilder.go @@ -26,6 +26,7 @@ import ( backend_types "go.woodpecker-ci.org/woodpecker/v2/pipeline/backend/types" pipeline_errors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors" + errorTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/metadata" "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml" "go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/compiler" @@ -135,7 +136,7 @@ func (b *StepBuilder) genItemForWorkflow(workflow *model.Workflow, axis matrix.A // parse yaml pipeline parsed, err := yaml.ParseString(substituted) if err != nil { - return nil, &pipeline_errors.PipelineError{Message: err.Error(), Type: pipeline_errors.PipelineErrorTypeCompiler} + return nil, &errorTypes.PipelineError{Message: err.Error(), Type: errorTypes.PipelineErrorTypeCompiler} } // lint pipeline diff --git a/server/store/datastore/migration/027_convert_to_new_pipeline_errors_format.go b/server/store/datastore/migration/027_convert_to_new_pipeline_errors_format.go index de6bc229fc..fa99942948 100644 --- a/server/store/datastore/migration/027_convert_to_new_pipeline_errors_format.go +++ b/server/store/datastore/migration/027_convert_to_new_pipeline_errors_format.go @@ -18,16 +18,16 @@ import ( "src.techknowlogick.com/xormigrate" "xorm.io/xorm" - "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors" + errorTypes "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" ) // perPage027 set the size of the slice to read per page var perPage027 = 100 type pipeline027 struct { - ID int64 `json:"id" xorm:"pk autoincr 'pipeline_id'"` - Error string `json:"error" xorm:"LONGTEXT 'pipeline_error'"` // old error format - Errors []*errors.PipelineError `json:"errors" xorm:"json 'pipeline_errors'"` // new error format + ID int64 `json:"id" xorm:"pk autoincr 'pipeline_id'"` + Error string `json:"error" xorm:"LONGTEXT 'pipeline_error'"` // old error format + Errors []*errorTypes.PipelineError `json:"errors" xorm:"json 'pipeline_errors'"` // new error format } func (pipeline027) TableName() string { @@ -64,7 +64,7 @@ var convertToNewPipelineErrorFormat = xormigrate.Migration{ for _, oldPipeline := range oldPipelines { var newPipeline pipeline027 newPipeline.ID = oldPipeline.ID - newPipeline.Errors = []*errors.PipelineError{{ + newPipeline.Errors = []*errorTypes.PipelineError{{ Type: "generic", Message: oldPipeline.Error, }} From 2784acf0bc438f96411147845508aa8a1b1f850e Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 28 Jan 2024 14:46:39 +0100 Subject: [PATCH 08/44] fix flag types --- cmd/server/flags.go | 8 ++++---- cmd/server/setup.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 41f7959705..ae47226753 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -261,22 +261,22 @@ var flags = append([]cli.Flag{ Name: "addons", Usage: "list of addon files", }, - &cli.StringSliceFlag{ + &cli.StringFlag{ EnvVars: []string{"WOODPECKER_ADDON_CONFIG_SERVICE"}, Name: "addons-config-service", Usage: "config service addon", }, - &cli.StringSliceFlag{ + &cli.StringFlag{ EnvVars: []string{"WOODPECKER_ADDON_REGISTRY_SERVICE"}, Name: "addons-registry-service", Usage: "registry service addon", }, - &cli.StringSliceFlag{ + &cli.StringFlag{ EnvVars: []string{"WOODPECKER_ADDON_ENVIRONMENT_SERVICE"}, Name: "addons-environ-service", Usage: "environment service addon", }, - &cli.StringSliceFlag{ + &cli.StringFlag{ EnvVars: []string{"WOODPECKER_ADDON_SECRET_SERVICE"}, Name: "addons-secret-service", Usage: "secret service addon", diff --git a/cmd/server/setup.go b/cmd/server/setup.go index eb0ebd2e2f..76b8ec7c7f 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -131,8 +131,8 @@ func setupSecretService(c *cli.Context, s model.SecretStore) (model.SecretServic } func setupRegistryService(c *cli.Context, s store.Store) (model.RegistryService, error) { - if a := c.String("addons-registry-service"); a != "" { - addonExt, err := hashicorp.Load(a, registryservice.Addon) + if add := c.String("addons-registry-service"); add != "" { + addonExt, err := hashicorp.Load(add, registryservice.Addon) if err != nil { return nil, err } From 6df50b09cf243846ef684e0e85a947d9751f7ff9 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Thu, 8 Feb 2024 20:00:56 +0100 Subject: [PATCH 09/44] Add basic forge addon stuff (wip) --- shared/addon/hashicorp/forge/args.go | 36 ++++ shared/addon/hashicorp/forge/client.go | 218 ++++++++++++++++++++++ shared/addon/hashicorp/forge/interface.go | 30 +++ shared/addon/hashicorp/forge/load.go | 8 + shared/addon/hashicorp/forge/server.go | 117 ++++++++++++ 5 files changed, 409 insertions(+) create mode 100644 shared/addon/hashicorp/forge/args.go create mode 100644 shared/addon/hashicorp/forge/client.go create mode 100644 shared/addon/hashicorp/forge/interface.go create mode 100644 shared/addon/hashicorp/forge/load.go create mode 100644 shared/addon/hashicorp/forge/server.go diff --git a/shared/addon/hashicorp/forge/args.go b/shared/addon/hashicorp/forge/args.go new file mode 100644 index 0000000000..623c05dc38 --- /dev/null +++ b/shared/addon/hashicorp/forge/args.go @@ -0,0 +1,36 @@ +package configservice + +import ( + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +type argumentsAuth struct { + Token string `json:"token"` + Secret string `json:"secret"` +} + +type argumentsRepo struct { + U *model.User `json:"u"` + RemoteID model.ForgeRemoteID `json:"remote_id"` + Owner string `json:"owner"` + Name string `json:"name"` +} + +type argumentsFileDir struct { + U *model.User `json:"u"` + R *model.Repo `json:"r"` + B *model.Pipeline `json:"b"` + F string `json:"f"` +} + +type argumentsStatus struct { + U *model.User `json:"u"` + R *model.Repo `json:"r"` + B *model.Pipeline `json:"b"` + P *model.Workflow `json:"p"` +} + +type argumentsNetrc struct { + U *model.User `json:"u"` + R *model.Repo `json:"r"` +} diff --git a/shared/addon/hashicorp/forge/client.go b/shared/addon/hashicorp/forge/client.go new file mode 100644 index 0000000000..3da8e26af7 --- /dev/null +++ b/shared/addon/hashicorp/forge/client.go @@ -0,0 +1,218 @@ +package configservice + +import ( + "context" + "encoding/json" + "net/http" + "net/rpc" + + "go.woodpecker-ci.org/woodpecker/v2/server/forge" + "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +var f forge.Forge = new(RPC) + +// TODO issue: user models are not sent with token/secret (token/secret is json:"-") +// possible solution: two-way-communication with two funcs: 1. token/secret for user 2. token/secret for repo +// however, that's an issue in both directions: the addon can't return tokens/secrets +type RPC struct{ client *rpc.Client } + +func (g *RPC) Name() string { + var resp string + _ = g.client.Call("Plugin.Name", nil, &resp) + return resp +} + +func (g *RPC) URL() string { + var resp string + _ = g.client.Call("Plugin.URL", nil, &resp) + return resp +} + +func (g *RPC) Login(ctx context.Context, w http.ResponseWriter, r *http.Request) (*model.User, error) { + /* TODO args, err := json.Marshal(&arguments{ + Repo: repo, + Pipeline: pipeline, + CurrentFileMeta: currentFileMeta, + Netrc: netrc, + Timeout: timeout, + }) + if err != nil { + return nil, err + }*/ + var jsonResp []byte + /*err = g.client.Call("Plugin.Login", args, &jsonResp) + if err != nil { + return nil, err + }*/ + + var resp *model.User + return resp, json.Unmarshal(jsonResp, resp) +} + +func (g *RPC) Auth(ctx context.Context, token, secret string) (string, error) { + args, err := json.Marshal(&argumentsAuth{ + Token: token, + Secret: secret, + }) + if err != nil { + return "", err + } + var resp string + return resp, g.client.Call("Plugin.Auth", args, &resp) +} + +func (g *RPC) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) { + args, err := json.Marshal(u) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.Teams", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp []*model.Team + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRemoteID, owner, name string) (*model.Repo, error) { + args, err := json.Marshal(&argumentsRepo{ + U: u, + RemoteID: remoteID, + Owner: owner, + Name: name, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.Repo", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp *model.Repo + return resp, json.Unmarshal(jsonResp, resp) +} + +func (g *RPC) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) { + args, err := json.Marshal(u) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.Repos", args, &jsonResp) + if err != nil { + return nil, err + } + + var resp []*model.Repo + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { + args, err := json.Marshal(&argumentsFileDir{ + U: u, + R: r, + B: b, + F: f, + }) + if err != nil { + return nil, err + } + var resp []byte + return resp, g.client.Call("Plugin.File", args, &resp) +} + +func (g *RPC) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*types.FileMeta, error) { + args, err := json.Marshal(&argumentsFileDir{ + U: u, + R: r, + B: b, + F: f, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.Dir", args, &jsonResp) + if err != nil { + return nil, err + } + var resp []*types.FileMeta + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Workflow) error { + args, err := json.Marshal(&argumentsStatus{ + U: u, + R: r, + B: b, + P: p, + }) + if err != nil { + return err + } + var jsonResp []byte + return g.client.Call("Plugin.Status", args, &jsonResp) +} + +func (g *RPC) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { + args, err := json.Marshal(&argumentsNetrc{ + U: u, + R: r, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.Netrc", args, &jsonResp) + if err != nil { + return nil, err + } + var resp *model.Netrc + return resp, json.Unmarshal(jsonResp, &resp) +} + +func (g *RPC) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error { + //TODO implement me + panic("implement me") +} + +func (g *RPC) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { + //TODO implement me + panic("implement me") +} + +func (g *RPC) Branches(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) { + //TODO implement me + panic("implement me") +} + +func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (string, error) { + //TODO implement me + panic("implement me") +} + +func (g *RPC) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) { + //TODO implement me + panic("implement me") +} + +func (g *RPC) Hook(ctx context.Context, r *http.Request) (repo *model.Repo, pipeline *model.Pipeline, err error) { + //TODO implement me + panic("implement me") +} + +func (g *RPC) OrgMembership(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error) { + //TODO implement me + panic("implement me") +} + +func (g *RPC) Org(ctx context.Context, u *model.User, org string) (*model.Org, error) { + //TODO implement me + panic("implement me") +} diff --git a/shared/addon/hashicorp/forge/interface.go b/shared/addon/hashicorp/forge/interface.go new file mode 100644 index 0000000000..c9da8553a3 --- /dev/null +++ b/shared/addon/hashicorp/forge/interface.go @@ -0,0 +1,30 @@ +package configservice + +import ( + "net/rpc" + + "github.com/hashicorp/go-plugin" + + "go.woodpecker-ci.org/woodpecker/v2/server/forge" +) + +type Plugin struct { + Impl forge.Forge +} + +func (p *Plugin) Key() string { + return "configservice" +} + +func (p *Plugin) WithImpl(t forge.Forge) plugin.Plugin { + p.Impl = t + return p +} + +func (p *Plugin) Server(*plugin.MuxBroker) (any, error) { + return &RPCServer{Impl: p.Impl}, nil +} + +func (*Plugin) Client(_ *plugin.MuxBroker, c *rpc.Client) (any, error) { + return &RPC{client: c}, nil +} diff --git a/shared/addon/hashicorp/forge/load.go b/shared/addon/hashicorp/forge/load.go new file mode 100644 index 0000000000..e0062fb42a --- /dev/null +++ b/shared/addon/hashicorp/forge/load.go @@ -0,0 +1,8 @@ +package configservice + +import ( + "go.woodpecker-ci.org/woodpecker/v2/server/forge" + "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" +) + +var Addon hashicorp.Plugin[forge.Forge] = &Plugin{} diff --git a/shared/addon/hashicorp/forge/server.go b/shared/addon/hashicorp/forge/server.go new file mode 100644 index 0000000000..2571bc0e7b --- /dev/null +++ b/shared/addon/hashicorp/forge/server.go @@ -0,0 +1,117 @@ +package configservice + +import ( + "context" + "encoding/json" + + "go.woodpecker-ci.org/woodpecker/v2/server/forge" + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +func mkCtx() context.Context { + return context.Background() +} + +type RPCServer struct { + Impl forge.Forge +} + +func (s *RPCServer) Name(_ []byte, resp *string) error { + *resp = s.Impl.Name() + return nil +} + +func (s *RPCServer) URL(_ []byte, resp *string) error { + *resp = s.Impl.URL() + return nil +} + +func (s *RPCServer) Teams(args []byte, resp *[]byte) error { + var a *model.User + err := json.Unmarshal(args, a) + if err != nil { + return err + } + teams, err := s.Impl.Teams(mkCtx(), a) + if err != nil { + return err + } + *resp, err = json.Marshal(teams) + return err +} + +func (s *RPCServer) Repo(args []byte, resp *[]byte) error { + var a argumentsRepo + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + repos, err := s.Impl.Repo(mkCtx(), a.U, a.RemoteID, a.Owner, a.Name) + if err != nil { + return err + } + *resp, err = json.Marshal(repos) + return err +} + +func (s *RPCServer) Repos(args []byte, resp *[]byte) error { + var a *model.User + err := json.Unmarshal(args, a) + if err != nil { + return err + } + repos, err := s.Impl.Repos(mkCtx(), a) + if err != nil { + return err + } + *resp, err = json.Marshal(repos) + return err +} + +func (s *RPCServer) File(args []byte, resp *[]byte) error { + var a argumentsFileDir + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp, err = s.Impl.File(mkCtx(), a.U, a.R, a.B, a.F) + return err +} + +func (s *RPCServer) Dir(args []byte, resp *[]byte) error { + var a argumentsFileDir + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + meta, err := s.Impl.Dir(mkCtx(), a.U, a.R, a.B, a.F) + if err != nil { + return err + } + *resp, err = json.Marshal(meta) + return err +} + +func (s *RPCServer) Status(args []byte, resp *[]byte) error { + var a argumentsStatus + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.Status(mkCtx(), a.U, a.R, a.B, a.P) +} + +func (s *RPCServer) Netrc(args []byte, resp *[]byte) error { + var a argumentsNetrc + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + netrc, err := s.Impl.Netrc(a.U, a.R) + if err != nil { + return err + } + *resp, err = json.Marshal(netrc) + return err +} From a1a8d21f654781c76fce1e83d465b177ef80b9de Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Fri, 9 Feb 2024 10:22:55 +0100 Subject: [PATCH 10/44] continue forge addon --- shared/addon/hashicorp/forge/args.go | 28 ++++++ shared/addon/hashicorp/forge/client.go | 125 +++++++++++++++++++++---- shared/addon/hashicorp/forge/server.go | 120 ++++++++++++++++++++++++ 3 files changed, 253 insertions(+), 20 deletions(-) diff --git a/shared/addon/hashicorp/forge/args.go b/shared/addon/hashicorp/forge/args.go index 623c05dc38..cfd8b10462 100644 --- a/shared/addon/hashicorp/forge/args.go +++ b/shared/addon/hashicorp/forge/args.go @@ -34,3 +34,31 @@ type argumentsNetrc struct { U *model.User `json:"u"` R *model.Repo `json:"r"` } + +type argumentsActivateDeactivate struct { + U *model.User `json:"u"` + R *model.Repo `json:"r"` + Link string `json:"link"` +} + +type argumentsBranchesPullRequests struct { + U *model.User `json:"u"` + R *model.Repo `json:"r"` + P *model.ListOptions `json:"p"` +} + +type argumentsBranchHead struct { + U *model.User `json:"u"` + R *model.Repo `json:"r"` + Branch string `json:"branch"` +} + +type argumentsOrgMembershipOrg struct { + U *model.User `json:"u"` + Org string `json:"org"` +} + +type responseHook struct { + Repo *model.Repo `json:"repo"` + Pipeline *model.Pipeline `json:"pipeline"` +} diff --git a/shared/addon/hashicorp/forge/client.go b/shared/addon/hashicorp/forge/client.go index 3da8e26af7..1f15e38f04 100644 --- a/shared/addon/hashicorp/forge/client.go +++ b/shared/addon/hashicorp/forge/client.go @@ -6,13 +6,10 @@ import ( "net/http" "net/rpc" - "go.woodpecker-ci.org/woodpecker/v2/server/forge" "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" "go.woodpecker-ci.org/woodpecker/v2/server/model" ) -var f forge.Forge = new(RPC) - // TODO issue: user models are not sent with token/secret (token/secret is json:"-") // possible solution: two-way-communication with two funcs: 1. token/secret for user 2. token/secret for repo // however, that's an issue in both directions: the addon can't return tokens/secrets @@ -178,41 +175,129 @@ func (g *RPC) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { } func (g *RPC) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error { - //TODO implement me - panic("implement me") + args, err := json.Marshal(&argumentsActivateDeactivate{ + U: u, + R: r, + Link: link, + }) + if err != nil { + return err + } + var jsonResp []byte + return g.client.Call("Plugin.Activate", args, &jsonResp) } func (g *RPC) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { - //TODO implement me - panic("implement me") + args, err := json.Marshal(&argumentsActivateDeactivate{ + U: u, + R: r, + Link: link, + }) + if err != nil { + return err + } + var jsonResp []byte + return g.client.Call("Plugin.Deactivate", args, &jsonResp) } func (g *RPC) Branches(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) { - //TODO implement me - panic("implement me") + args, err := json.Marshal(&argumentsBranchesPullRequests{ + U: u, + R: r, + P: p, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.Branches", args, &jsonResp) + if err != nil { + return nil, err + } + var resp []string + return resp, json.Unmarshal(jsonResp, &resp) } func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (string, error) { - //TODO implement me - panic("implement me") + args, err := json.Marshal(&argumentsBranchHead{ + U: u, + R: r, + Branch: branch, + }) + if err != nil { + return "", err + } + var resp string + return resp, g.client.Call("Plugin.BranchHead", args, &resp) } func (g *RPC) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) { - //TODO implement me - panic("implement me") + args, err := json.Marshal(&argumentsBranchesPullRequests{ + U: u, + R: r, + P: p, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.PullRequests", args, &jsonResp) + if err != nil { + return nil, err + } + var resp []*model.PullRequest + return resp, json.Unmarshal(jsonResp, &resp) } -func (g *RPC) Hook(ctx context.Context, r *http.Request) (repo *model.Repo, pipeline *model.Pipeline, err error) { - //TODO implement me - panic("implement me") +func (g *RPC) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { + // TODO marshalling http.request + args, err := json.Marshal(r) + if err != nil { + return nil, nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.Hook", args, &jsonResp) + if err != nil { + return nil, nil, err + } + var resp responseHook + err = json.Unmarshal(jsonResp, &resp) + if err != nil { + return nil, nil, err + } + return resp.Repo, resp.Pipeline, nil } func (g *RPC) OrgMembership(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error) { - //TODO implement me - panic("implement me") + args, err := json.Marshal(&argumentsOrgMembershipOrg{ + U: u, + Org: org, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.OrgMembership", args, &jsonResp) + if err != nil { + return nil, err + } + var resp *model.OrgPerm + return resp, json.Unmarshal(jsonResp, &resp) } func (g *RPC) Org(ctx context.Context, u *model.User, org string) (*model.Org, error) { - //TODO implement me - panic("implement me") + args, err := json.Marshal(&argumentsOrgMembershipOrg{ + U: u, + Org: org, + }) + if err != nil { + return nil, err + } + var jsonResp []byte + err = g.client.Call("Plugin.Org", args, &jsonResp) + if err != nil { + return nil, err + } + var resp *model.Org + return resp, json.Unmarshal(jsonResp, &resp) } diff --git a/shared/addon/hashicorp/forge/server.go b/shared/addon/hashicorp/forge/server.go index 2571bc0e7b..ef057e9728 100644 --- a/shared/addon/hashicorp/forge/server.go +++ b/shared/addon/hashicorp/forge/server.go @@ -3,6 +3,7 @@ package configservice import ( "context" "encoding/json" + "net/http" "go.woodpecker-ci.org/woodpecker/v2/server/forge" "go.woodpecker-ci.org/woodpecker/v2/server/model" @@ -115,3 +116,122 @@ func (s *RPCServer) Netrc(args []byte, resp *[]byte) error { *resp, err = json.Marshal(netrc) return err } + +func (s *RPCServer) Activate(args []byte, resp *[]byte) error { + var a argumentsActivateDeactivate + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.Activate(mkCtx(), a.U, a.R, a.Link) +} + +func (s *RPCServer) Deactivate(args []byte, resp *[]byte) error { + var a argumentsActivateDeactivate + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp = []byte{} + return s.Impl.Deactivate(mkCtx(), a.U, a.R, a.Link) +} + +func (s *RPCServer) Branches(args []byte, resp *[]byte) error { + var a argumentsBranchesPullRequests + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + branches, err := s.Impl.Branches(mkCtx(), a.U, a.R, a.P) + if err != nil { + return err + } + *resp, err = json.Marshal(branches) + return err +} + +func (s *RPCServer) BranchHead(args []byte, resp *string) error { + var a argumentsBranchHead + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + *resp, err = s.Impl.BranchHead(mkCtx(), a.U, a.R, a.Branch) + return err +} + +func (s *RPCServer) PullRequests(args []byte, resp *[]byte) error { + var a argumentsBranchesPullRequests + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + prs, err := s.Impl.PullRequests(mkCtx(), a.U, a.R, a.P) + if err != nil { + return err + } + *resp, err = json.Marshal(prs) + return err +} + +func (s *RPCServer) OrgMembership(args []byte, resp *[]byte) error { + var a argumentsOrgMembershipOrg + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + org, err := s.Impl.OrgMembership(mkCtx(), a.U, a.Org) + if err != nil { + return err + } + *resp, err = json.Marshal(org) + return err +} + +func (s *RPCServer) Org(args []byte, resp *[]byte) error { + var a argumentsOrgMembershipOrg + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + org, err := s.Impl.Org(mkCtx(), a.U, a.Org) + if err != nil { + return err + } + *resp, err = json.Marshal(org) + return err +} + +func (s *RPCServer) Hook(args []byte, resp *[]byte) error { + // TODO http.request json + var a *http.Request + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + repo, pipeline, err := s.Impl.Hook(mkCtx(), a) + if err != nil { + return err + } + *resp, err = json.Marshal(&responseHook{ + Repo: repo, + Pipeline: pipeline, + }) + return err +} + +func (s *RPCServer) Login(args []byte, resp *[]byte) error { + // TODO http.request and iowriter json + var a *http.Request + err := json.Unmarshal(args, &a) + if err != nil { + return err + } + user, err := s.Impl.Login(mkCtx(), nil, a) + if err != nil { + return err + } + *resp, err = json.Marshal(user) + return err +} From bce1ad376e65a158f9b9934f494a7f9f457d302a Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Fri, 9 Feb 2024 10:27:18 +0100 Subject: [PATCH 11/44] fix id --- shared/addon/hashicorp/forge/interface.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/addon/hashicorp/forge/interface.go b/shared/addon/hashicorp/forge/interface.go index c9da8553a3..1e32ab1c60 100644 --- a/shared/addon/hashicorp/forge/interface.go +++ b/shared/addon/hashicorp/forge/interface.go @@ -13,7 +13,7 @@ type Plugin struct { } func (p *Plugin) Key() string { - return "configservice" + return "forge" } func (p *Plugin) WithImpl(t forge.Forge) plugin.Plugin { From b9308325e6f82fbab56727ef8696924fb8c0609d Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Fri, 9 Feb 2024 10:31:49 +0100 Subject: [PATCH 12/44] replace goplugins --- cmd/server/flags.go | 10 +++++----- cmd/server/setup.go | 17 +++++++++-------- shared/addon/hashicorp/forge/args.go | 2 +- shared/addon/hashicorp/forge/client.go | 2 +- shared/addon/hashicorp/forge/interface.go | 2 +- shared/addon/hashicorp/forge/load.go | 2 +- shared/addon/hashicorp/forge/server.go | 2 +- 7 files changed, 19 insertions(+), 18 deletions(-) diff --git a/cmd/server/flags.go b/cmd/server/flags.go index ae47226753..75e21f3a49 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -256,11 +256,6 @@ var flags = append([]cli.Flag{ Usage: "Disable version check in admin web ui.", Name: "skip-version-check", }, - &cli.StringSliceFlag{ - EnvVars: []string{"WOODPECKER_ADDONS"}, - Name: "addons", - Usage: "list of addon files", - }, &cli.StringFlag{ EnvVars: []string{"WOODPECKER_ADDON_CONFIG_SERVICE"}, Name: "addons-config-service", @@ -281,6 +276,11 @@ var flags = append([]cli.Flag{ Name: "addons-secret-service", Usage: "secret service addon", }, + &cli.StringFlag{ + EnvVars: []string{"WOODPECKER_ADDON_FORGE"}, + Name: "addons-forge", + Usage: "forge addon", + }, // // backend options for pipeline compiler // diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 76b8ec7c7f..5b4544a964 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -50,13 +50,12 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/server/store" "go.woodpecker-ci.org/woodpecker/v2/server/store/datastore" "go.woodpecker-ci.org/woodpecker/v2/server/store/types" - "go.woodpecker-ci.org/woodpecker/v2/shared/addon" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/configservice" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/environservice" + forgeaddon "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/forge" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/registryservice" "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/secretservice" - addonTypes "go.woodpecker-ci.org/woodpecker/v2/shared/addon/types" ) func setupStore(c *cli.Context) (store.Store, error) { @@ -170,12 +169,14 @@ func setupMembershipService(_ *cli.Context, r forge.Forge) cache.MembershipServi // setupForge helper function to set up the forge from the CLI arguments. func setupForge(c *cli.Context) (forge.Forge, error) { - addonForge, err := addon.Load[forge.Forge](c.StringSlice("addons"), addonTypes.TypeForge) - if err != nil { - return nil, err - } - if addonForge != nil { - return addonForge.Value, nil + if a := c.String("addons-forge"); a != "" { + addonExt, err := hashicorp.Load(a, forgeaddon.Addon) + if err != nil { + return nil, err + } + if addonExt != nil { + return addonExt.Value, nil + } } switch { diff --git a/shared/addon/hashicorp/forge/args.go b/shared/addon/hashicorp/forge/args.go index cfd8b10462..55ff0ab655 100644 --- a/shared/addon/hashicorp/forge/args.go +++ b/shared/addon/hashicorp/forge/args.go @@ -1,4 +1,4 @@ -package configservice +package forgeaddon import ( "go.woodpecker-ci.org/woodpecker/v2/server/model" diff --git a/shared/addon/hashicorp/forge/client.go b/shared/addon/hashicorp/forge/client.go index 1f15e38f04..40d8a042cc 100644 --- a/shared/addon/hashicorp/forge/client.go +++ b/shared/addon/hashicorp/forge/client.go @@ -1,4 +1,4 @@ -package configservice +package forgeaddon import ( "context" diff --git a/shared/addon/hashicorp/forge/interface.go b/shared/addon/hashicorp/forge/interface.go index 1e32ab1c60..39edebee1a 100644 --- a/shared/addon/hashicorp/forge/interface.go +++ b/shared/addon/hashicorp/forge/interface.go @@ -1,4 +1,4 @@ -package configservice +package forgeaddon import ( "net/rpc" diff --git a/shared/addon/hashicorp/forge/load.go b/shared/addon/hashicorp/forge/load.go index e0062fb42a..08e27284c0 100644 --- a/shared/addon/hashicorp/forge/load.go +++ b/shared/addon/hashicorp/forge/load.go @@ -1,4 +1,4 @@ -package configservice +package forgeaddon import ( "go.woodpecker-ci.org/woodpecker/v2/server/forge" diff --git a/shared/addon/hashicorp/forge/server.go b/shared/addon/hashicorp/forge/server.go index ef057e9728..de12ca0cbe 100644 --- a/shared/addon/hashicorp/forge/server.go +++ b/shared/addon/hashicorp/forge/server.go @@ -1,4 +1,4 @@ -package configservice +package forgeaddon import ( "context" From 458b6870d51b2609af2b65e3b8534f81b7f87616 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 11 Feb 2024 19:11:15 +0100 Subject: [PATCH 13/44] fix merge --- pipeline/errors/error.go | 36 ++++++------------------- pipeline/errors/types/errors.go | 1 + pipeline/frontend/yaml/linter/linter.go | 12 ++++----- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/pipeline/errors/error.go b/pipeline/errors/error.go index 1a0ae167cc..f8bba4c67f 100644 --- a/pipeline/errors/error.go +++ b/pipeline/errors/error.go @@ -2,28 +2,12 @@ package errors import ( "errors" - "fmt" "go.uber.org/multierr" -) - -type PipelineErrorType string -const ( - PipelineErrorTypeLinter PipelineErrorType = "linter" // some error with the config syntax - PipelineErrorTypeDeprecation PipelineErrorType = "deprecation" // using some deprecated feature - PipelineErrorTypeCompiler PipelineErrorType = "compiler" // some error with the config semantics - PipelineErrorTypeGeneric PipelineErrorType = "generic" // some generic error - PipelineErrorTypeBadHabit PipelineErrorType = "bad_habit" // some bad-habit error + "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors/types" ) -type PipelineError struct { - Type PipelineErrorType `json:"type"` - Message string `json:"message"` - IsWarning bool `json:"is_warning"` - Data any `json:"data"` -} - type LinterErrorData struct { File string `json:"file"` Field string `json:"field"` @@ -35,12 +19,8 @@ type DeprecationErrorData struct { Docs string `json:"docs"` } -func (e *PipelineError) Error() string { - return fmt.Sprintf("[%s] %s", e.Type, e.Message) -} - -func (e *PipelineError) GetLinterData() *LinterErrorData { - if e.Type != PipelineErrorTypeLinter { +func GetLinterData(e *types.PipelineError) *LinterErrorData { + if e.Type != types.PipelineErrorTypeLinter { return nil } @@ -51,16 +31,16 @@ func (e *PipelineError) GetLinterData() *LinterErrorData { return nil } -func GetPipelineErrors(err error) []*PipelineError { - var pipelineErrors []*PipelineError +func GetPipelineErrors(err error) []*types.PipelineError { + var pipelineErrors []*types.PipelineError for _, _err := range multierr.Errors(err) { - var err *PipelineError + var err *types.PipelineError if errors.As(_err, &err) { pipelineErrors = append(pipelineErrors, err) } else { - pipelineErrors = append(pipelineErrors, &PipelineError{ + pipelineErrors = append(pipelineErrors, &types.PipelineError{ Message: _err.Error(), - Type: PipelineErrorTypeGeneric, + Type: types.PipelineErrorTypeGeneric, }) } } diff --git a/pipeline/errors/types/errors.go b/pipeline/errors/types/errors.go index 42e7dde0db..752eb6904e 100644 --- a/pipeline/errors/types/errors.go +++ b/pipeline/errors/types/errors.go @@ -9,6 +9,7 @@ const ( PipelineErrorTypeDeprecation PipelineErrorType = "deprecation" // using some deprecated feature PipelineErrorTypeCompiler PipelineErrorType = "compiler" // some error with the config semantics PipelineErrorTypeGeneric PipelineErrorType = "generic" // some generic error + PipelineErrorTypeBadHabit PipelineErrorType = "bad_habit" // some bad-habit error ) type PipelineError struct { diff --git a/pipeline/frontend/yaml/linter/linter.go b/pipeline/frontend/yaml/linter/linter.go index ba83df2401..dc1a262a76 100644 --- a/pipeline/frontend/yaml/linter/linter.go +++ b/pipeline/frontend/yaml/linter/linter.go @@ -266,8 +266,8 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { for i, c := range parsed.When.Constraints { if len(c.Event.Exclude) != 0 { - err = multierr.Append(err, &errors.PipelineError{ - Type: errors.PipelineErrorTypeDeprecation, + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeDeprecation, Message: "Please only use allow lists for events", Data: errors.DeprecationErrorData{ File: config.File, @@ -282,8 +282,8 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { for _, step := range parsed.Steps.ContainerList { for i, c := range step.When.Constraints { if len(c.Event.Exclude) != 0 { - err = multierr.Append(err, &errors.PipelineError{ - Type: errors.PipelineErrorTypeDeprecation, + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeDeprecation, Message: "Please only use allow lists for events", Data: errors.DeprecationErrorData{ File: config.File, @@ -332,8 +332,8 @@ func (l *Linter) lintBadHabits(config *WorkflowConfig) (err error) { } } if field != "" { - err = multierr.Append(err, &errors.PipelineError{ - Type: errors.PipelineErrorTypeBadHabit, + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeBadHabit, Message: "Please set an event filter on all when branches", Data: errors.LinterErrorData{ File: config.File, From e842ae7d197d75baec2b4dc57a3200b9f9433760 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 11 Feb 2024 19:15:26 +0100 Subject: [PATCH 14/44] move addon pkg --- cmd/server/setup.go | 4 ++-- {shared/addon => server/forge}/hashicorp/forge/args.go | 0 {shared/addon => server/forge}/hashicorp/forge/client.go | 0 {shared/addon => server/forge}/hashicorp/forge/interface.go | 0 {shared/addon => server/forge}/hashicorp/forge/load.go | 2 +- {shared/addon => server/forge}/hashicorp/forge/server.go | 0 {shared/addon => server/forge}/hashicorp/load.go | 0 {shared/addon => server/forge}/hashicorp/pluginaddon.go | 0 {shared/addon => server/forge}/hashicorp/serve.go | 0 9 files changed, 3 insertions(+), 3 deletions(-) rename {shared/addon => server/forge}/hashicorp/forge/args.go (100%) rename {shared/addon => server/forge}/hashicorp/forge/client.go (100%) rename {shared/addon => server/forge}/hashicorp/forge/interface.go (100%) rename {shared/addon => server/forge}/hashicorp/forge/load.go (68%) rename {shared/addon => server/forge}/hashicorp/forge/server.go (100%) rename {shared/addon => server/forge}/hashicorp/load.go (100%) rename {shared/addon => server/forge}/hashicorp/pluginaddon.go (100%) rename {shared/addon => server/forge}/hashicorp/serve.go (100%) diff --git a/cmd/server/setup.go b/cmd/server/setup.go index ecbd6b6774..6803bde758 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -36,11 +36,11 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/server/forge/gitea" "go.woodpecker-ci.org/woodpecker/v2/server/forge/github" "go.woodpecker-ci.org/woodpecker/v2/server/forge/gitlab" + "go.woodpecker-ci.org/woodpecker/v2/server/forge/hashicorp" + "go.woodpecker-ci.org/woodpecker/v2/server/forge/hashicorp/forge" "go.woodpecker-ci.org/woodpecker/v2/server/queue" "go.woodpecker-ci.org/woodpecker/v2/server/store" "go.woodpecker-ci.org/woodpecker/v2/server/store/datastore" - "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" - forgeaddon "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp/forge" ) func setupStore(c *cli.Context) (store.Store, error) { diff --git a/shared/addon/hashicorp/forge/args.go b/server/forge/hashicorp/forge/args.go similarity index 100% rename from shared/addon/hashicorp/forge/args.go rename to server/forge/hashicorp/forge/args.go diff --git a/shared/addon/hashicorp/forge/client.go b/server/forge/hashicorp/forge/client.go similarity index 100% rename from shared/addon/hashicorp/forge/client.go rename to server/forge/hashicorp/forge/client.go diff --git a/shared/addon/hashicorp/forge/interface.go b/server/forge/hashicorp/forge/interface.go similarity index 100% rename from shared/addon/hashicorp/forge/interface.go rename to server/forge/hashicorp/forge/interface.go diff --git a/shared/addon/hashicorp/forge/load.go b/server/forge/hashicorp/forge/load.go similarity index 68% rename from shared/addon/hashicorp/forge/load.go rename to server/forge/hashicorp/forge/load.go index 08e27284c0..e667829b76 100644 --- a/shared/addon/hashicorp/forge/load.go +++ b/server/forge/hashicorp/forge/load.go @@ -2,7 +2,7 @@ package forgeaddon import ( "go.woodpecker-ci.org/woodpecker/v2/server/forge" - "go.woodpecker-ci.org/woodpecker/v2/shared/addon/hashicorp" + "go.woodpecker-ci.org/woodpecker/v2/server/forge/hashicorp" ) var Addon hashicorp.Plugin[forge.Forge] = &Plugin{} diff --git a/shared/addon/hashicorp/forge/server.go b/server/forge/hashicorp/forge/server.go similarity index 100% rename from shared/addon/hashicorp/forge/server.go rename to server/forge/hashicorp/forge/server.go diff --git a/shared/addon/hashicorp/load.go b/server/forge/hashicorp/load.go similarity index 100% rename from shared/addon/hashicorp/load.go rename to server/forge/hashicorp/load.go diff --git a/shared/addon/hashicorp/pluginaddon.go b/server/forge/hashicorp/pluginaddon.go similarity index 100% rename from shared/addon/hashicorp/pluginaddon.go rename to server/forge/hashicorp/pluginaddon.go diff --git a/shared/addon/hashicorp/serve.go b/server/forge/hashicorp/serve.go similarity index 100% rename from shared/addon/hashicorp/serve.go rename to server/forge/hashicorp/serve.go From ad8d25b7db4f3d5de1baa71ae00aea5ef5a57478 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 11 Feb 2024 19:36:21 +0100 Subject: [PATCH 15/44] Remove moularity --- cmd/server/setup.go | 13 ++----------- server/forge/hashicorp/{forge => }/args.go | 2 +- server/forge/hashicorp/{forge => }/client.go | 15 ++++++++++----- server/forge/hashicorp/forge/load.go | 8 -------- server/forge/hashicorp/{forge => }/interface.go | 11 +---------- server/forge/hashicorp/load.go | 16 ++++++++-------- server/forge/hashicorp/pluginaddon.go | 9 --------- server/forge/hashicorp/serve.go | 6 ++++-- server/forge/hashicorp/{forge => }/server.go | 10 +++++++--- 9 files changed, 33 insertions(+), 57 deletions(-) rename server/forge/hashicorp/{forge => }/args.go (98%) rename server/forge/hashicorp/{forge => }/client.go (96%) delete mode 100644 server/forge/hashicorp/forge/load.go rename server/forge/hashicorp/{forge => }/interface.go (70%) delete mode 100644 server/forge/hashicorp/pluginaddon.go rename server/forge/hashicorp/{forge => }/server.go (95%) diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 6803bde758..dca2a06203 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -37,7 +37,6 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/server/forge/github" "go.woodpecker-ci.org/woodpecker/v2/server/forge/gitlab" "go.woodpecker-ci.org/woodpecker/v2/server/forge/hashicorp" - "go.woodpecker-ci.org/woodpecker/v2/server/forge/hashicorp/forge" "go.woodpecker-ci.org/woodpecker/v2/server/queue" "go.woodpecker-ci.org/woodpecker/v2/server/store" "go.woodpecker-ci.org/woodpecker/v2/server/store/datastore" @@ -106,17 +105,9 @@ func setupMembershipService(_ *cli.Context, r forge.Forge) cache.MembershipServi // setupForge helper function to set up the forge from the CLI arguments. func setupForge(c *cli.Context) (forge.Forge, error) { - if a := c.String("addons-forge"); a != "" { - addonExt, err := hashicorp.Load(a, forgeaddon.Addon) - if err != nil { - return nil, err - } - if addonExt != nil { - return addonExt.Value, nil - } - } - switch { + case c.String("addons-forge") != "": + return hashicorp.Load(c.String("addons-forge")) case c.Bool("github"): return setupGitHub(c) case c.Bool("gitlab"): diff --git a/server/forge/hashicorp/forge/args.go b/server/forge/hashicorp/args.go similarity index 98% rename from server/forge/hashicorp/forge/args.go rename to server/forge/hashicorp/args.go index 55ff0ab655..0e5b3a5315 100644 --- a/server/forge/hashicorp/forge/args.go +++ b/server/forge/hashicorp/args.go @@ -1,4 +1,4 @@ -package forgeaddon +package hashicorp import ( "go.woodpecker-ci.org/woodpecker/v2/server/model" diff --git a/server/forge/hashicorp/forge/client.go b/server/forge/hashicorp/client.go similarity index 96% rename from server/forge/hashicorp/forge/client.go rename to server/forge/hashicorp/client.go index 40d8a042cc..67fdaded52 100644 --- a/server/forge/hashicorp/forge/client.go +++ b/server/forge/hashicorp/client.go @@ -1,4 +1,4 @@ -package forgeaddon +package hashicorp import ( "context" @@ -218,17 +218,22 @@ func (g *RPC) Branches(ctx context.Context, u *model.User, r *model.Repo, p *mod return resp, json.Unmarshal(jsonResp, &resp) } -func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (string, error) { +func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (*model.Commit, error) { args, err := json.Marshal(&argumentsBranchHead{ U: u, R: r, Branch: branch, }) if err != nil { - return "", err + return nil, err } - var resp string - return resp, g.client.Call("Plugin.BranchHead", args, &resp) + var jsonResp []byte + err = g.client.Call("Plugin.BranchHead", args, &jsonResp) + if err != nil { + return nil, err + } + var resp *model.Commit + return resp, json.Unmarshal(jsonResp, &resp) } func (g *RPC) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) { diff --git a/server/forge/hashicorp/forge/load.go b/server/forge/hashicorp/forge/load.go deleted file mode 100644 index e667829b76..0000000000 --- a/server/forge/hashicorp/forge/load.go +++ /dev/null @@ -1,8 +0,0 @@ -package forgeaddon - -import ( - "go.woodpecker-ci.org/woodpecker/v2/server/forge" - "go.woodpecker-ci.org/woodpecker/v2/server/forge/hashicorp" -) - -var Addon hashicorp.Plugin[forge.Forge] = &Plugin{} diff --git a/server/forge/hashicorp/forge/interface.go b/server/forge/hashicorp/interface.go similarity index 70% rename from server/forge/hashicorp/forge/interface.go rename to server/forge/hashicorp/interface.go index 39edebee1a..50c99b657d 100644 --- a/server/forge/hashicorp/forge/interface.go +++ b/server/forge/hashicorp/interface.go @@ -1,4 +1,4 @@ -package forgeaddon +package hashicorp import ( "net/rpc" @@ -12,15 +12,6 @@ type Plugin struct { Impl forge.Forge } -func (p *Plugin) Key() string { - return "forge" -} - -func (p *Plugin) WithImpl(t forge.Forge) plugin.Plugin { - p.Impl = t - return p -} - func (p *Plugin) Server(*plugin.MuxBroker) (any, error) { return &RPCServer{Impl: p.Impl}, nil } diff --git a/server/forge/hashicorp/load.go b/server/forge/hashicorp/load.go index a1fbe60803..bffc05a464 100644 --- a/server/forge/hashicorp/load.go +++ b/server/forge/hashicorp/load.go @@ -4,17 +4,17 @@ import ( "os/exec" "github.com/hashicorp/go-plugin" + + "go.woodpecker-ci.org/woodpecker/v2/server/forge" ) -type Addon[T any] struct { - Value T -} +const pluginKey = "forge" -func Load[T any](file string, a Plugin[T]) (*Addon[T], error) { +func Load(file string) (forge.Forge, error) { client := plugin.NewClient(&plugin.ClientConfig{ HandshakeConfig: HandshakeConfig, Plugins: map[string]plugin.Plugin{ - a.Key(): a, + pluginKey: &Plugin{}, }, Cmd: exec.Command(file), }) @@ -25,13 +25,13 @@ func Load[T any](file string, a Plugin[T]) (*Addon[T], error) { return nil, err } - raw, err := rpcClient.Dispense(a.Key()) + raw, err := rpcClient.Dispense(pluginKey) if err != nil { return nil, err } - extension, _ := raw.(T) - return &Addon[T]{Value: extension}, nil + extension, _ := raw.(forge.Forge) + return extension, nil } var HandshakeConfig = plugin.HandshakeConfig{ diff --git a/server/forge/hashicorp/pluginaddon.go b/server/forge/hashicorp/pluginaddon.go deleted file mode 100644 index a074f52dd0..0000000000 --- a/server/forge/hashicorp/pluginaddon.go +++ /dev/null @@ -1,9 +0,0 @@ -package hashicorp - -import "github.com/hashicorp/go-plugin" - -type Plugin[T any] interface { - plugin.Plugin - Key() string - WithImpl(T) plugin.Plugin -} diff --git a/server/forge/hashicorp/serve.go b/server/forge/hashicorp/serve.go index 29ea9d4877..5701f2ddec 100644 --- a/server/forge/hashicorp/serve.go +++ b/server/forge/hashicorp/serve.go @@ -2,13 +2,15 @@ package hashicorp import ( "github.com/hashicorp/go-plugin" + + "go.woodpecker-ci.org/woodpecker/v2/server/forge" ) -func Serve[T any](addon Plugin[T], impl T) { +func Serve(impl forge.Forge) { plugin.Serve(&plugin.ServeConfig{ HandshakeConfig: HandshakeConfig, Plugins: map[string]plugin.Plugin{ - addon.Key(): addon.WithImpl(impl), + pluginKey: &Plugin{Impl: impl}, }, }) } diff --git a/server/forge/hashicorp/forge/server.go b/server/forge/hashicorp/server.go similarity index 95% rename from server/forge/hashicorp/forge/server.go rename to server/forge/hashicorp/server.go index de12ca0cbe..ca3686ed72 100644 --- a/server/forge/hashicorp/forge/server.go +++ b/server/forge/hashicorp/server.go @@ -1,4 +1,4 @@ -package forgeaddon +package hashicorp import ( "context" @@ -151,13 +151,17 @@ func (s *RPCServer) Branches(args []byte, resp *[]byte) error { return err } -func (s *RPCServer) BranchHead(args []byte, resp *string) error { +func (s *RPCServer) BranchHead(args []byte, resp *[]byte) error { var a argumentsBranchHead err := json.Unmarshal(args, &a) if err != nil { return err } - *resp, err = s.Impl.BranchHead(mkCtx(), a.U, a.R, a.Branch) + commit, err := s.Impl.BranchHead(mkCtx(), a.U, a.R, a.Branch) + if err != nil { + return err + } + *resp, err = json.Marshal(commit) return err } From b17a6d4117eb2e0bc802bddd9d9ffb1686a11320 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 11 Feb 2024 20:23:35 +0100 Subject: [PATCH 16/44] complete hook func --- server/forge/hashicorp/args.go | 8 ++++++++ server/forge/hashicorp/client.go | 18 +++++++++++++++--- server/forge/hashicorp/load.go | 2 +- server/forge/hashicorp/server.go | 12 +++++++++--- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/server/forge/hashicorp/args.go b/server/forge/hashicorp/args.go index 0e5b3a5315..6f5ace1b1a 100644 --- a/server/forge/hashicorp/args.go +++ b/server/forge/hashicorp/args.go @@ -62,3 +62,11 @@ type responseHook struct { Repo *model.Repo `json:"repo"` Pipeline *model.Pipeline `json:"pipeline"` } + +type httpRequest struct { + Method string `json:"method"` + URL string `json:"url"` + Header map[string][]string `json:"header"` + Form map[string][]string `json:"form"` + Body []byte `json:"body"` +} diff --git a/server/forge/hashicorp/client.go b/server/forge/hashicorp/client.go index 67fdaded52..ca99c1e7a3 100644 --- a/server/forge/hashicorp/client.go +++ b/server/forge/hashicorp/client.go @@ -3,6 +3,7 @@ package hashicorp import ( "context" "encoding/json" + "io" "net/http" "net/rpc" @@ -13,7 +14,9 @@ import ( // TODO issue: user models are not sent with token/secret (token/secret is json:"-") // possible solution: two-way-communication with two funcs: 1. token/secret for user 2. token/secret for repo // however, that's an issue in both directions: the addon can't return tokens/secrets -type RPC struct{ client *rpc.Client } +type RPC struct { + client *rpc.Client +} func (g *RPC) Name() string { var resp string @@ -255,8 +258,17 @@ func (g *RPC) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p } func (g *RPC) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { - // TODO marshalling http.request - args, err := json.Marshal(r) + body, err := io.ReadAll(r.Body) + if err != nil { + return nil, nil, err + } + args, err := json.Marshal(&httpRequest{ + Method: r.Method, + URL: r.URL.String(), + Header: r.Header, + Form: r.Form, + Body: body, + }) if err != nil { return nil, nil, err } diff --git a/server/forge/hashicorp/load.go b/server/forge/hashicorp/load.go index bffc05a464..43ea3d45e7 100644 --- a/server/forge/hashicorp/load.go +++ b/server/forge/hashicorp/load.go @@ -36,6 +36,6 @@ func Load(file string) (forge.Forge, error) { var HandshakeConfig = plugin.HandshakeConfig{ ProtocolVersion: 1, - MagicCookieKey: "WOODPECKER_PLUGIN", + MagicCookieKey: "WOODPECKER_FORGE_ADDON_PLUGIN", MagicCookieValue: "woodpecker-plugin-magic-cookie-value", } diff --git a/server/forge/hashicorp/server.go b/server/forge/hashicorp/server.go index ca3686ed72..58e5b10431 100644 --- a/server/forge/hashicorp/server.go +++ b/server/forge/hashicorp/server.go @@ -1,6 +1,7 @@ package hashicorp import ( + "bytes" "context" "encoding/json" "net/http" @@ -208,13 +209,18 @@ func (s *RPCServer) Org(args []byte, resp *[]byte) error { } func (s *RPCServer) Hook(args []byte, resp *[]byte) error { - // TODO http.request json - var a *http.Request + var a httpRequest err := json.Unmarshal(args, &a) if err != nil { return err } - repo, pipeline, err := s.Impl.Hook(mkCtx(), a) + req, err := http.NewRequest(a.Method, a.URL, bytes.NewBuffer(a.Body)) + if err != nil { + return err + } + req.Header = a.Header + req.Form = a.Form + repo, pipeline, err := s.Impl.Hook(mkCtx(), req) if err != nil { return err } From f2b1beeb9e20ad70e64420dec4fd9321035e6eb8 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Tue, 13 Feb 2024 20:28:39 +0100 Subject: [PATCH 17/44] finish basic work --- server/forge/hashicorp/args.go | 5 ++ server/forge/hashicorp/client.go | 60 ++++++++++++++----- server/forge/hashicorp/load.go | 41 ------------- .../hashicorp/{interface.go => plugin.go} | 8 +++ server/forge/hashicorp/serve.go | 16 ----- server/forge/hashicorp/server.go | 24 ++++++-- 6 files changed, 77 insertions(+), 77 deletions(-) delete mode 100644 server/forge/hashicorp/load.go rename server/forge/hashicorp/{interface.go => plugin.go} (64%) delete mode 100644 server/forge/hashicorp/serve.go diff --git a/server/forge/hashicorp/args.go b/server/forge/hashicorp/args.go index 6f5ace1b1a..f8b0d70838 100644 --- a/server/forge/hashicorp/args.go +++ b/server/forge/hashicorp/args.go @@ -63,6 +63,11 @@ type responseHook struct { Pipeline *model.Pipeline `json:"pipeline"` } +type responseLogin struct { + User *model.User `json:"user"` + RedirectURL string `json:"redirect_url"` +} + type httpRequest struct { Method string `json:"method"` URL string `json:"url"` diff --git a/server/forge/hashicorp/client.go b/server/forge/hashicorp/client.go index ca99c1e7a3..b616a9df21 100644 --- a/server/forge/hashicorp/client.go +++ b/server/forge/hashicorp/client.go @@ -6,11 +6,42 @@ import ( "io" "net/http" "net/rpc" + "os/exec" + "github.com/hashicorp/go-plugin" + + "go.woodpecker-ci.org/woodpecker/v2/server/forge" "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" "go.woodpecker-ci.org/woodpecker/v2/server/model" ) +// make sure RPC implements forge.Forge +var _ forge.Forge = new(RPC) + +func Load(file string) (forge.Forge, error) { + client := plugin.NewClient(&plugin.ClientConfig{ + HandshakeConfig: HandshakeConfig, + Plugins: map[string]plugin.Plugin{ + pluginKey: &Plugin{}, + }, + Cmd: exec.Command(file), + }) + // TODO defer client.Kill() + + rpcClient, err := client.Client() + if err != nil { + return nil, err + } + + raw, err := rpcClient.Dispense(pluginKey) + if err != nil { + return nil, err + } + + extension, _ := raw.(forge.Forge) + return extension, nil +} + // TODO issue: user models are not sent with token/secret (token/secret is json:"-") // possible solution: two-way-communication with two funcs: 1. token/secret for user 2. token/secret for repo // however, that's an issue in both directions: the addon can't return tokens/secrets @@ -30,25 +61,24 @@ func (g *RPC) URL() string { return resp } -func (g *RPC) Login(ctx context.Context, w http.ResponseWriter, r *http.Request) (*model.User, error) { - /* TODO args, err := json.Marshal(&arguments{ - Repo: repo, - Pipeline: pipeline, - CurrentFileMeta: currentFileMeta, - Netrc: netrc, - Timeout: timeout, - }) +func (g *RPC) Login(ctx context.Context, r *types.OAuthRequest) (*model.User, string, error) { + args, err := json.Marshal(r) if err != nil { - return nil, err - }*/ + return nil, "", err + } var jsonResp []byte - /*err = g.client.Call("Plugin.Login", args, &jsonResp) + err = g.client.Call("Plugin.Login", args, &jsonResp) if err != nil { - return nil, err - }*/ + return nil, "", err + } - var resp *model.User - return resp, json.Unmarshal(jsonResp, resp) + var resp responseLogin + err = json.Unmarshal(jsonResp, &resp) + if err != nil { + return nil, "", err + } + + return resp.User, resp.RedirectURL, nil } func (g *RPC) Auth(ctx context.Context, token, secret string) (string, error) { diff --git a/server/forge/hashicorp/load.go b/server/forge/hashicorp/load.go deleted file mode 100644 index 43ea3d45e7..0000000000 --- a/server/forge/hashicorp/load.go +++ /dev/null @@ -1,41 +0,0 @@ -package hashicorp - -import ( - "os/exec" - - "github.com/hashicorp/go-plugin" - - "go.woodpecker-ci.org/woodpecker/v2/server/forge" -) - -const pluginKey = "forge" - -func Load(file string) (forge.Forge, error) { - client := plugin.NewClient(&plugin.ClientConfig{ - HandshakeConfig: HandshakeConfig, - Plugins: map[string]plugin.Plugin{ - pluginKey: &Plugin{}, - }, - Cmd: exec.Command(file), - }) - // TODO defer client.Kill() - - rpcClient, err := client.Client() - if err != nil { - return nil, err - } - - raw, err := rpcClient.Dispense(pluginKey) - if err != nil { - return nil, err - } - - extension, _ := raw.(forge.Forge) - return extension, nil -} - -var HandshakeConfig = plugin.HandshakeConfig{ - ProtocolVersion: 1, - MagicCookieKey: "WOODPECKER_FORGE_ADDON_PLUGIN", - MagicCookieValue: "woodpecker-plugin-magic-cookie-value", -} diff --git a/server/forge/hashicorp/interface.go b/server/forge/hashicorp/plugin.go similarity index 64% rename from server/forge/hashicorp/interface.go rename to server/forge/hashicorp/plugin.go index 50c99b657d..3285cd1cbe 100644 --- a/server/forge/hashicorp/interface.go +++ b/server/forge/hashicorp/plugin.go @@ -8,6 +8,14 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/server/forge" ) +const pluginKey = "forge" + +var HandshakeConfig = plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "WOODPECKER_FORGE_ADDON_PLUGIN", + MagicCookieValue: "woodpecker-plugin-magic-cookie-value", +} + type Plugin struct { Impl forge.Forge } diff --git a/server/forge/hashicorp/serve.go b/server/forge/hashicorp/serve.go deleted file mode 100644 index 5701f2ddec..0000000000 --- a/server/forge/hashicorp/serve.go +++ /dev/null @@ -1,16 +0,0 @@ -package hashicorp - -import ( - "github.com/hashicorp/go-plugin" - - "go.woodpecker-ci.org/woodpecker/v2/server/forge" -) - -func Serve(impl forge.Forge) { - plugin.Serve(&plugin.ServeConfig{ - HandshakeConfig: HandshakeConfig, - Plugins: map[string]plugin.Plugin{ - pluginKey: &Plugin{Impl: impl}, - }, - }) -} diff --git a/server/forge/hashicorp/server.go b/server/forge/hashicorp/server.go index 58e5b10431..a77838299b 100644 --- a/server/forge/hashicorp/server.go +++ b/server/forge/hashicorp/server.go @@ -6,10 +6,22 @@ import ( "encoding/json" "net/http" + "github.com/hashicorp/go-plugin" + "go.woodpecker-ci.org/woodpecker/v2/server/forge" + "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" "go.woodpecker-ci.org/woodpecker/v2/server/model" ) +func Serve(impl forge.Forge) { + plugin.Serve(&plugin.ServeConfig{ + HandshakeConfig: HandshakeConfig, + Plugins: map[string]plugin.Plugin{ + pluginKey: &Plugin{Impl: impl}, + }, + }) +} + func mkCtx() context.Context { return context.Background() } @@ -232,16 +244,18 @@ func (s *RPCServer) Hook(args []byte, resp *[]byte) error { } func (s *RPCServer) Login(args []byte, resp *[]byte) error { - // TODO http.request and iowriter json - var a *http.Request - err := json.Unmarshal(args, &a) + var a *types.OAuthRequest + err := json.Unmarshal(args, a) if err != nil { return err } - user, err := s.Impl.Login(mkCtx(), nil, a) + user, red, err := s.Impl.Login(mkCtx(), a) if err != nil { return err } - *resp, err = json.Marshal(user) + *resp, err = json.Marshal(&responseLogin{ + User: user, + RedirectURL: red, + }) return err } From 21d1ab33b9bf89821aaaf39213fa0ed767f2d0dc Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Tue, 13 Feb 2024 20:29:27 +0100 Subject: [PATCH 18/44] add copyright --- server/forge/hashicorp/args.go | 14 ++++++++++++++ server/forge/hashicorp/client.go | 14 ++++++++++++++ server/forge/hashicorp/plugin.go | 14 ++++++++++++++ server/forge/hashicorp/server.go | 14 ++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/server/forge/hashicorp/args.go b/server/forge/hashicorp/args.go index f8b0d70838..89017e68b1 100644 --- a/server/forge/hashicorp/args.go +++ b/server/forge/hashicorp/args.go @@ -1,3 +1,17 @@ +// Copyright 2024 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 hashicorp import ( diff --git a/server/forge/hashicorp/client.go b/server/forge/hashicorp/client.go index b616a9df21..0187d19bf7 100644 --- a/server/forge/hashicorp/client.go +++ b/server/forge/hashicorp/client.go @@ -1,3 +1,17 @@ +// Copyright 2024 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 hashicorp import ( diff --git a/server/forge/hashicorp/plugin.go b/server/forge/hashicorp/plugin.go index 3285cd1cbe..ae0cd16f89 100644 --- a/server/forge/hashicorp/plugin.go +++ b/server/forge/hashicorp/plugin.go @@ -1,3 +1,17 @@ +// Copyright 2024 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 hashicorp import ( diff --git a/server/forge/hashicorp/server.go b/server/forge/hashicorp/server.go index a77838299b..479830bae2 100644 --- a/server/forge/hashicorp/server.go +++ b/server/forge/hashicorp/server.go @@ -1,3 +1,17 @@ +// Copyright 2024 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 hashicorp import ( From e06a5201cc6ff3f93cc21062c1f4cdf700e23302 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Tue, 13 Feb 2024 20:41:18 +0100 Subject: [PATCH 19/44] fix json on user model --- server/forge/hashicorp/args.go | 89 ++++++++++++++++++++++++++++---- server/forge/hashicorp/client.go | 26 +++++----- server/forge/hashicorp/server.go | 26 +++++----- 3 files changed, 104 insertions(+), 37 deletions(-) diff --git a/server/forge/hashicorp/args.go b/server/forge/hashicorp/args.go index 89017e68b1..4dc9d5465e 100644 --- a/server/forge/hashicorp/args.go +++ b/server/forge/hashicorp/args.go @@ -24,52 +24,52 @@ type argumentsAuth struct { } type argumentsRepo struct { - U *model.User `json:"u"` + U *modelUser `json:"u"` RemoteID model.ForgeRemoteID `json:"remote_id"` Owner string `json:"owner"` Name string `json:"name"` } type argumentsFileDir struct { - U *model.User `json:"u"` + U *modelUser `json:"u"` R *model.Repo `json:"r"` B *model.Pipeline `json:"b"` F string `json:"f"` } type argumentsStatus struct { - U *model.User `json:"u"` + U *modelUser `json:"u"` R *model.Repo `json:"r"` B *model.Pipeline `json:"b"` P *model.Workflow `json:"p"` } type argumentsNetrc struct { - U *model.User `json:"u"` + U *modelUser `json:"u"` R *model.Repo `json:"r"` } type argumentsActivateDeactivate struct { - U *model.User `json:"u"` + U *modelUser `json:"u"` R *model.Repo `json:"r"` Link string `json:"link"` } type argumentsBranchesPullRequests struct { - U *model.User `json:"u"` + U *modelUser `json:"u"` R *model.Repo `json:"r"` P *model.ListOptions `json:"p"` } type argumentsBranchHead struct { - U *model.User `json:"u"` + U *modelUser `json:"u"` R *model.Repo `json:"r"` Branch string `json:"branch"` } type argumentsOrgMembershipOrg struct { - U *model.User `json:"u"` - Org string `json:"org"` + U *modelUser `json:"u"` + Org string `json:"org"` } type responseHook struct { @@ -78,8 +78,8 @@ type responseHook struct { } type responseLogin struct { - User *model.User `json:"user"` - RedirectURL string `json:"redirect_url"` + User *modelUser `json:"user"` + RedirectURL string `json:"redirect_url"` } type httpRequest struct { @@ -89,3 +89,70 @@ type httpRequest struct { Form map[string][]string `json:"form"` Body []byte `json:"body"` } + +// modelUser is a model.User, but all fields are marshaled to JSON +type modelUser struct { + // the id for this user. + ID int64 `json:"id"` + + ForgeRemoteID model.ForgeRemoteID `json:"forge_remote_id"` + + // Login is the username for this user. + Login string `json:"login"` + + // Token is the oauth2 token. + Token string `json:"token"` + + // Secret is the oauth2 token secret. + Secret string `json:"secret"` + + // Expiry is the token and secret expiration timestamp. + Expiry int64 `json:"expiry"` + + // Email is the email address for this user. + Email string `json:"email"` + + // the avatar url for this user. + Avatar string `json:"avatar_url"` + + // Admin indicates the user is a system administrator. + Admin bool `json:"admin"` + + // Hash is a unique token used to sign tokens. + Hash string `json:"hash"` + + // OrgID is the of the user as model.Org. + OrgID int64 `json:"org_id"` +} + +func (m *modelUser) asModel() *model.User { + return &model.User{ + ID: m.ID, + ForgeRemoteID: m.ForgeRemoteID, + Login: m.Login, + Token: m.Token, + Secret: m.Secret, + Expiry: m.Expiry, + Email: m.Email, + Avatar: m.Avatar, + Admin: m.Admin, + Hash: m.Hash, + OrgID: m.OrgID, + } +} + +func modelUserFromModel(u *model.User) *modelUser { + return &modelUser{ + ID: u.ID, + ForgeRemoteID: u.ForgeRemoteID, + Login: u.Login, + Token: u.Token, + Secret: u.Secret, + Expiry: u.Expiry, + Email: u.Email, + Avatar: u.Avatar, + Admin: u.Admin, + Hash: u.Hash, + OrgID: u.OrgID, + } +} diff --git a/server/forge/hashicorp/client.go b/server/forge/hashicorp/client.go index 0187d19bf7..f181916f7e 100644 --- a/server/forge/hashicorp/client.go +++ b/server/forge/hashicorp/client.go @@ -92,7 +92,7 @@ func (g *RPC) Login(ctx context.Context, r *types.OAuthRequest) (*model.User, st return nil, "", err } - return resp.User, resp.RedirectURL, nil + return resp.User.asModel(), resp.RedirectURL, nil } func (g *RPC) Auth(ctx context.Context, token, secret string) (string, error) { @@ -124,7 +124,7 @@ func (g *RPC) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) { func (g *RPC) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRemoteID, owner, name string) (*model.Repo, error) { args, err := json.Marshal(&argumentsRepo{ - U: u, + U: modelUserFromModel(u), RemoteID: remoteID, Owner: owner, Name: name, @@ -159,7 +159,7 @@ func (g *RPC) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) { func (g *RPC) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { args, err := json.Marshal(&argumentsFileDir{ - U: u, + U: modelUserFromModel(u), R: r, B: b, F: f, @@ -173,7 +173,7 @@ func (g *RPC) File(ctx context.Context, u *model.User, r *model.Repo, b *model.P func (g *RPC) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*types.FileMeta, error) { args, err := json.Marshal(&argumentsFileDir{ - U: u, + U: modelUserFromModel(u), R: r, B: b, F: f, @@ -192,7 +192,7 @@ func (g *RPC) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pi func (g *RPC) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Workflow) error { args, err := json.Marshal(&argumentsStatus{ - U: u, + U: modelUserFromModel(u), R: r, B: b, P: p, @@ -206,7 +206,7 @@ func (g *RPC) Status(ctx context.Context, u *model.User, r *model.Repo, b *model func (g *RPC) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { args, err := json.Marshal(&argumentsNetrc{ - U: u, + U: modelUserFromModel(u), R: r, }) if err != nil { @@ -223,7 +223,7 @@ func (g *RPC) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { func (g *RPC) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error { args, err := json.Marshal(&argumentsActivateDeactivate{ - U: u, + U: modelUserFromModel(u), R: r, Link: link, }) @@ -236,7 +236,7 @@ func (g *RPC) Activate(ctx context.Context, u *model.User, r *model.Repo, link s func (g *RPC) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { args, err := json.Marshal(&argumentsActivateDeactivate{ - U: u, + U: modelUserFromModel(u), R: r, Link: link, }) @@ -249,7 +249,7 @@ func (g *RPC) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link func (g *RPC) Branches(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) { args, err := json.Marshal(&argumentsBranchesPullRequests{ - U: u, + U: modelUserFromModel(u), R: r, P: p, }) @@ -267,7 +267,7 @@ func (g *RPC) Branches(ctx context.Context, u *model.User, r *model.Repo, p *mod func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (*model.Commit, error) { args, err := json.Marshal(&argumentsBranchHead{ - U: u, + U: modelUserFromModel(u), R: r, Branch: branch, }) @@ -285,7 +285,7 @@ func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, bran func (g *RPC) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) { args, err := json.Marshal(&argumentsBranchesPullRequests{ - U: u, + U: modelUserFromModel(u), R: r, P: p, }) @@ -331,7 +331,7 @@ func (g *RPC) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pi func (g *RPC) OrgMembership(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error) { args, err := json.Marshal(&argumentsOrgMembershipOrg{ - U: u, + U: modelUserFromModel(u), Org: org, }) if err != nil { @@ -348,7 +348,7 @@ func (g *RPC) OrgMembership(ctx context.Context, u *model.User, org string) (*mo func (g *RPC) Org(ctx context.Context, u *model.User, org string) (*model.Org, error) { args, err := json.Marshal(&argumentsOrgMembershipOrg{ - U: u, + U: modelUserFromModel(u), Org: org, }) if err != nil { diff --git a/server/forge/hashicorp/server.go b/server/forge/hashicorp/server.go index 479830bae2..6a45e2af56 100644 --- a/server/forge/hashicorp/server.go +++ b/server/forge/hashicorp/server.go @@ -74,7 +74,7 @@ func (s *RPCServer) Repo(args []byte, resp *[]byte) error { if err != nil { return err } - repos, err := s.Impl.Repo(mkCtx(), a.U, a.RemoteID, a.Owner, a.Name) + repos, err := s.Impl.Repo(mkCtx(), a.U.asModel(), a.RemoteID, a.Owner, a.Name) if err != nil { return err } @@ -102,7 +102,7 @@ func (s *RPCServer) File(args []byte, resp *[]byte) error { if err != nil { return err } - *resp, err = s.Impl.File(mkCtx(), a.U, a.R, a.B, a.F) + *resp, err = s.Impl.File(mkCtx(), a.U.asModel(), a.R, a.B, a.F) return err } @@ -112,7 +112,7 @@ func (s *RPCServer) Dir(args []byte, resp *[]byte) error { if err != nil { return err } - meta, err := s.Impl.Dir(mkCtx(), a.U, a.R, a.B, a.F) + meta, err := s.Impl.Dir(mkCtx(), a.U.asModel(), a.R, a.B, a.F) if err != nil { return err } @@ -127,7 +127,7 @@ func (s *RPCServer) Status(args []byte, resp *[]byte) error { return err } *resp = []byte{} - return s.Impl.Status(mkCtx(), a.U, a.R, a.B, a.P) + return s.Impl.Status(mkCtx(), a.U.asModel(), a.R, a.B, a.P) } func (s *RPCServer) Netrc(args []byte, resp *[]byte) error { @@ -136,7 +136,7 @@ func (s *RPCServer) Netrc(args []byte, resp *[]byte) error { if err != nil { return err } - netrc, err := s.Impl.Netrc(a.U, a.R) + netrc, err := s.Impl.Netrc(a.U.asModel(), a.R) if err != nil { return err } @@ -151,7 +151,7 @@ func (s *RPCServer) Activate(args []byte, resp *[]byte) error { return err } *resp = []byte{} - return s.Impl.Activate(mkCtx(), a.U, a.R, a.Link) + return s.Impl.Activate(mkCtx(), a.U.asModel(), a.R, a.Link) } func (s *RPCServer) Deactivate(args []byte, resp *[]byte) error { @@ -161,7 +161,7 @@ func (s *RPCServer) Deactivate(args []byte, resp *[]byte) error { return err } *resp = []byte{} - return s.Impl.Deactivate(mkCtx(), a.U, a.R, a.Link) + return s.Impl.Deactivate(mkCtx(), a.U.asModel(), a.R, a.Link) } func (s *RPCServer) Branches(args []byte, resp *[]byte) error { @@ -170,7 +170,7 @@ func (s *RPCServer) Branches(args []byte, resp *[]byte) error { if err != nil { return err } - branches, err := s.Impl.Branches(mkCtx(), a.U, a.R, a.P) + branches, err := s.Impl.Branches(mkCtx(), a.U.asModel(), a.R, a.P) if err != nil { return err } @@ -184,7 +184,7 @@ func (s *RPCServer) BranchHead(args []byte, resp *[]byte) error { if err != nil { return err } - commit, err := s.Impl.BranchHead(mkCtx(), a.U, a.R, a.Branch) + commit, err := s.Impl.BranchHead(mkCtx(), a.U.asModel(), a.R, a.Branch) if err != nil { return err } @@ -198,7 +198,7 @@ func (s *RPCServer) PullRequests(args []byte, resp *[]byte) error { if err != nil { return err } - prs, err := s.Impl.PullRequests(mkCtx(), a.U, a.R, a.P) + prs, err := s.Impl.PullRequests(mkCtx(), a.U.asModel(), a.R, a.P) if err != nil { return err } @@ -212,7 +212,7 @@ func (s *RPCServer) OrgMembership(args []byte, resp *[]byte) error { if err != nil { return err } - org, err := s.Impl.OrgMembership(mkCtx(), a.U, a.Org) + org, err := s.Impl.OrgMembership(mkCtx(), a.U.asModel(), a.Org) if err != nil { return err } @@ -226,7 +226,7 @@ func (s *RPCServer) Org(args []byte, resp *[]byte) error { if err != nil { return err } - org, err := s.Impl.Org(mkCtx(), a.U, a.Org) + org, err := s.Impl.Org(mkCtx(), a.U.asModel(), a.Org) if err != nil { return err } @@ -268,7 +268,7 @@ func (s *RPCServer) Login(args []byte, resp *[]byte) error { return err } *resp, err = json.Marshal(&responseLogin{ - User: user, + User: modelUserFromModel(user), RedirectURL: red, }) return err From 92f5391b8863aaa196ac1e4e47c5c9797b6dea95 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Tue, 13 Feb 2024 20:53:21 +0100 Subject: [PATCH 20/44] fix for repos & rework --- server/forge/hashicorp/args.go | 94 +++++++++++++++----------------- server/forge/hashicorp/client.go | 47 +++++++++------- server/forge/hashicorp/server.go | 37 +++++++------ 3 files changed, 93 insertions(+), 85 deletions(-) diff --git a/server/forge/hashicorp/args.go b/server/forge/hashicorp/args.go index 4dc9d5465e..baaaa7a048 100644 --- a/server/forge/hashicorp/args.go +++ b/server/forge/hashicorp/args.go @@ -32,39 +32,39 @@ type argumentsRepo struct { type argumentsFileDir struct { U *modelUser `json:"u"` - R *model.Repo `json:"r"` + R *modelRepo `json:"r"` B *model.Pipeline `json:"b"` F string `json:"f"` } type argumentsStatus struct { U *modelUser `json:"u"` - R *model.Repo `json:"r"` + R *modelRepo `json:"r"` B *model.Pipeline `json:"b"` P *model.Workflow `json:"p"` } type argumentsNetrc struct { - U *modelUser `json:"u"` - R *model.Repo `json:"r"` + U *modelUser `json:"u"` + R *modelRepo `json:"r"` } type argumentsActivateDeactivate struct { - U *modelUser `json:"u"` - R *model.Repo `json:"r"` - Link string `json:"link"` + U *modelUser `json:"u"` + R *modelRepo `json:"r"` + Link string `json:"link"` } type argumentsBranchesPullRequests struct { U *modelUser `json:"u"` - R *model.Repo `json:"r"` + R *modelRepo `json:"r"` P *model.ListOptions `json:"p"` } type argumentsBranchHead struct { - U *modelUser `json:"u"` - R *model.Repo `json:"r"` - Branch string `json:"branch"` + U *modelUser `json:"u"` + R *modelRepo `json:"r"` + Branch string `json:"branch"` } type argumentsOrgMembershipOrg struct { @@ -73,7 +73,7 @@ type argumentsOrgMembershipOrg struct { } type responseHook struct { - Repo *model.Repo `json:"repo"` + Repo *modelRepo `json:"repo"` Pipeline *model.Pipeline `json:"pipeline"` } @@ -90,16 +90,12 @@ type httpRequest struct { Body []byte `json:"body"` } -// modelUser is a model.User, but all fields are marshaled to JSON +// modelUser is an extension of model.User to marshal all fields to JSON type modelUser struct { - // the id for this user. - ID int64 `json:"id"` + User *model.User `json:"user"` ForgeRemoteID model.ForgeRemoteID `json:"forge_remote_id"` - // Login is the username for this user. - Login string `json:"login"` - // Token is the oauth2 token. Token string `json:"token"` @@ -109,50 +105,50 @@ type modelUser struct { // Expiry is the token and secret expiration timestamp. Expiry int64 `json:"expiry"` - // Email is the email address for this user. - Email string `json:"email"` - - // the avatar url for this user. - Avatar string `json:"avatar_url"` - - // Admin indicates the user is a system administrator. - Admin bool `json:"admin"` - // Hash is a unique token used to sign tokens. Hash string `json:"hash"` - - // OrgID is the of the user as model.Org. - OrgID int64 `json:"org_id"` } func (m *modelUser) asModel() *model.User { - return &model.User{ - ID: m.ID, - ForgeRemoteID: m.ForgeRemoteID, - Login: m.Login, - Token: m.Token, - Secret: m.Secret, - Expiry: m.Expiry, - Email: m.Email, - Avatar: m.Avatar, - Admin: m.Admin, - Hash: m.Hash, - OrgID: m.OrgID, - } + m.User.ForgeRemoteID = m.ForgeRemoteID + m.User.Token = m.Token + m.User.Secret = m.Secret + m.User.Expiry = m.Expiry + m.User.Hash = m.Hash + return m.User } func modelUserFromModel(u *model.User) *modelUser { return &modelUser{ - ID: u.ID, + User: u, ForgeRemoteID: u.ForgeRemoteID, - Login: u.Login, Token: u.Token, Secret: u.Secret, Expiry: u.Expiry, - Email: u.Email, - Avatar: u.Avatar, - Admin: u.Admin, Hash: u.Hash, - OrgID: u.OrgID, + } +} + +// modelUser is an extension of model.User to marshal all fields to JSON +type modelRepo struct { + Repo *model.Repo `json:"repo"` + UserID int64 `json:"-"` + Hash string `json:"-"` + Perm *model.Perm `json:"-"` +} + +func (m *modelRepo) asModel() *model.Repo { + m.Repo.UserID = m.UserID + m.Repo.Hash = m.Hash + m.Repo.Perm = m.Perm + return m.Repo +} + +func modelRepoFromModel(r *model.Repo) *modelRepo { + return &modelRepo{ + Repo: r, + UserID: r.UserID, + Hash: r.Hash, + Perm: r.Perm, } } diff --git a/server/forge/hashicorp/client.go b/server/forge/hashicorp/client.go index f181916f7e..ec9a0ad9c5 100644 --- a/server/forge/hashicorp/client.go +++ b/server/forge/hashicorp/client.go @@ -56,9 +56,6 @@ func Load(file string) (forge.Forge, error) { return extension, nil } -// TODO issue: user models are not sent with token/secret (token/secret is json:"-") -// possible solution: two-way-communication with two funcs: 1. token/secret for user 2. token/secret for repo -// however, that's an issue in both directions: the addon can't return tokens/secrets type RPC struct { client *rpc.Client } @@ -108,7 +105,7 @@ func (g *RPC) Auth(ctx context.Context, token, secret string) (string, error) { } func (g *RPC) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) { - args, err := json.Marshal(u) + args, err := json.Marshal(modelUserFromModel(u)) if err != nil { return nil, err } @@ -138,12 +135,16 @@ func (g *RPC) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRemot return nil, err } - var resp *model.Repo - return resp, json.Unmarshal(jsonResp, resp) + var resp *modelRepo + err = json.Unmarshal(jsonResp, resp) + if err != nil { + return nil, err + } + return resp.asModel(), nil } func (g *RPC) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) { - args, err := json.Marshal(u) + args, err := json.Marshal(modelUserFromModel(u)) if err != nil { return nil, err } @@ -153,14 +154,22 @@ func (g *RPC) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) { return nil, err } - var resp []*model.Repo - return resp, json.Unmarshal(jsonResp, &resp) + var resp []*modelRepo + err = json.Unmarshal(jsonResp, &resp) + if err != nil { + return nil, err + } + var modelRepos []*model.Repo + for _, repo := range resp { + modelRepos = append(modelRepos, repo.asModel()) + } + return modelRepos, nil } func (g *RPC) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { args, err := json.Marshal(&argumentsFileDir{ U: modelUserFromModel(u), - R: r, + R: modelRepoFromModel(r), B: b, F: f, }) @@ -174,7 +183,7 @@ func (g *RPC) File(ctx context.Context, u *model.User, r *model.Repo, b *model.P func (g *RPC) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*types.FileMeta, error) { args, err := json.Marshal(&argumentsFileDir{ U: modelUserFromModel(u), - R: r, + R: modelRepoFromModel(r), B: b, F: f, }) @@ -193,7 +202,7 @@ func (g *RPC) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pi func (g *RPC) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Workflow) error { args, err := json.Marshal(&argumentsStatus{ U: modelUserFromModel(u), - R: r, + R: modelRepoFromModel(r), B: b, P: p, }) @@ -207,7 +216,7 @@ func (g *RPC) Status(ctx context.Context, u *model.User, r *model.Repo, b *model func (g *RPC) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { args, err := json.Marshal(&argumentsNetrc{ U: modelUserFromModel(u), - R: r, + R: modelRepoFromModel(r), }) if err != nil { return nil, err @@ -224,7 +233,7 @@ func (g *RPC) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { func (g *RPC) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error { args, err := json.Marshal(&argumentsActivateDeactivate{ U: modelUserFromModel(u), - R: r, + R: modelRepoFromModel(r), Link: link, }) if err != nil { @@ -237,7 +246,7 @@ func (g *RPC) Activate(ctx context.Context, u *model.User, r *model.Repo, link s func (g *RPC) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { args, err := json.Marshal(&argumentsActivateDeactivate{ U: modelUserFromModel(u), - R: r, + R: modelRepoFromModel(r), Link: link, }) if err != nil { @@ -250,7 +259,7 @@ func (g *RPC) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link func (g *RPC) Branches(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) { args, err := json.Marshal(&argumentsBranchesPullRequests{ U: modelUserFromModel(u), - R: r, + R: modelRepoFromModel(r), P: p, }) if err != nil { @@ -268,7 +277,7 @@ func (g *RPC) Branches(ctx context.Context, u *model.User, r *model.Repo, p *mod func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (*model.Commit, error) { args, err := json.Marshal(&argumentsBranchHead{ U: modelUserFromModel(u), - R: r, + R: modelRepoFromModel(r), Branch: branch, }) if err != nil { @@ -286,7 +295,7 @@ func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, bran func (g *RPC) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) { args, err := json.Marshal(&argumentsBranchesPullRequests{ U: modelUserFromModel(u), - R: r, + R: modelRepoFromModel(r), P: p, }) if err != nil { @@ -326,7 +335,7 @@ func (g *RPC) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pi if err != nil { return nil, nil, err } - return resp.Repo, resp.Pipeline, nil + return resp.Repo.asModel(), resp.Pipeline, nil } func (g *RPC) OrgMembership(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error) { diff --git a/server/forge/hashicorp/server.go b/server/forge/hashicorp/server.go index 6a45e2af56..dfc0c56cda 100644 --- a/server/forge/hashicorp/server.go +++ b/server/forge/hashicorp/server.go @@ -24,7 +24,6 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/server/forge" "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" - "go.woodpecker-ci.org/woodpecker/v2/server/model" ) func Serve(impl forge.Forge) { @@ -55,12 +54,12 @@ func (s *RPCServer) URL(_ []byte, resp *string) error { } func (s *RPCServer) Teams(args []byte, resp *[]byte) error { - var a *model.User + var a *modelUser err := json.Unmarshal(args, a) if err != nil { return err } - teams, err := s.Impl.Teams(mkCtx(), a) + teams, err := s.Impl.Teams(mkCtx(), a.asModel()) if err != nil { return err } @@ -78,21 +77,25 @@ func (s *RPCServer) Repo(args []byte, resp *[]byte) error { if err != nil { return err } - *resp, err = json.Marshal(repos) + *resp, err = json.Marshal(modelRepoFromModel(repos)) return err } func (s *RPCServer) Repos(args []byte, resp *[]byte) error { - var a *model.User + var a *modelUser err := json.Unmarshal(args, a) if err != nil { return err } - repos, err := s.Impl.Repos(mkCtx(), a) + repos, err := s.Impl.Repos(mkCtx(), a.asModel()) if err != nil { return err } - *resp, err = json.Marshal(repos) + var modelRepos []*modelRepo + for _, repo := range repos { + modelRepos = append(modelRepos, modelRepoFromModel(repo)) + } + *resp, err = json.Marshal(modelRepos) return err } @@ -102,7 +105,7 @@ func (s *RPCServer) File(args []byte, resp *[]byte) error { if err != nil { return err } - *resp, err = s.Impl.File(mkCtx(), a.U.asModel(), a.R, a.B, a.F) + *resp, err = s.Impl.File(mkCtx(), a.U.asModel(), a.R.asModel(), a.B, a.F) return err } @@ -112,7 +115,7 @@ func (s *RPCServer) Dir(args []byte, resp *[]byte) error { if err != nil { return err } - meta, err := s.Impl.Dir(mkCtx(), a.U.asModel(), a.R, a.B, a.F) + meta, err := s.Impl.Dir(mkCtx(), a.U.asModel(), a.R.asModel(), a.B, a.F) if err != nil { return err } @@ -127,7 +130,7 @@ func (s *RPCServer) Status(args []byte, resp *[]byte) error { return err } *resp = []byte{} - return s.Impl.Status(mkCtx(), a.U.asModel(), a.R, a.B, a.P) + return s.Impl.Status(mkCtx(), a.U.asModel(), a.R.asModel(), a.B, a.P) } func (s *RPCServer) Netrc(args []byte, resp *[]byte) error { @@ -136,7 +139,7 @@ func (s *RPCServer) Netrc(args []byte, resp *[]byte) error { if err != nil { return err } - netrc, err := s.Impl.Netrc(a.U.asModel(), a.R) + netrc, err := s.Impl.Netrc(a.U.asModel(), a.R.asModel()) if err != nil { return err } @@ -151,7 +154,7 @@ func (s *RPCServer) Activate(args []byte, resp *[]byte) error { return err } *resp = []byte{} - return s.Impl.Activate(mkCtx(), a.U.asModel(), a.R, a.Link) + return s.Impl.Activate(mkCtx(), a.U.asModel(), a.R.asModel(), a.Link) } func (s *RPCServer) Deactivate(args []byte, resp *[]byte) error { @@ -161,7 +164,7 @@ func (s *RPCServer) Deactivate(args []byte, resp *[]byte) error { return err } *resp = []byte{} - return s.Impl.Deactivate(mkCtx(), a.U.asModel(), a.R, a.Link) + return s.Impl.Deactivate(mkCtx(), a.U.asModel(), a.R.asModel(), a.Link) } func (s *RPCServer) Branches(args []byte, resp *[]byte) error { @@ -170,7 +173,7 @@ func (s *RPCServer) Branches(args []byte, resp *[]byte) error { if err != nil { return err } - branches, err := s.Impl.Branches(mkCtx(), a.U.asModel(), a.R, a.P) + branches, err := s.Impl.Branches(mkCtx(), a.U.asModel(), a.R.asModel(), a.P) if err != nil { return err } @@ -184,7 +187,7 @@ func (s *RPCServer) BranchHead(args []byte, resp *[]byte) error { if err != nil { return err } - commit, err := s.Impl.BranchHead(mkCtx(), a.U.asModel(), a.R, a.Branch) + commit, err := s.Impl.BranchHead(mkCtx(), a.U.asModel(), a.R.asModel(), a.Branch) if err != nil { return err } @@ -198,7 +201,7 @@ func (s *RPCServer) PullRequests(args []byte, resp *[]byte) error { if err != nil { return err } - prs, err := s.Impl.PullRequests(mkCtx(), a.U.asModel(), a.R, a.P) + prs, err := s.Impl.PullRequests(mkCtx(), a.U.asModel(), a.R.asModel(), a.P) if err != nil { return err } @@ -251,7 +254,7 @@ func (s *RPCServer) Hook(args []byte, resp *[]byte) error { return err } *resp, err = json.Marshal(&responseHook{ - Repo: repo, + Repo: modelRepoFromModel(repo), Pipeline: pipeline, }) return err From d03814e667980573445efe64786814d2dad6fa87 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Tue, 13 Feb 2024 20:53:50 +0100 Subject: [PATCH 21/44] rename pkg --- cmd/server/setup.go | 4 ++-- server/forge/{hashicorp => addon}/args.go | 2 +- server/forge/{hashicorp => addon}/client.go | 2 +- server/forge/{hashicorp => addon}/plugin.go | 2 +- server/forge/{hashicorp => addon}/server.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) rename server/forge/{hashicorp => addon}/args.go (99%) rename server/forge/{hashicorp => addon}/client.go (99%) rename server/forge/{hashicorp => addon}/plugin.go (98%) rename server/forge/{hashicorp => addon}/server.go (99%) diff --git a/cmd/server/setup.go b/cmd/server/setup.go index dca2a06203..8bb5131de7 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -36,7 +36,7 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/server/forge/gitea" "go.woodpecker-ci.org/woodpecker/v2/server/forge/github" "go.woodpecker-ci.org/woodpecker/v2/server/forge/gitlab" - "go.woodpecker-ci.org/woodpecker/v2/server/forge/hashicorp" + "go.woodpecker-ci.org/woodpecker/v2/server/forge/addon" "go.woodpecker-ci.org/woodpecker/v2/server/queue" "go.woodpecker-ci.org/woodpecker/v2/server/store" "go.woodpecker-ci.org/woodpecker/v2/server/store/datastore" @@ -107,7 +107,7 @@ func setupMembershipService(_ *cli.Context, r forge.Forge) cache.MembershipServi func setupForge(c *cli.Context) (forge.Forge, error) { switch { case c.String("addons-forge") != "": - return hashicorp.Load(c.String("addons-forge")) + return addon.Load(c.String("addons-forge")) case c.Bool("github"): return setupGitHub(c) case c.Bool("gitlab"): diff --git a/server/forge/hashicorp/args.go b/server/forge/addon/args.go similarity index 99% rename from server/forge/hashicorp/args.go rename to server/forge/addon/args.go index baaaa7a048..bbbe915c6b 100644 --- a/server/forge/hashicorp/args.go +++ b/server/forge/addon/args.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package hashicorp +package addon import ( "go.woodpecker-ci.org/woodpecker/v2/server/model" diff --git a/server/forge/hashicorp/client.go b/server/forge/addon/client.go similarity index 99% rename from server/forge/hashicorp/client.go rename to server/forge/addon/client.go index ec9a0ad9c5..39872096ee 100644 --- a/server/forge/hashicorp/client.go +++ b/server/forge/addon/client.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package hashicorp +package addon import ( "context" diff --git a/server/forge/hashicorp/plugin.go b/server/forge/addon/plugin.go similarity index 98% rename from server/forge/hashicorp/plugin.go rename to server/forge/addon/plugin.go index ae0cd16f89..21099cf68d 100644 --- a/server/forge/hashicorp/plugin.go +++ b/server/forge/addon/plugin.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package hashicorp +package addon import ( "net/rpc" diff --git a/server/forge/hashicorp/server.go b/server/forge/addon/server.go similarity index 99% rename from server/forge/hashicorp/server.go rename to server/forge/addon/server.go index dfc0c56cda..a65967eaab 100644 --- a/server/forge/hashicorp/server.go +++ b/server/forge/addon/server.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package hashicorp +package addon import ( "bytes" From 14ab7feeb771ca45fd17bfc441f4d64f9839d9c8 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Tue, 13 Feb 2024 20:54:23 +0100 Subject: [PATCH 22/44] fix repo struct --- cmd/server/setup.go | 2 +- server/forge/addon/args.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 8bb5131de7..34f181f7d7 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -32,11 +32,11 @@ import ( "go.woodpecker-ci.org/woodpecker/v2/server" "go.woodpecker-ci.org/woodpecker/v2/server/cache" "go.woodpecker-ci.org/woodpecker/v2/server/forge" + "go.woodpecker-ci.org/woodpecker/v2/server/forge/addon" "go.woodpecker-ci.org/woodpecker/v2/server/forge/bitbucket" "go.woodpecker-ci.org/woodpecker/v2/server/forge/gitea" "go.woodpecker-ci.org/woodpecker/v2/server/forge/github" "go.woodpecker-ci.org/woodpecker/v2/server/forge/gitlab" - "go.woodpecker-ci.org/woodpecker/v2/server/forge/addon" "go.woodpecker-ci.org/woodpecker/v2/server/queue" "go.woodpecker-ci.org/woodpecker/v2/server/store" "go.woodpecker-ci.org/woodpecker/v2/server/store/datastore" diff --git a/server/forge/addon/args.go b/server/forge/addon/args.go index bbbe915c6b..038e8b0e04 100644 --- a/server/forge/addon/args.go +++ b/server/forge/addon/args.go @@ -129,12 +129,12 @@ func modelUserFromModel(u *model.User) *modelUser { } } -// modelUser is an extension of model.User to marshal all fields to JSON +// modelRepo is an extension of model.Repo to marshal all fields to JSON type modelRepo struct { Repo *model.Repo `json:"repo"` - UserID int64 `json:"-"` - Hash string `json:"-"` - Perm *model.Perm `json:"-"` + UserID int64 `json:"user_id"` + Hash string `json:"hash"` + Perm *model.Perm `json:"perm"` } func (m *modelRepo) asModel() *model.Repo { From 5b7bd63fe9a6b3a035cc04d9c594eeae1e7d84b4 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 17 Feb 2024 20:06:41 +0100 Subject: [PATCH 23/44] return error on failed type --- server/forge/addon/client.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/forge/addon/client.go b/server/forge/addon/client.go index 39872096ee..11b7713c8d 100644 --- a/server/forge/addon/client.go +++ b/server/forge/addon/client.go @@ -17,6 +17,7 @@ package addon import ( "context" "encoding/json" + "fmt" "io" "net/http" "net/rpc" @@ -52,7 +53,10 @@ func Load(file string) (forge.Forge, error) { return nil, err } - extension, _ := raw.(forge.Forge) + extension, ok := raw.(forge.Forge) + if !ok { + return nil, fmt.Errorf("addon forge does not implement forge interface") + } return extension, nil } From 8fb3f3c2374d775a6ec9c5b454746af0b85d7dfd Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 17 Feb 2024 20:50:04 +0100 Subject: [PATCH 24/44] Add addon logger --- server/forge/addon/client.go | 4 + server/forge/addon/logger.go | 167 +++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 server/forge/addon/logger.go diff --git a/server/forge/addon/client.go b/server/forge/addon/client.go index 11b7713c8d..669f843fec 100644 --- a/server/forge/addon/client.go +++ b/server/forge/addon/client.go @@ -24,6 +24,7 @@ import ( "os/exec" "github.com/hashicorp/go-plugin" + "github.com/rs/zerolog/log" "go.woodpecker-ci.org/woodpecker/v2/server/forge" "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" @@ -40,6 +41,9 @@ func Load(file string) (forge.Forge, error) { pluginKey: &Plugin{}, }, Cmd: exec.Command(file), + Logger: clientLogger{ + logger: log.With().Str("addon", file).Logger(), + }, }) // TODO defer client.Kill() diff --git a/server/forge/addon/logger.go b/server/forge/addon/logger.go new file mode 100644 index 0000000000..677141d512 --- /dev/null +++ b/server/forge/addon/logger.go @@ -0,0 +1,167 @@ +// Copyright 2024 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 addon + +import ( + "bytes" + "io" + stdlog "log" + + "github.com/hashicorp/go-hclog" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +type clientLogger struct { + logger zerolog.Logger + name string + withArgs []any +} + +func convertLvl(level hclog.Level) zerolog.Level { + switch level { + case hclog.Error: + return zerolog.ErrorLevel + case hclog.Warn: + return zerolog.WarnLevel + case hclog.Info: + return zerolog.InfoLevel + case hclog.Debug: + return zerolog.DebugLevel + case hclog.Trace: + return zerolog.TraceLevel + } + return zerolog.NoLevel +} + +func (c clientLogger) applyArgs(args []any) *zerolog.Logger { + var key string + logger := c.logger.With() + args = append(args, c.withArgs) + for i, arg := range args { + if key != "" { + logger.Any(key, arg) + key = "" + } else if i == len(args)-1 { + logger.Any(hclog.MissingKey, arg) + } else { + key, _ = arg.(string) + } + } + l := logger.Logger() + return &l +} + +func (c clientLogger) Log(level hclog.Level, msg string, args ...any) { + c.applyArgs(args).WithLevel(convertLvl(level)).Msgf(msg, args) +} + +func (c clientLogger) Trace(msg string, args ...any) { + c.applyArgs(args).Trace().Msgf(msg, args) +} + +func (c clientLogger) Debug(msg string, args ...any) { + c.applyArgs(args).Debug().Msgf(msg, args) +} + +func (c clientLogger) Info(msg string, args ...any) { + c.applyArgs(args).Info().Msgf(msg, args) +} + +func (c clientLogger) Warn(msg string, args ...any) { + c.applyArgs(args).Warn().Msgf(msg, args) +} + +func (c clientLogger) Error(msg string, args ...any) { + c.applyArgs(args).Error().Msgf(msg, args) +} + +func (c clientLogger) IsTrace() bool { + return log.Logger.GetLevel() >= zerolog.TraceLevel +} + +func (c clientLogger) IsDebug() bool { + return log.Logger.GetLevel() >= zerolog.DebugLevel +} + +func (c clientLogger) IsInfo() bool { + return log.Logger.GetLevel() >= zerolog.InfoLevel +} + +func (c clientLogger) IsWarn() bool { + return log.Logger.GetLevel() >= zerolog.WarnLevel +} + +func (c clientLogger) IsError() bool { + return log.Logger.GetLevel() >= zerolog.ErrorLevel +} + +func (c clientLogger) ImpliedArgs() []any { + return c.withArgs +} + +func (c clientLogger) With(args ...any) hclog.Logger { + return &clientLogger{ + logger: c.logger, + name: c.name, + withArgs: args, + } +} + +func (c clientLogger) Name() string { + return c.name +} + +func (c clientLogger) Named(name string) hclog.Logger { + curr := c.name + if curr != "" { + curr = c.name + "." + } + return clientLogger{ + logger: c.logger, + name: curr + name, + withArgs: c.withArgs, + } +} + +func (c clientLogger) ResetNamed(name string) hclog.Logger { + return clientLogger{ + logger: c.logger, + name: name, + withArgs: c.withArgs, + } +} + +func (c clientLogger) SetLevel(level hclog.Level) { + c.logger = c.logger.Level(convertLvl(level)) +} + +func (c clientLogger) StandardLogger(opts *hclog.StandardLoggerOptions) *stdlog.Logger { + return stdlog.New(c.StandardWriter(opts), "", 0) +} + +func (c clientLogger) StandardWriter(*hclog.StandardLoggerOptions) io.Writer { + return ioAdapter{logger: c.logger} +} + +type ioAdapter struct { + logger zerolog.Logger +} + +func (i ioAdapter) Write(p []byte) (n int, err error) { + str := string(bytes.TrimRight(p, " \t\n")) + i.logger.Log().Msg(str) + return len(p), nil +} From 1a9fcbe5a42bb2f80f67bd56c0a4360a5edd8c2a Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 17 Feb 2024 20:54:59 +0100 Subject: [PATCH 25/44] Revert "return error on failed type" This reverts commit 5b7bd63fe9a6b3a035cc04d9c594eeae1e7d84b4. --- server/forge/addon/client.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/server/forge/addon/client.go b/server/forge/addon/client.go index 669f843fec..1671f8f3d5 100644 --- a/server/forge/addon/client.go +++ b/server/forge/addon/client.go @@ -17,7 +17,6 @@ package addon import ( "context" "encoding/json" - "fmt" "io" "net/http" "net/rpc" @@ -57,10 +56,7 @@ func Load(file string) (forge.Forge, error) { return nil, err } - extension, ok := raw.(forge.Forge) - if !ok { - return nil, fmt.Errorf("addon forge does not implement forge interface") - } + extension, _ := raw.(forge.Forge) return extension, nil } From 25265756aefc2550eb598deba337ce1afd66a380 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 17 Feb 2024 21:09:27 +0100 Subject: [PATCH 26/44] Update addon docs --- .../30-administration/10-server-config.md | 12 +-- .../30-administration/11-forges/100-addon.md | 63 ++++++++++++ .../75-addons/00-overview.md | 40 -------- .../75-addons/20-creating-addons.md | 97 ------------------- .../75-addons/_category_.yaml | 6 -- 5 files changed, 68 insertions(+), 150 deletions(-) create mode 100644 docs/docs/30-administration/11-forges/100-addon.md delete mode 100644 docs/docs/30-administration/75-addons/00-overview.md delete mode 100644 docs/docs/30-administration/75-addons/20-creating-addons.md delete mode 100644 docs/docs/30-administration/75-addons/_category_.yaml diff --git a/docs/docs/30-administration/10-server-config.md b/docs/docs/30-administration/10-server-config.md index 7d38c75a2d..b370302ad5 100644 --- a/docs/docs/30-administration/10-server-config.md +++ b/docs/docs/30-administration/10-server-config.md @@ -497,12 +497,6 @@ Supported variables: - `owner`: the repo's owner - `repo`: the repo's name -### `WOODPECKER_ADDONS` - -> Default: empty - -List of addon files. See [addons](./75-addons/00-overview.md). - --- ### `WOODPECKER_LIMIT_MEM_SWAP` @@ -583,4 +577,8 @@ See [Bitbucket configuration](./11-forges/50-bitbucket.md#configuration) ### `WOODPECKER_GITLAB_...` -See [Gitlab configuration](./11-forges/40-gitlab.md#configuration) +See [GitLab configuration](./11-forges/40-gitlab.md#configuration) + +### `WOODPECKER_ADDON_FORGE` + +See [addon forges](./11-forges/100-addon.md). diff --git a/docs/docs/30-administration/11-forges/100-addon.md b/docs/docs/30-administration/11-forges/100-addon.md new file mode 100644 index 0000000000..fc9c7f8db4 --- /dev/null +++ b/docs/docs/30-administration/11-forges/100-addon.md @@ -0,0 +1,63 @@ +# Addon forges + + +:::warning +Addon forges are still experimental. Their implementation can change and break at any time. +::: + +:::danger +You need to trust the author of the addon forge you use. It can access authentication codes and other possibly sensitive information. +::: + +## Usage + +To use an addon forge, download the correct addon version. Then, you can add the following to your configuration: + +```ini +WOODPECKER_ADDON_FORGE=/path/to/your/addon/forge/file.so +``` + +In case you run Woodpecker as container, you probably want to mount the addon binary to `/opt/addons/`. + +Using an addon forge always overwrites Woodpecker's internal forge configuration. + +### Bug reports + +If you experience bugs, please check which component has the issue. If it's the addon, **do not raise an issue in the main repository**, but rather use the separate addon repositories. To check which component is responsible for the bug, look at the logs. Logs from addons are marked with a special field `addon` containing their addon file name. + +## Creating addon forges + +Addons use RPC to communicate to the server and are implemented using the [`go-plugin` library](https://github.com/hashicorp/go-plugin). + +### Writing your code + +This example will use the Go language. + +Directly import Woodpecker's Go packages (`go.woodpecker-ci.org/woodpecker/woodpecker/v2`) and use the interfaces and types defined there. + +In the `main` function, just call `"go.woodpecker-ci.org/woodpecker/v2/server/forge/addon".Serve` with a `"go.woodpecker-ci.org/woodpecker/v2/server/forge".Forge` as argument. +This will take care of connecting the addon forge to the server. + +### Example structure + +```go +package main + +import ( + "context" + "net/http" + + "go.woodpecker-ci.org/woodpecker/v2/server/forge/addon" + forgeTypes "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" + "go.woodpecker-ci.org/woodpecker/v2/server/model" +) + +func main() { + addon.Serve(config{}) +} + +type config struct { +} + +// `config` must implement `"go.woodpecker-ci.org/woodpecker/v2/server/forge".Forge`. You must directly use Woodpecker's packages - see imports above. +``` diff --git a/docs/docs/30-administration/75-addons/00-overview.md b/docs/docs/30-administration/75-addons/00-overview.md deleted file mode 100644 index 747dc4b366..0000000000 --- a/docs/docs/30-administration/75-addons/00-overview.md +++ /dev/null @@ -1,40 +0,0 @@ -# Addons - -:::warning -Addons are still experimental. Their implementation can change and break at any time. -::: - -:::danger -You need to trust the author of the addons you use. Depending on their type, addons can access forge authentication codes, your secrets or other sensitive information. -::: - -To adapt Woodpecker to your needs beyond the [configuration](../10-server-config.md), Woodpecker has its own **addon** system, built ontop of [Go's internal plugin system](https://go.dev/pkg/plugin). - -Addons can be used for: - -- Forges - -## Restrictions - -Addons are restricted by how Go plugins work. This includes the following restrictions: - -- only supported on Linux, FreeBSD, and macOS -- addons must have been built for the correct Woodpecker version. If an addon is not provided specifically for this version, you likely won't be able to use it. - -## Usage - -To use an addon, download the addon version built for your Woodpecker version. Then, you can add the following to your configuration: - -```ini -WOODPECKER_ADDONS=/path/to/your/addon/file.so -``` - -In case you run Woodpecker as container, you probably want to mount the addon binaries to `/opt/addons/`. - -You can list multiple addons, Woodpecker will automatically determine their type. If you specify multiple addons with the same type, only the first one will be used. - -Using an addon always overwrites Woodpecker's internal setup. This means, that a forge addon will be used if specified, no matter what's configured for the forges natively supported by Woodpecker. - -### Bug reports - -If you experience bugs, please check which component has the issue. If it's the addon, **do not raise an issue in the main repository**, but rather use the separate addon repositories. To check which component is responsible for the bug, look at the logs. Logs from addons are marked with a special field `addon` containing their addon file name. diff --git a/docs/docs/30-administration/75-addons/20-creating-addons.md b/docs/docs/30-administration/75-addons/20-creating-addons.md deleted file mode 100644 index 283c456f45..0000000000 --- a/docs/docs/30-administration/75-addons/20-creating-addons.md +++ /dev/null @@ -1,97 +0,0 @@ -# Creating addons - -Addons are written in Go. - -## Writing your code - -An addon consists of two variables/functions in Go. - -1. The `Type` variable. Specifies the type of the addon and must be directly accessed from `shared/addons/types/types.go`. -2. The `Addon` function which is the main point of your addon. - This function takes the `zerolog` logger you should use to log errors, warnings, etc. as argument. - - It returns two values: - - 1. The actual addon. For type reference see [table below](#return-types). - 2. An error. If this error is not `nil`, Woodpecker exits. - -Directly import Woodpecker's Go package (`go.woodpecker-ci.org/woodpecker/woodpecker/v2`) and use the interfaces and types defined there. - -### Return types - -| Addon type | Return type | -| ---------- | -------------------------------------------------------------------- | -| `Forge` | `"go.woodpecker-ci.org/woodpecker/woodpecker/v2/server/forge".Forge` | - -### Using configurations - -If you write a plugin for the server (`Forge` and the services), you can access the server config. - -Therefore, use the `"go.woodpecker-ci.org/woodpecker/v2/server".Config` variable. - -:::warning -The config is not available when your addon is initialized, i.e., the `Addon` function is called. -Only use the config in the interface methods. -::: - -## Compiling - -After you write your addon code, compile your addon: - -```sh -go build -buildmode plugin -``` - -The output file is your addon that is now ready to be used. - -## Restrictions - -Addons must directly depend on Woodpecker's core (`go.woodpecker-ci.org/woodpecker/woodpecker/v2`). -The addon must have been built with **exactly the same code** as the Woodpecker instance you'd like to use it on. This means: If you build your addon with a specific commit from Woodpecker `next`, you can likely only use it with the Woodpecker version compiled from this commit. -Also, if you change something inside Woodpecker without committing, it might fail because you need to recompile your addon with this code first. - -In addition to this, addons are only supported on Linux, FreeBSD, and macOS. - -:::info -It is recommended to at least support the latest version of Woodpecker. -::: - -### Compile for different versions - -As long as there are no changes to Woodpecker's interfaces, -or they are backwards-compatible, you can compile the addon for multiple versions -by changing the version of `go.woodpecker-ci.org/woodpecker/woodpecker/v2` using `go get` before compiling. - -## Logging - -The entrypoint receives a `zerolog.Logger` as input. **Do not use any other logging solution.** This logger follows the configuration of the Woodpecker instance and adds a special field `addon` to the log entries which allows users to find out which component is writing the log messages. - -## Example structure - -```go -package main - -import ( - "context" - "net/http" - - "github.com/rs/zerolog" - "go.woodpecker-ci.org/woodpecker/v2/server/forge" - forge_types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" - "go.woodpecker-ci.org/woodpecker/v2/server/model" - addon_types "go.woodpecker-ci.org/woodpecker/v2/shared/addon/types" -) - -var Type = addon_types.TypeForge - -func Addon(logger zerolog.Logger) (forge.Forge, error) { - logger.Info().Msg("hello world from addon") - return &config{l: logger}, nil -} - -type config struct { - l zerolog.Logger -} - -// In this case, `config` must implement `forge.Forge`. You must directly use Woodpecker's packages - see imports above. -``` diff --git a/docs/docs/30-administration/75-addons/_category_.yaml b/docs/docs/30-administration/75-addons/_category_.yaml deleted file mode 100644 index 4cd7380c57..0000000000 --- a/docs/docs/30-administration/75-addons/_category_.yaml +++ /dev/null @@ -1,6 +0,0 @@ -label: 'Addons' -collapsible: true -collapsed: true -link: - type: 'doc' - id: 'overview' From 1aeb25f4b44cef770ec00ac26023db5811859b25 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 17 Feb 2024 21:12:49 +0100 Subject: [PATCH 27/44] Update docs --- docs/docs/30-administration/11-forges/100-addon.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/docs/30-administration/11-forges/100-addon.md b/docs/docs/30-administration/11-forges/100-addon.md index fc9c7f8db4..99f4d50eb4 100644 --- a/docs/docs/30-administration/11-forges/100-addon.md +++ b/docs/docs/30-administration/11-forges/100-addon.md @@ -1,5 +1,6 @@ # Addon forges +If the forge you're using does not comply with [Woodpecker's requirements](TODO) or your setup is too specific to be added to Woodpecker's core, you can write your own forge using an addon forge. :::warning Addon forges are still experimental. Their implementation can change and break at any time. @@ -25,6 +26,12 @@ Using an addon forge always overwrites Woodpecker's internal forge configuration If you experience bugs, please check which component has the issue. If it's the addon, **do not raise an issue in the main repository**, but rather use the separate addon repositories. To check which component is responsible for the bug, look at the logs. Logs from addons are marked with a special field `addon` containing their addon file name. +## List of addon forges + +If you wrote or found an addon forge, please add it here so others can find it! + +- [Radicle](TODO) + ## Creating addon forges Addons use RPC to communicate to the server and are implemented using the [`go-plugin` library](https://github.com/hashicorp/go-plugin). From 490289336399630f645fb9ef93dcbe632cbbc531 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 17 Feb 2024 21:17:01 +0100 Subject: [PATCH 28/44] fix lint --- server/forge/addon/client.go | 34 +++++++++--------- server/forge/addon/logger.go | 68 +++++++++++++++++------------------- 2 files changed, 50 insertions(+), 52 deletions(-) diff --git a/server/forge/addon/client.go b/server/forge/addon/client.go index 1671f8f3d5..323b0e8ab8 100644 --- a/server/forge/addon/client.go +++ b/server/forge/addon/client.go @@ -40,7 +40,7 @@ func Load(file string) (forge.Forge, error) { pluginKey: &Plugin{}, }, Cmd: exec.Command(file), - Logger: clientLogger{ + Logger: &clientLogger{ logger: log.With().Str("addon", file).Logger(), }, }) @@ -76,7 +76,7 @@ func (g *RPC) URL() string { return resp } -func (g *RPC) Login(ctx context.Context, r *types.OAuthRequest) (*model.User, string, error) { +func (g *RPC) Login(_ context.Context, r *types.OAuthRequest) (*model.User, string, error) { args, err := json.Marshal(r) if err != nil { return nil, "", err @@ -96,7 +96,7 @@ func (g *RPC) Login(ctx context.Context, r *types.OAuthRequest) (*model.User, st return resp.User.asModel(), resp.RedirectURL, nil } -func (g *RPC) Auth(ctx context.Context, token, secret string) (string, error) { +func (g *RPC) Auth(_ context.Context, token, secret string) (string, error) { args, err := json.Marshal(&argumentsAuth{ Token: token, Secret: secret, @@ -108,7 +108,7 @@ func (g *RPC) Auth(ctx context.Context, token, secret string) (string, error) { return resp, g.client.Call("Plugin.Auth", args, &resp) } -func (g *RPC) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) { +func (g *RPC) Teams(_ context.Context, u *model.User) ([]*model.Team, error) { args, err := json.Marshal(modelUserFromModel(u)) if err != nil { return nil, err @@ -123,7 +123,7 @@ func (g *RPC) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) { return resp, json.Unmarshal(jsonResp, &resp) } -func (g *RPC) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRemoteID, owner, name string) (*model.Repo, error) { +func (g *RPC) Repo(_ context.Context, u *model.User, remoteID model.ForgeRemoteID, owner, name string) (*model.Repo, error) { args, err := json.Marshal(&argumentsRepo{ U: modelUserFromModel(u), RemoteID: remoteID, @@ -147,7 +147,7 @@ func (g *RPC) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRemot return resp.asModel(), nil } -func (g *RPC) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) { +func (g *RPC) Repos(_ context.Context, u *model.User) ([]*model.Repo, error) { args, err := json.Marshal(modelUserFromModel(u)) if err != nil { return nil, err @@ -170,7 +170,7 @@ func (g *RPC) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) { return modelRepos, nil } -func (g *RPC) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { +func (g *RPC) File(_ context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { args, err := json.Marshal(&argumentsFileDir{ U: modelUserFromModel(u), R: modelRepoFromModel(r), @@ -184,7 +184,7 @@ func (g *RPC) File(ctx context.Context, u *model.User, r *model.Repo, b *model.P return resp, g.client.Call("Plugin.File", args, &resp) } -func (g *RPC) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*types.FileMeta, error) { +func (g *RPC) Dir(_ context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*types.FileMeta, error) { args, err := json.Marshal(&argumentsFileDir{ U: modelUserFromModel(u), R: modelRepoFromModel(r), @@ -203,7 +203,7 @@ func (g *RPC) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pi return resp, json.Unmarshal(jsonResp, &resp) } -func (g *RPC) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Workflow) error { +func (g *RPC) Status(_ context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Workflow) error { args, err := json.Marshal(&argumentsStatus{ U: modelUserFromModel(u), R: modelRepoFromModel(r), @@ -234,7 +234,7 @@ func (g *RPC) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { return resp, json.Unmarshal(jsonResp, &resp) } -func (g *RPC) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error { +func (g *RPC) Activate(_ context.Context, u *model.User, r *model.Repo, link string) error { args, err := json.Marshal(&argumentsActivateDeactivate{ U: modelUserFromModel(u), R: modelRepoFromModel(r), @@ -247,7 +247,7 @@ func (g *RPC) Activate(ctx context.Context, u *model.User, r *model.Repo, link s return g.client.Call("Plugin.Activate", args, &jsonResp) } -func (g *RPC) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { +func (g *RPC) Deactivate(_ context.Context, u *model.User, r *model.Repo, link string) error { args, err := json.Marshal(&argumentsActivateDeactivate{ U: modelUserFromModel(u), R: modelRepoFromModel(r), @@ -260,7 +260,7 @@ func (g *RPC) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link return g.client.Call("Plugin.Deactivate", args, &jsonResp) } -func (g *RPC) Branches(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) { +func (g *RPC) Branches(_ context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) { args, err := json.Marshal(&argumentsBranchesPullRequests{ U: modelUserFromModel(u), R: modelRepoFromModel(r), @@ -278,7 +278,7 @@ func (g *RPC) Branches(ctx context.Context, u *model.User, r *model.Repo, p *mod return resp, json.Unmarshal(jsonResp, &resp) } -func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (*model.Commit, error) { +func (g *RPC) BranchHead(_ context.Context, u *model.User, r *model.Repo, branch string) (*model.Commit, error) { args, err := json.Marshal(&argumentsBranchHead{ U: modelUserFromModel(u), R: modelRepoFromModel(r), @@ -296,7 +296,7 @@ func (g *RPC) BranchHead(ctx context.Context, u *model.User, r *model.Repo, bran return resp, json.Unmarshal(jsonResp, &resp) } -func (g *RPC) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) { +func (g *RPC) PullRequests(_ context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) { args, err := json.Marshal(&argumentsBranchesPullRequests{ U: modelUserFromModel(u), R: modelRepoFromModel(r), @@ -314,7 +314,7 @@ func (g *RPC) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p return resp, json.Unmarshal(jsonResp, &resp) } -func (g *RPC) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { +func (g *RPC) Hook(_ context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { body, err := io.ReadAll(r.Body) if err != nil { return nil, nil, err @@ -342,7 +342,7 @@ func (g *RPC) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pi return resp.Repo.asModel(), resp.Pipeline, nil } -func (g *RPC) OrgMembership(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error) { +func (g *RPC) OrgMembership(_ context.Context, u *model.User, org string) (*model.OrgPerm, error) { args, err := json.Marshal(&argumentsOrgMembershipOrg{ U: modelUserFromModel(u), Org: org, @@ -359,7 +359,7 @@ func (g *RPC) OrgMembership(ctx context.Context, u *model.User, org string) (*mo return resp, json.Unmarshal(jsonResp, &resp) } -func (g *RPC) Org(ctx context.Context, u *model.User, org string) (*model.Org, error) { +func (g *RPC) Org(_ context.Context, u *model.User, org string) (*model.Org, error) { args, err := json.Marshal(&argumentsOrgMembershipOrg{ U: modelUserFromModel(u), Org: org, diff --git a/server/forge/addon/logger.go b/server/forge/addon/logger.go index 677141d512..84ebd71b95 100644 --- a/server/forge/addon/logger.go +++ b/server/forge/addon/logger.go @@ -46,17 +46,19 @@ func convertLvl(level hclog.Level) zerolog.Level { return zerolog.NoLevel } -func (c clientLogger) applyArgs(args []any) *zerolog.Logger { +func (c *clientLogger) applyArgs(args []any) *zerolog.Logger { var key string logger := c.logger.With() args = append(args, c.withArgs) for i, arg := range args { - if key != "" { + switch { + case key != "": logger.Any(key, arg) key = "" - } else if i == len(args)-1 { + case i == len(args)-1: logger.Any(hclog.MissingKey, arg) - } else { + default: + key, _ = arg.(string) } } @@ -64,55 +66,55 @@ func (c clientLogger) applyArgs(args []any) *zerolog.Logger { return &l } -func (c clientLogger) Log(level hclog.Level, msg string, args ...any) { - c.applyArgs(args).WithLevel(convertLvl(level)).Msgf(msg, args) +func (c *clientLogger) Log(level hclog.Level, msg string, args ...any) { + c.applyArgs(args).WithLevel(convertLvl(level)).Msg(msg) } -func (c clientLogger) Trace(msg string, args ...any) { - c.applyArgs(args).Trace().Msgf(msg, args) +func (c *clientLogger) Trace(msg string, args ...any) { + c.applyArgs(args).Trace().Msg(msg) } -func (c clientLogger) Debug(msg string, args ...any) { - c.applyArgs(args).Debug().Msgf(msg, args) +func (c *clientLogger) Debug(msg string, args ...any) { + c.applyArgs(args).Debug().Msg(msg) } -func (c clientLogger) Info(msg string, args ...any) { - c.applyArgs(args).Info().Msgf(msg, args) +func (c *clientLogger) Info(msg string, args ...any) { + c.applyArgs(args).Info().Msg(msg) } -func (c clientLogger) Warn(msg string, args ...any) { - c.applyArgs(args).Warn().Msgf(msg, args) +func (c *clientLogger) Warn(msg string, args ...any) { + c.applyArgs(args).Warn().Msg(msg) } -func (c clientLogger) Error(msg string, args ...any) { - c.applyArgs(args).Error().Msgf(msg, args) +func (c *clientLogger) Error(msg string, args ...any) { + c.applyArgs(args).Error().Msg(msg) } -func (c clientLogger) IsTrace() bool { +func (c *clientLogger) IsTrace() bool { return log.Logger.GetLevel() >= zerolog.TraceLevel } -func (c clientLogger) IsDebug() bool { +func (c *clientLogger) IsDebug() bool { return log.Logger.GetLevel() >= zerolog.DebugLevel } -func (c clientLogger) IsInfo() bool { +func (c *clientLogger) IsInfo() bool { return log.Logger.GetLevel() >= zerolog.InfoLevel } -func (c clientLogger) IsWarn() bool { +func (c *clientLogger) IsWarn() bool { return log.Logger.GetLevel() >= zerolog.WarnLevel } -func (c clientLogger) IsError() bool { +func (c *clientLogger) IsError() bool { return log.Logger.GetLevel() >= zerolog.ErrorLevel } -func (c clientLogger) ImpliedArgs() []any { +func (c *clientLogger) ImpliedArgs() []any { return c.withArgs } -func (c clientLogger) With(args ...any) hclog.Logger { +func (c *clientLogger) With(args ...any) hclog.Logger { return &clientLogger{ logger: c.logger, name: c.name, @@ -120,39 +122,35 @@ func (c clientLogger) With(args ...any) hclog.Logger { } } -func (c clientLogger) Name() string { +func (c *clientLogger) Name() string { return c.name } -func (c clientLogger) Named(name string) hclog.Logger { +func (c *clientLogger) Named(name string) hclog.Logger { curr := c.name if curr != "" { curr = c.name + "." } - return clientLogger{ - logger: c.logger, - name: curr + name, - withArgs: c.withArgs, - } + return c.ResetNamed(curr + name) } -func (c clientLogger) ResetNamed(name string) hclog.Logger { - return clientLogger{ +func (c *clientLogger) ResetNamed(name string) hclog.Logger { + return &clientLogger{ logger: c.logger, name: name, withArgs: c.withArgs, } } -func (c clientLogger) SetLevel(level hclog.Level) { +func (c *clientLogger) SetLevel(level hclog.Level) { c.logger = c.logger.Level(convertLvl(level)) } -func (c clientLogger) StandardLogger(opts *hclog.StandardLoggerOptions) *stdlog.Logger { +func (c *clientLogger) StandardLogger(opts *hclog.StandardLoggerOptions) *stdlog.Logger { return stdlog.New(c.StandardWriter(opts), "", 0) } -func (c clientLogger) StandardWriter(*hclog.StandardLoggerOptions) io.Writer { +func (c *clientLogger) StandardWriter(*hclog.StandardLoggerOptions) io.Writer { return ioAdapter{logger: c.logger} } From cfacb1c2b1e050f9b92dfad7df1418909ab06e8a Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 18 Feb 2024 07:51:55 +0100 Subject: [PATCH 29/44] update link --- docs/docs/30-administration/11-forges/100-addon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/30-administration/11-forges/100-addon.md b/docs/docs/30-administration/11-forges/100-addon.md index 99f4d50eb4..bf1f39de55 100644 --- a/docs/docs/30-administration/11-forges/100-addon.md +++ b/docs/docs/30-administration/11-forges/100-addon.md @@ -30,7 +30,7 @@ If you experience bugs, please check which component has the issue. If it's the If you wrote or found an addon forge, please add it here so others can find it! -- [Radicle](TODO) +- Radicle ## Creating addon forges From b3d1fc16c027e4887a33880b953ccbacdd57c5ac Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 18 Feb 2024 06:52:54 +0000 Subject: [PATCH 30/44] [pre-commit.ci] auto fixes from pre-commit.com hooks [CI SKIP] for more information, see https://pre-commit.ci --- docs/docs/30-administration/11-forges/100-addon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/30-administration/11-forges/100-addon.md b/docs/docs/30-administration/11-forges/100-addon.md index bf1f39de55..c9a51dee7f 100644 --- a/docs/docs/30-administration/11-forges/100-addon.md +++ b/docs/docs/30-administration/11-forges/100-addon.md @@ -53,7 +53,7 @@ package main import ( "context" "net/http" - + "go.woodpecker-ci.org/woodpecker/v2/server/forge/addon" forgeTypes "go.woodpecker-ci.org/woodpecker/v2/server/forge/types" "go.woodpecker-ci.org/woodpecker/v2/server/model" From 70e2845d4a9a451bfc41b2183ba97bd3513c20b7 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 18 Feb 2024 08:00:44 +0100 Subject: [PATCH 31/44] update docs --- docs/docs/30-administration/11-forges/100-addon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/30-administration/11-forges/100-addon.md b/docs/docs/30-administration/11-forges/100-addon.md index c9a51dee7f..43a8b953d1 100644 --- a/docs/docs/30-administration/11-forges/100-addon.md +++ b/docs/docs/30-administration/11-forges/100-addon.md @@ -15,7 +15,7 @@ You need to trust the author of the addon forge you use. It can access authentic To use an addon forge, download the correct addon version. Then, you can add the following to your configuration: ```ini -WOODPECKER_ADDON_FORGE=/path/to/your/addon/forge/file.so +WOODPECKER_ADDON_FORGE=/path/to/your/addon/forge/file ``` In case you run Woodpecker as container, you probably want to mount the addon binary to `/opt/addons/`. From b56a859353a440448d53cad2667c097ad08187c3 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 18 Feb 2024 12:24:57 +0100 Subject: [PATCH 32/44] update link --- docs/docs/30-administration/11-forges/100-addon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/30-administration/11-forges/100-addon.md b/docs/docs/30-administration/11-forges/100-addon.md index 43a8b953d1..8b911b148f 100644 --- a/docs/docs/30-administration/11-forges/100-addon.md +++ b/docs/docs/30-administration/11-forges/100-addon.md @@ -1,6 +1,6 @@ # Addon forges -If the forge you're using does not comply with [Woodpecker's requirements](TODO) or your setup is too specific to be added to Woodpecker's core, you can write your own forge using an addon forge. +If the forge you're using does not comply with [Woodpecker's requirements](../../92-development/02-core-ideas.md#forge) or your setup is too specific to be added to Woodpecker's core, you can write your own forge using an addon forge. :::warning Addon forges are still experimental. Their implementation can change and break at any time. From 4c6e185c6078b836f0c13d1035e1c8f721ebd20c Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Mon, 19 Feb 2024 10:13:45 +0100 Subject: [PATCH 33/44] fix link --- docs/docs/92-development/02-core-ideas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/92-development/02-core-ideas.md b/docs/docs/92-development/02-core-ideas.md index c4527e6c72..8e0d6e292a 100644 --- a/docs/docs/92-development/02-core-ideas.md +++ b/docs/docs/92-development/02-core-ideas.md @@ -8,7 +8,7 @@ ## Addons and extensions If you are wondering whether your contribution will be accepted to be merged in the Woodpecker core, or whether it's better to write an -[addon](../30-administration/75-addons/00-overview.md), [extension](../30-administration/100-external-configuration-api.md) or an +[addon forge](../30-administration/11-forges/100-addon.md), [extension](../30-administration/100-external-configuration-api.md) or an [external custom backend](../30-administration/22-backends/50-custom-backends.md), please check these points: - Is your change very specific to your setup and unlikely to be used by anyone else? From 7dc291248a6ea43c93ac0b4801f520edef292866 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Mon, 19 Feb 2024 10:20:14 +0100 Subject: [PATCH 34/44] update swagger --- cmd/server/docs/docs.go | 80 ++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 6c1d65c4ee..7c9fc5ed36 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -3922,7 +3922,7 @@ const docTemplate = `{ "errors": { "type": "array", "items": { - "$ref": "#/definitions/errors.PipelineError" + "$ref": "#/definitions/types.PipelineError" } }, "event": { @@ -4402,45 +4402,6 @@ const docTemplate = `{ "EventManual" ] }, - "errors.PipelineError": { - "type": "object", - "properties": { - "data": {}, - "is_warning": { - "type": "boolean" - }, - "message": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/errors.PipelineErrorType" - } - } - }, - "errors.PipelineErrorType": { - "type": "string", - "enum": [ - "linter", - "deprecation", - "compiler", - "generic", - "bad_habit" - ], - "x-enum-comments": { - "PipelineErrorTypeBadHabit": "some bad-habit error", - "PipelineErrorTypeCompiler": "some error with the config semantics", - "PipelineErrorTypeDeprecation": "using some deprecated feature", - "PipelineErrorTypeGeneric": "some generic error", - "PipelineErrorTypeLinter": "some error with the config syntax" - }, - "x-enum-varnames": [ - "PipelineErrorTypeLinter", - "PipelineErrorTypeDeprecation", - "PipelineErrorTypeCompiler", - "PipelineErrorTypeGeneric", - "PipelineErrorTypeBadHabit" - ] - }, "model.Workflow": { "type": "object", "properties": { @@ -4487,6 +4448,45 @@ const docTemplate = `{ "$ref": "#/definitions/StatusValue" } } + }, + "types.PipelineError": { + "type": "object", + "properties": { + "data": {}, + "is_warning": { + "type": "boolean" + }, + "message": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/types.PipelineErrorType" + } + } + }, + "types.PipelineErrorType": { + "type": "string", + "enum": [ + "linter", + "deprecation", + "compiler", + "generic", + "bad_habit" + ], + "x-enum-comments": { + "PipelineErrorTypeBadHabit": "some bad-habit error", + "PipelineErrorTypeCompiler": "some error with the config semantics", + "PipelineErrorTypeDeprecation": "using some deprecated feature", + "PipelineErrorTypeGeneric": "some generic error", + "PipelineErrorTypeLinter": "some error with the config syntax" + }, + "x-enum-varnames": [ + "PipelineErrorTypeLinter", + "PipelineErrorTypeDeprecation", + "PipelineErrorTypeCompiler", + "PipelineErrorTypeGeneric", + "PipelineErrorTypeBadHabit" + ] } } }` From 2fcc67b642cd2abdaa4552266f13d8d916093740 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Mon, 19 Feb 2024 18:15:20 +0100 Subject: [PATCH 35/44] replace radicle with info --- docs/docs/30-administration/11-forges/100-addon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/30-administration/11-forges/100-addon.md b/docs/docs/30-administration/11-forges/100-addon.md index 8b911b148f..0721b3e1c2 100644 --- a/docs/docs/30-administration/11-forges/100-addon.md +++ b/docs/docs/30-administration/11-forges/100-addon.md @@ -30,7 +30,7 @@ If you experience bugs, please check which component has the issue. If it's the If you wrote or found an addon forge, please add it here so others can find it! -- Radicle +*Be the first one to add your addon forge!* ## Creating addon forges From 389df9cc0b1c443c06a5580bd6dc0b44c11fd637 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Mon, 19 Feb 2024 18:16:12 +0100 Subject: [PATCH 36/44] Rename flag --- cmd/server/flags.go | 2 +- cmd/server/setup.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/server/flags.go b/cmd/server/flags.go index 027e8fe1b8..597b76c341 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -258,7 +258,7 @@ var flags = append([]cli.Flag{ }, &cli.StringFlag{ EnvVars: []string{"WOODPECKER_ADDON_FORGE"}, - Name: "addons-forge", + Name: "addon-forge", Usage: "forge addon", }, // diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 34f181f7d7..447995228d 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -106,8 +106,8 @@ func setupMembershipService(_ *cli.Context, r forge.Forge) cache.MembershipServi // setupForge helper function to set up the forge from the CLI arguments. func setupForge(c *cli.Context) (forge.Forge, error) { switch { - case c.String("addons-forge") != "": - return addon.Load(c.String("addons-forge")) + case c.String("addon-forge") != "": + return addon.Load(c.String("addon-forge")) case c.Bool("github"): return setupGitHub(c) case c.Bool("gitlab"): From c06d834973f4f48939cd1c34dd9d8feaf5b6c508 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Mon, 26 Feb 2024 10:24:09 +0100 Subject: [PATCH 37/44] fix yaml syntax --- docs/docs/10-intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/10-intro.md b/docs/docs/10-intro.md index 276dcb000e..1cb2b0a90a 100644 --- a/docs/docs/10-intro.md +++ b/docs/docs/10-intro.md @@ -75,7 +75,7 @@ kubectl apply -f $PLUGIN_TEMPLATE ```yaml title=".woodpecker.yaml" steps: - deploy-to-k8s: + - name: deploy-to-k8s image: laszlocloud/my-k8s-plugin settings: template: config/k8s/service.yaml From 13278393e0446682c98c893f19527331984529dd Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 3 Mar 2024 12:10:50 +0100 Subject: [PATCH 38/44] fix build --- pipeline/frontend/yaml/linter/linter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pipeline/frontend/yaml/linter/linter.go b/pipeline/frontend/yaml/linter/linter.go index 7b0647078b..6460919721 100644 --- a/pipeline/frontend/yaml/linter/linter.go +++ b/pipeline/frontend/yaml/linter/linter.go @@ -299,8 +299,8 @@ func (l *Linter) lintDeprecations(config *WorkflowConfig) (err error) { for _, step := range parsed.Steps.ContainerList { for i, c := range step.Secrets.Secrets { if c.Source != c.Target { - err = multierr.Append(err, &errors.PipelineError{ - Type: errors.PipelineErrorTypeDeprecation, + err = multierr.Append(err, &errorTypes.PipelineError{ + Type: errorTypes.PipelineErrorTypeDeprecation, Message: "Secrets alternative names are deprecated, use environment with from_secret", Data: errors.DeprecationErrorData{ File: config.File, From e3edc0fc51e2c9cb08029830d466f462f15f3e6d Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sun, 3 Mar 2024 12:39:55 +0100 Subject: [PATCH 39/44] prettier --- docs/docs/30-administration/11-forges/100-addon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/30-administration/11-forges/100-addon.md b/docs/docs/30-administration/11-forges/100-addon.md index 0721b3e1c2..647ce4af41 100644 --- a/docs/docs/30-administration/11-forges/100-addon.md +++ b/docs/docs/30-administration/11-forges/100-addon.md @@ -30,7 +30,7 @@ If you experience bugs, please check which component has the issue. If it's the If you wrote or found an addon forge, please add it here so others can find it! -*Be the first one to add your addon forge!* +_Be the first one to add your addon forge!_ ## Creating addon forges From e1e2f9cdba38260e923fd2b9271391cec1a50e16 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Mon, 4 Mar 2024 08:51:13 +0100 Subject: [PATCH 40/44] fix renovate pr label --- .github/renovate.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json b/.github/renovate.json index b38fc1202b..aec8eb05fc 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -4,7 +4,7 @@ "packageRules": [ { "matchManagers": ["docker-compose"], - "matchFileNames": ["docker-compose.gitpod.yml"], + "matchFileNames": ["docker-compose.gitpod.yaml"], "addLabels": ["devx"] }, { From 09f086b944aa6629b0d5bfb71452060421e9275f Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Fri, 8 Mar 2024 13:36:20 +0100 Subject: [PATCH 41/44] update some docs --- .../51-plugins/20-creating-plugins.md | 4 +-- .../11-forges/60-bitbucket_datacenter.md | 35 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/docs/docs/20-usage/51-plugins/20-creating-plugins.md b/docs/docs/20-usage/51-plugins/20-creating-plugins.md index adbb4df3e2..c08d882b1e 100644 --- a/docs/docs/20-usage/51-plugins/20-creating-plugins.md +++ b/docs/docs/20-usage/51-plugins/20-creating-plugins.md @@ -118,5 +118,5 @@ docker run --rm \ These should also be built for different OS/architectures. - Use [built-in env vars](../50-environment.md#built-in-environment-variables) where possible. - Do not use any configuration except settings (and internal env vars). This means: Don't require using [`environment`](../50-environment.md) and don't require specific secret names. -- Add a `docs.md` file, listing all your settings and plugin metadata ([example](https://codeberg.org/woodpecker-plugins/plugin-docker-buildx/src/branch/main/docs.md)). -- Add your plugin to the [plugin index](/plugins) using your `docs.md` ([the example above in the index](https://woodpecker-ci.org/plugins/Docker%20Buildx)). +- Add a `docs.md` file, listing all your settings and plugin metadata ([example](https://github.com/woodpecker-ci/plugin-git/blob/main/docs.md)). +- Add your plugin to the [plugin index](/plugins) using your `docs.md` ([the example above in the index](https://woodpecker-ci.org/plugins/Git%20Clone)). diff --git a/docs/docs/30-administration/11-forges/60-bitbucket_datacenter.md b/docs/docs/30-administration/11-forges/60-bitbucket_datacenter.md index e85242c056..9304d13a14 100644 --- a/docs/docs/30-administration/11-forges/60-bitbucket_datacenter.md +++ b/docs/docs/30-administration/11-forges/60-bitbucket_datacenter.md @@ -10,24 +10,23 @@ Woodpecker comes with experimental support for Bitbucket Datacenter / Server, fo To enable Bitbucket Server you should configure the Woodpecker container using the following environment variables: -```diff -# docker-compose.yml -version: '3' - -services: - woodpecker-server: - [...] - environment: - - [...] -+ - WOODPECKER_BITBUCKET_DC=true -+ - WOODPECKER_BITBUCKET_DC_GIT_USERNAME=foo -+ - WOODPECKER_BITBUCKET_DC_GIT_PASSWORD=bar -+ - WOODPECKER_BITBUCKET_DC_CLIENT_ID=xxx -+ - WOODPECKER_BITBUCKET_DC_CLIENT_SECRET=yyy -+ - WOODPECKER_BITBUCKET_DC_URL=http://stash.mycompany.com - - woodpecker-agent: - [...] +```diff title="docker-compose.yaml" + version: '3' + + services: + woodpecker-server: + [...] + environment: + - [...] ++ - WOODPECKER_BITBUCKET_DC=true ++ - WOODPECKER_BITBUCKET_DC_GIT_USERNAME=foo ++ - WOODPECKER_BITBUCKET_DC_GIT_PASSWORD=bar ++ - WOODPECKER_BITBUCKET_DC_CLIENT_ID=xxx ++ - WOODPECKER_BITBUCKET_DC_CLIENT_SECRET=yyy ++ - WOODPECKER_BITBUCKET_DC_URL=http://stash.mycompany.com + + woodpecker-agent: + [...] ``` ## Service Account From aee656d130b849b519dc328c51cf6b188f72681a Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Fri, 8 Mar 2024 14:44:08 +0100 Subject: [PATCH 42/44] Update prettier --- .woodpecker/static.yaml | 2 +- docs/plugins/woodpecker-plugins/tsconfig.json | 4 ++-- docs/tsconfig.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.woodpecker/static.yaml b/.woodpecker/static.yaml index 80259c7b3d..bc97b7f9a5 100644 --- a/.woodpecker/static.yaml +++ b/.woodpecker/static.yaml @@ -23,7 +23,7 @@ steps: image: docker.io/woodpeckerci/plugin-prettier:0.1.0 depends_on: [] settings: - version: 3.2.4 + version: 3.2.5 - name: links image: lycheeverse/lychee:0.14.3 diff --git a/docs/plugins/woodpecker-plugins/tsconfig.json b/docs/plugins/woodpecker-plugins/tsconfig.json index 9b03611a84..cb5616fbce 100644 --- a/docs/plugins/woodpecker-plugins/tsconfig.json +++ b/docs/plugins/woodpecker-plugins/tsconfig.json @@ -18,6 +18,6 @@ "baseUrl": ".", "rootDir": "src", "pretty": true, - "noEmit": false, - }, + "noEmit": false + } } diff --git a/docs/tsconfig.json b/docs/tsconfig.json index bd12d9ee6a..4541193ab8 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -1,4 +1,4 @@ { "extends": "@docusaurus/tsconfig", - "include": ["src/"], + "include": ["src/"] } From d1b18faa2ded43c915f4765177b9addd54cd645d Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Fri, 8 Mar 2024 14:44:23 +0100 Subject: [PATCH 43/44] Revert "Update prettier" This reverts commit aee656d130b849b519dc328c51cf6b188f72681a. --- .woodpecker/static.yaml | 2 +- docs/plugins/woodpecker-plugins/tsconfig.json | 4 ++-- docs/tsconfig.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.woodpecker/static.yaml b/.woodpecker/static.yaml index bc97b7f9a5..80259c7b3d 100644 --- a/.woodpecker/static.yaml +++ b/.woodpecker/static.yaml @@ -23,7 +23,7 @@ steps: image: docker.io/woodpeckerci/plugin-prettier:0.1.0 depends_on: [] settings: - version: 3.2.5 + version: 3.2.4 - name: links image: lycheeverse/lychee:0.14.3 diff --git a/docs/plugins/woodpecker-plugins/tsconfig.json b/docs/plugins/woodpecker-plugins/tsconfig.json index cb5616fbce..9b03611a84 100644 --- a/docs/plugins/woodpecker-plugins/tsconfig.json +++ b/docs/plugins/woodpecker-plugins/tsconfig.json @@ -18,6 +18,6 @@ "baseUrl": ".", "rootDir": "src", "pretty": true, - "noEmit": false - } + "noEmit": false, + }, } diff --git a/docs/tsconfig.json b/docs/tsconfig.json index 4541193ab8..bd12d9ee6a 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -1,4 +1,4 @@ { "extends": "@docusaurus/tsconfig", - "include": ["src/"] + "include": ["src/"], } From 57e34487c4810534bdab4718b4608d694b2fe945 Mon Sep 17 00:00:00 2001 From: qwerty287 <80460567+qwerty287@users.noreply.github.com> Date: Mon, 15 Apr 2024 09:51:57 +0200 Subject: [PATCH 44/44] Update docs/docs/30-administration/11-forges/100-addon.md Co-authored-by: Anbraten <6918444+anbraten@users.noreply.github.com> --- docs/docs/30-administration/11-forges/100-addon.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/docs/30-administration/11-forges/100-addon.md b/docs/docs/30-administration/11-forges/100-addon.md index 647ce4af41..5c98149acb 100644 --- a/docs/docs/30-administration/11-forges/100-addon.md +++ b/docs/docs/30-administration/11-forges/100-addon.md @@ -20,8 +20,6 @@ WOODPECKER_ADDON_FORGE=/path/to/your/addon/forge/file In case you run Woodpecker as container, you probably want to mount the addon binary to `/opt/addons/`. -Using an addon forge always overwrites Woodpecker's internal forge configuration. - ### Bug reports If you experience bugs, please check which component has the issue. If it's the addon, **do not raise an issue in the main repository**, but rather use the separate addon repositories. To check which component is responsible for the bug, look at the logs. Logs from addons are marked with a special field `addon` containing their addon file name.