Skip to content

Commit 5cf085d

Browse files
committed
Implement SourceHut forge backend
1 parent 3e45257 commit 5cf085d

File tree

18 files changed

+3547
-7
lines changed

18 files changed

+3547
-7
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ __debug_bin*
2121
# Output of the go coverage tool, specifically when used with LiteIDE
2222
*.out
2323

24+
# Generated GraphQL client code
25+
server/forge/sourcehut/*/gql.go
26+
2427
### Frontend ###
2528
web/dist/**
2629
!web/dist/.gitkeep

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,17 @@ clean-all: clean ## Clean all artifacts
118118
rm -rf docs/docs/40-cli.md docs/openapi.json
119119

120120
.PHONY: generate
121-
generate: install-mockery generate-openapi ## Run all code generations
121+
generate: install-mockery generate-openapi generate-sourcehut ## Run all code generations
122122
mockery
123123
CGO_ENABLED=0 go generate ./...
124124

125125
generate-openapi: ## Run openapi code generation and format it
126126
CGO_ENABLED=0 go run github.com/swaggo/swag/cmd/swag fmt --exclude pipeline/rpc/proto
127127
CGO_ENABLED=0 go generate cmd/server/openapi.go
128128

129+
generate-sourcehut: ## Run sourcehut GraphQL client generation
130+
CGO_ENABLED=0 go generate ./server/forge/sourcehut/...
131+
129132
generate-license-header: install-addlicense
130133
addlicense -c "Woodpecker Authors" -ignore "vendor/**" **/*.go
131134

cmd/server/flags.go

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ var flags = append([]cli.Flag{
390390
&cli.StringFlag{
391391
Name: "forge-url",
392392
Usage: "url of the forge",
393-
Sources: cli.EnvVars("WOODPECKER_FORGE_URL", "WOODPECKER_GITHUB_URL", "WOODPECKER_GITLAB_URL", "WOODPECKER_GITEA_URL", "WOODPECKER_FORGEJO_URL", "WOODPECKER_BITBUCKET_URL", "WOODPECKER_BITBUCKET_DC_URL"),
393+
Sources: cli.EnvVars("WOODPECKER_FORGE_URL", "WOODPECKER_GITHUB_URL", "WOODPECKER_GITLAB_URL", "WOODPECKER_GITEA_URL", "WOODPECKER_FORGEJO_URL", "WOODPECKER_BITBUCKET_URL", "WOODPECKER_BITBUCKET_DC_URL", "WOODPECKER_SOURCEHUT_URL"),
394394
},
395395
&cli.StringFlag{
396396
Sources: cli.NewValueSourceChain(
@@ -401,14 +401,16 @@ var flags = append([]cli.Flag{
401401
"WOODPECKER_GITEA_CLIENT_FILE",
402402
"WOODPECKER_FORGEJO_CLIENT_FILE",
403403
"WOODPECKER_BITBUCKET_CLIENT_FILE",
404-
"WOODPECKER_BITBUCKET_DC_CLIENT_ID_FILE")),
404+
"WOODPECKER_BITBUCKET_DC_CLIENT_ID_FILE",
405+
"WOODPECKER_SOURCEHUT_CLIENT_FILE")),
405406
cli.EnvVar("WOODPECKER_FORGE_CLIENT"),
406407
cli.EnvVar("WOODPECKER_GITHUB_CLIENT"),
407408
cli.EnvVar("WOODPECKER_GITLAB_CLIENT"),
408409
cli.EnvVar("WOODPECKER_GITEA_CLIENT"),
409410
cli.EnvVar("WOODPECKER_FORGEJO_CLIENT"),
410411
cli.EnvVar("WOODPECKER_BITBUCKET_CLIENT"),
411-
cli.EnvVar("WOODPECKER_BITBUCKET_DC_CLIENT_ID")),
412+
cli.EnvVar("WOODPECKER_BITBUCKET_DC_CLIENT_ID"),
413+
cli.EnvVar("WOODPECKER_SOURCEHUT_CLIENT")),
412414
Name: "forge-oauth-client",
413415
Usage: "oauth2 client id",
414416
Config: cli.StringConfig{
@@ -425,14 +427,16 @@ var flags = append([]cli.Flag{
425427
"WOODPECKER_FORGEJO_SECRET_FILE",
426428
"WOODPECKER_BITBUCKET_SECRET_FILE",
427429
"WOODPECKER_BITBUCKET_DC_CLIENT_SECRET_FILE",
430+
"WOODPECKER_SOURCEHUT_SECRET_FILE",
428431
)),
429432
cli.EnvVar("WOODPECKER_FORGE_SECRET"),
430433
cli.EnvVar("WOODPECKER_GITHUB_SECRET"),
431434
cli.EnvVar("WOODPECKER_GITLAB_SECRET"),
432435
cli.EnvVar("WOODPECKER_GITEA_SECRET"),
433436
cli.EnvVar("WOODPECKER_FORGEJO_SECRET"),
434437
cli.EnvVar("WOODPECKER_BITBUCKET_SECRET"),
435-
cli.EnvVar("WOODPECKER_BITBUCKET_DC_CLIENT_SECRET")),
438+
cli.EnvVar("WOODPECKER_BITBUCKET_DC_CLIENT_SECRET"),
439+
cli.EnvVar("WOODPECKER_SOURCEHUT_SECRET")),
436440
Name: "forge-oauth-secret",
437441
Usage: "oauth2 client secret",
438442
Config: cli.StringConfig{
@@ -448,7 +452,8 @@ var flags = append([]cli.Flag{
448452
"WOODPECKER_GITLAB_SKIP_VERIFY",
449453
"WOODPECKER_GITEA_SKIP_VERIFY",
450454
"WOODPECKER_FORGEJO_SKIP_VERIFY",
451-
"WOODPECKER_BITBUCKET_SKIP_VERIFY"),
455+
"WOODPECKER_BITBUCKET_SKIP_VERIFY",
456+
"WOODPECKER_SOURCEHUT_SKIP_VERIFY"),
452457
},
453458
&cli.StringFlag{
454459
Sources: cli.EnvVars("WOODPECKER_EXPERT_FORGE_OAUTH_HOST"),
@@ -549,6 +554,29 @@ var flags = append([]cli.Flag{
549554
Usage: "Bitbucket DataCenter/Server oauth2 scope should be configured to include PROJECT_ADMIN configuration.",
550555
},
551556
//
557+
// SourceHut
558+
//
559+
&cli.BoolFlag{
560+
Sources: cli.EnvVars("WOODPECKER_SOURCEHUT"),
561+
Name: "sourcehut",
562+
Usage: "sourcehut driver is enabled",
563+
},
564+
&cli.StringFlag{
565+
Sources: cli.EnvVars("WOODPECKER_SOURCEHUT_META_URL"),
566+
Name: "sourcehut-meta-url",
567+
Usage: "sourcehut meta.sr.ht URL",
568+
},
569+
&cli.StringFlag{
570+
Sources: cli.EnvVars("WOODPECKER_SOURCEHUT_GIT_URL"),
571+
Name: "sourcehut-git-url",
572+
Usage: "sourcehut git.sr.ht URL",
573+
},
574+
&cli.StringFlag{
575+
Sources: cli.EnvVars("WOODPECKER_SOURCEHUT_LISTS_URL"),
576+
Name: "sourcehut-lists-url",
577+
Usage: "sourcehut lists.sr.ht URL",
578+
},
579+
//
552580
// development flags
553581
//
554582
&cli.StringFlag{

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@ require (
7777

7878
require (
7979
filippo.io/edwards25519 v1.1.0 // indirect
80+
git.sr.ht/~emersion/gqlclient v0.0.0-20250318184027-d4a003529bba // indirect
8081
github.com/42wim/httpsig v1.2.3 // indirect
8182
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
8283
github.com/KyleBanks/depth v1.2.1 // indirect
8384
github.com/Microsoft/go-winio v0.6.1 // indirect
85+
github.com/agnivade/levenshtein v1.1.1 // indirect
8486
github.com/atotto/clipboard v0.1.4 // indirect
8587
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
8688
github.com/beorn7/perks v1.0.1 // indirect
@@ -101,6 +103,7 @@ require (
101103
github.com/containerd/log v0.1.0 // indirect
102104
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
103105
github.com/danieljoos/wincred v1.2.3 // indirect
106+
github.com/dave/jennifer v1.7.0 // indirect
104107
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
105108
github.com/davidmz/go-pageant v1.0.2 // indirect
106109
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
@@ -197,6 +200,7 @@ require (
197200
github.com/ugorji/go/codec v1.3.0 // indirect
198201
github.com/urfave/cli/v2 v2.25.3 // indirect
199202
github.com/valyala/fastjson v1.6.4 // indirect
203+
github.com/vektah/gqlparser/v2 v2.5.8 // indirect
200204
github.com/woodsbury/decimal128 v1.3.0 // indirect
201205
github.com/x448/float16 v0.8.4 // indirect
202206
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect

go.sum

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2 v2.2.0 h1:HTCWpzyWQOHDWt3LzI6/d2jv
1010
codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2 v2.2.0/go.mod h1:ZglEEDj+qkxYUb+SQIeqGtFxQrbaMYqIOgahNKb7uxs=
1111
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
1212
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
13+
git.sr.ht/~emersion/gqlclient v0.0.0-20250318184027-d4a003529bba h1:Rl2ylhbDFXZ5LfT43Usf/8WTWOG01FQ+1uPTuLiH34k=
14+
git.sr.ht/~emersion/gqlclient v0.0.0-20250318184027-d4a003529bba/go.mod h1:kvl/JK0Z3VRmtbBxdOJR4ydyXVouUIcFIXgv4H6rVAY=
1315
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
1416
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
1517
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
@@ -32,8 +34,11 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc
3234
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
3335
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
3436
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
37+
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
38+
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
3539
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
3640
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
41+
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
3742
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
3843
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
3944
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
@@ -110,6 +115,8 @@ github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
110115
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
111116
github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ=
112117
github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs=
118+
github.com/dave/jennifer v1.7.0 h1:uRbSBH9UTS64yXbh4FrMHfgfY762RD+C7bUPKODpSJE=
119+
github.com/dave/jennifer v1.7.0/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
113120
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
114121
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
115122
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -120,6 +127,7 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvw
120127
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
121128
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
122129
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
130+
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
123131
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
124132
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
125133
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
@@ -575,6 +583,8 @@ github.com/urfave/cli/v3 v3.6.1 h1:j8Qq8NyUawj/7rTYdBGrxcH7A/j7/G8Q5LhWEW4G3Mo=
575583
github.com/urfave/cli/v3 v3.6.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
576584
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
577585
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
586+
github.com/vektah/gqlparser/v2 v2.5.8 h1:pm6WOnGdzFOCfcQo9L3+xzW51mKrlwTEg4Wr7AH1JW4=
587+
github.com/vektah/gqlparser/v2 v2.5.8/go.mod h1:z8xXUff237NntSuH8mLFijZ+1tjV1swDbpDqjJmk6ME=
578588
github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0=
579589
github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds=
580590
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
@@ -787,6 +797,7 @@ google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aO
787797
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
788798
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
789799
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
800+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
790801
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
791802
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
792803
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=

server/forge/setup/setup.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"go.woodpecker-ci.org/woodpecker/v3/server/forge/gitea"
1616
"go.woodpecker-ci.org/woodpecker/v3/server/forge/github"
1717
"go.woodpecker-ci.org/woodpecker/v3/server/forge/gitlab"
18+
"go.woodpecker-ci.org/woodpecker/v3/server/forge/sourcehut"
1819
"go.woodpecker-ci.org/woodpecker/v3/server/model"
1920
)
2021

@@ -34,6 +35,8 @@ func Forge(forge *model.Forge) (forge.Forge, error) {
3435
return setupForgejo(forge)
3536
case model.ForgeTypeBitbucketDatacenter:
3637
return setupBitbucketDatacenter(forge)
38+
case model.ForgeTypeSourceHut:
39+
return setupSourceHut(forge)
3740
default:
3841
return nil, fmt.Errorf("forge not configured")
3942
}
@@ -188,6 +191,54 @@ func setupBitbucketDatacenter(forge *model.Forge) (forge.Forge, error) {
188191
return bitbucketdatacenter.New(forge.ID, opts)
189192
}
190193

194+
func setupSourceHut(forge *model.Forge) (forge.Forge, error) {
195+
server, err := url.Parse(forge.URL)
196+
if err != nil {
197+
return nil, err
198+
}
199+
200+
metaURL, ok := forge.AdditionalOptions["meta-url"].(string)
201+
if !ok {
202+
return nil, fmt.Errorf("missing meta-url")
203+
}
204+
205+
gitURL, ok := forge.AdditionalOptions["git-url"].(string)
206+
if !ok {
207+
return nil, fmt.Errorf("missing git-url")
208+
}
209+
210+
listsURL, ok := forge.AdditionalOptions["lists-url"].(string)
211+
if !ok {
212+
return nil, fmt.Errorf("missing lists-url")
213+
}
214+
215+
opts := sourcehut.Opts{
216+
URL: strings.TrimRight(server.String(), "/"),
217+
MetaURL: metaURL,
218+
GitURL: gitURL,
219+
ListsURL: listsURL,
220+
OAuthClientID: forge.OAuthClientID,
221+
OAuthClientSecret: forge.OAuthClientSecret,
222+
SkipVerify: forge.SkipVerify,
223+
OAuth2URL: metaURL,
224+
}
225+
if len(opts.URL) == 0 {
226+
return nil, fmt.Errorf("WOODPECKER_SOURCEHUT_URL must be set")
227+
}
228+
log.Debug().
229+
Str("url", opts.URL).
230+
Str("meta-url", opts.MetaURL).
231+
Str("git-url", opts.GitURL).
232+
Str("lists-url", opts.ListsURL).
233+
Str("oauth2-url", opts.OAuth2URL).
234+
Bool("skip-verify", opts.SkipVerify).
235+
Bool("oauth-client-id-set", opts.OAuthClientID != "").
236+
Bool("oauth-client-secret-set", opts.OAuthClientSecret != "").
237+
Str("type", string(forge.Type)).
238+
Msg("setting up forge")
239+
return sourcehut.New(forge.ID, opts)
240+
}
241+
191242
func setupAddon(forge *model.Forge) (forge.Forge, error) {
192243
executable, ok := forge.AdditionalOptions["executable"].(string)
193244
if !ok {

server/forge/sourcehut/git/gen.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package git
2+
3+
//go:generate go run git.sr.ht/~emersion/gqlclient/cmd/gqlclientgen -s schema.graphqls -q queries.graphql -o gql.go -n git

0 commit comments

Comments
 (0)