diff --git a/cmd/server/flags.go b/cmd/server/flags.go index ffacb4223..fd6de02a2 100644 --- a/cmd/server/flags.go +++ b/cmd/server/flags.go @@ -318,37 +318,6 @@ var flags = []cli.Flag{ Usage: "github skip ssl verification", }, // - // Gogs - // - &cli.BoolFlag{ - EnvVars: []string{"WOODPECKER_GOGS"}, - Name: "gogs", - Usage: "gogs driver is enabled", - }, - &cli.StringFlag{ - EnvVars: []string{"WOODPECKER_GOGS_URL"}, - Name: "gogs-server", - Usage: "gogs server address", - Value: "https://try.gogs.io", - }, - &cli.StringFlag{ - EnvVars: []string{"WOODPECKER_GOGS_GIT_USERNAME"}, - Name: "gogs-git-username", - Usage: "gogs service account username", - FilePath: os.Getenv("WOODPECKER_GOGS_GIT_USERNAME_FILE"), - }, - &cli.StringFlag{ - EnvVars: []string{"WOODPECKER_GOGS_GIT_PASSWORD"}, - Name: "gogs-git-password", - Usage: "gogs service account password", - FilePath: os.Getenv("WOODPECKER_GOGS_GIT_PASSWORD_FILE"), - }, - &cli.BoolFlag{ - EnvVars: []string{"WOODPECKER_GOGS_SKIP_VERIFY"}, - Name: "gogs-skip-verify", - Usage: "gogs skip ssl verification", - }, - // // Gitea // &cli.BoolFlag{ diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 904d649c4..ae5917adf 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -42,7 +42,6 @@ import ( "github.com/woodpecker-ci/woodpecker/server/forge/gitea" "github.com/woodpecker-ci/woodpecker/server/forge/github" "github.com/woodpecker-ci/woodpecker/server/forge/gitlab" - "github.com/woodpecker-ci/woodpecker/server/forge/gogs" "github.com/woodpecker-ci/woodpecker/server/model" "github.com/woodpecker-ci/woodpecker/server/plugins/environments" "github.com/woodpecker-ci/woodpecker/server/plugins/registry" @@ -196,8 +195,6 @@ func setupForge(c *cli.Context) (forge.Forge, error) { return setupBitbucket(c) case c.Bool("stash"): return setupStash(c) - case c.Bool("gogs"): - return setupGogs(c) case c.Bool("gitea"): return setupGitea(c) default: @@ -205,7 +202,7 @@ func setupForge(c *cli.Context) (forge.Forge, error) { } } -// helper function to setup the Bitbucket forge from the CLI arguments. +// setupBitbucket helper function to setup the Bitbucket forge from the CLI arguments. func setupBitbucket(c *cli.Context) (forge.Forge, error) { opts := &bitbucket.Opts{ Client: c.String("bitbucket-client"), @@ -215,19 +212,7 @@ func setupBitbucket(c *cli.Context) (forge.Forge, error) { return bitbucket.New(opts) } -// helper function to setup the Gogs forge from the CLI arguments. -func setupGogs(c *cli.Context) (forge.Forge, error) { - opts := gogs.Opts{ - URL: c.String("gogs-server"), - Username: c.String("gogs-git-username"), - Password: c.String("gogs-git-password"), - SkipVerify: c.Bool("gogs-skip-verify"), - } - log.Trace().Msgf("Forge (gogs) opts: %#v", opts) - return gogs.New(opts) -} - -// helper function to setup the Gitea forge from the CLI arguments. +// setupGitea helper function to setup the Gitea forge from the CLI arguments. func setupGitea(c *cli.Context) (forge.Forge, error) { server, err := url.Parse(c.String("gitea-server")) if err != nil { @@ -246,7 +231,7 @@ func setupGitea(c *cli.Context) (forge.Forge, error) { return gitea.New(opts) } -// helper function to setup the Stash forge from the CLI arguments. +// setupStash helper function to setup the Stash forge from the CLI arguments. func setupStash(c *cli.Context) (forge.Forge, error) { opts := bitbucketserver.Opts{ URL: c.String("stash-server"), @@ -261,7 +246,7 @@ func setupStash(c *cli.Context) (forge.Forge, error) { return bitbucketserver.New(opts) } -// helper function to setup the GitLab forge from the CLI arguments. +// setupGitLab helper function to setup the GitLab forge from the CLI arguments. func setupGitLab(c *cli.Context) (forge.Forge, error) { return gitlab.New(gitlab.Opts{ URL: c.String("gitlab-server"), @@ -271,7 +256,7 @@ func setupGitLab(c *cli.Context) (forge.Forge, error) { }) } -// helper function to setup the GitHub forge from the CLI arguments. +// setupGitHub helper function to setup the GitHub forge from the CLI arguments. func setupGitHub(c *cli.Context) (forge.Forge, error) { opts := github.Opts{ URL: c.String("github-server"), @@ -344,7 +329,7 @@ func setupMetrics(g *errgroup.Group, _store store.Store) { }) } -// generate or load key pair to sign webhooks requests (i.e. used for extensions) +// setupSignatureKeys generate or load key pair to sign webhooks requests (i.e. used for extensions) func setupSignatureKeys(_store store.Store) (crypto.PrivateKey, crypto.PublicKey) { privKeyID := "signature-private-key" diff --git a/docs/docs/30-administration/10-server-config.md b/docs/docs/30-administration/10-server-config.md index 700ae9f14..282f6cc8e 100644 --- a/docs/docs/30-administration/10-server-config.md +++ b/docs/docs/30-administration/10-server-config.md @@ -422,10 +422,6 @@ Example: `WOODPECKER_ROOT_URL=/woodpecker` See [GitHub configuration](forges/github/#configuration) -### `WOODPECKER_GOGS_...` - -See [Gogs configuration](forges/gogs/#configuration) - ### `WOODPECKER_GITEA_...` See [Gitea configuration](forges/gitea/#configuration) diff --git a/docs/docs/30-administration/11-forges/10-overview.md b/docs/docs/30-administration/11-forges/10-overview.md index c4ef82f4e..696c6beb7 100644 --- a/docs/docs/30-administration/11-forges/10-overview.md +++ b/docs/docs/30-administration/11-forges/10-overview.md @@ -2,14 +2,13 @@ ## Supported features -| Feature | [GitHub](github/) | [Gitea / Forgejo](gitea/) | [Gitlab](gitlab/) | [Bitbucket](bitbucket/) | [Bitbucket Server](bitbucket_server/) | [Gogs](gogs/) | -| --- | :---: | :---: | :---: | :---: | :---: | :---: | -| Event: Push | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| Event: Tag | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | -| Event: Pull-Request | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | -| Event: Deploy | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | -| OAuth | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | -| [Multiple workflows](../../20-usage/25-workflows.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | -| [when.path filter](../../20-usage/20-pipeline-syntax.md#path) | :white_check_mark: | :white_check_mark:¹ | :white_check_mark: | :x: | :x: | :x: | +| Feature | [GitHub](github/) | [Gitea / Forgejo](gitea/) | [Gitlab](gitlab/) | [Bitbucket](bitbucket/) | [Bitbucket Server](bitbucket_server/) | +| --- | :---: | :---: | :---: | :---: | :---: | +| Event: Push | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Event: Tag | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | +| Event: Pull-Request | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| Event: Deploy | :white_check_mark: | :x: | :x: | :x: | :x: | +| [Multiple workflows](../../20-usage/25-workflows.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | +| [when.path filter](../../20-usage/20-pipeline-syntax.md#path) | :white_check_mark: | :white_check_mark:¹ | :white_check_mark: | :x: | :x: | ¹ for pull requests at least Gitea version 1.17 is required diff --git a/docs/docs/30-administration/11-forges/70-gogs.md b/docs/docs/30-administration/11-forges/70-gogs.md deleted file mode 100644 index 810da0227..000000000 --- a/docs/docs/30-administration/11-forges/70-gogs.md +++ /dev/null @@ -1,40 +0,0 @@ -# Gogs - -## Configuration - -This is a full list of configuration options. Please note that many of these options use default configuration values that should work for the majority of installations. - -### `WOODPECKER_GOGS` -> Default: `false` - -Enables the Gogs driver. - -### `WOODPECKER_GOGS_URL` -> Default: `https://try.gogs.io` - -Configures the Gogs server address. - -### `WOODPECKER_GOGS_GIT_USERNAME` -> Default: empty - -This username is used to authenticate and clone all private repositories. - -### `WOODPECKER_GOGS_GIT_USERNAME_FILE` -> Default: empty - -Read the value for `WOODPECKER_GOGS_GIT_USERNAME` from the specified filepath - -### `WOODPECKER_GOGS_GIT_PASSWORD` -> Default: empty - -The password is used to authenticate and clone all private repositories. - -### `WOODPECKER_GOGS_GIT_PASSWORD_FILE` -> Default: empty - -Read the value for `WOODPECKER_GOGS_GIT_PASSWORD` from the specified filepath - -### `WOODPECKER_GOGS_SKIP_VERIFY` -> Default: `false` - -Configure if SSL verification should be skipped. diff --git a/docs/docs/91-migrations.md b/docs/docs/91-migrations.md index 23b15d83f..72290e4bf 100644 --- a/docs/docs/91-migrations.md +++ b/docs/docs/91-migrations.md @@ -15,9 +15,8 @@ Some versions need some changes to the server configuration or the pipeline conf - Updated Prometheus gauge `*_job_*` to `*_step_*` - Renamed config env `WOODPECKER_MAX_PROCS` to `WOODPECKER_MAX_WORKFLOWS` (still available as fallback) - The pipelines are now also read from `.yaml` files, the new default order is `.woodpecker/*.yml` and `.woodpecker/*.yaml` (without any prioritization) -> `.woodpecker.yml` -> `.woodpecker.yaml` -> `.drone.yml` -- Dropped support for [Coding](https://coding.net/). +- Dropped support for [Coding](https://coding.net/) and [Gogs](https://gogs.io). - `/api/queue/resume` & `/api/queue/pause` endpoint methods were changed from `GET` to `POST` -- Dropped `WOODPECKER_GOGS_PRIVATE_MODE` (use `WOODPECKER_AUTHENTICATE_PUBLIC_REPOS`) ## 0.15.0 diff --git a/go.mod b/go.mod index 788797404..ad4f66703 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,6 @@ require ( github.com/gin-gonic/gin v1.9.0 github.com/go-ap/httpsig v0.0.0-20221203064646-3647b4d88fdf github.com/go-sql-driver/mysql v1.7.1 - github.com/gogits/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-github/v39 v39.2.0 github.com/google/tink/go v1.7.0 diff --git a/go.sum b/go.sum index 5cf53118c..b8c2c6143 100644 --- a/go.sum +++ b/go.sum @@ -162,8 +162,6 @@ github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogits/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:04sojTxgYxu1L4Hn7Tgf7UVtIosVa6CuHtvNY+7T1K4= -github.com/gogits/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:cY2AIrMgHm6oOHmR7jY+9TtjzSjQ3iG7tURJG3Y6XH0= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= diff --git a/server/forge/gogs/fixtures/handler.go b/server/forge/gogs/fixtures/handler.go deleted file mode 100644 index 0fdb7925c..000000000 --- a/server/forge/gogs/fixtures/handler.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2018 Drone.IO Inc. -// -// 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 fixtures - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -// Handler returns an http.Handler that is capable of handling a variety of mock -// Bitbucket requests and returning mock responses. -func Handler() http.Handler { - gin.SetMode(gin.TestMode) - - e := gin.New() - e.GET("/api/v1/repos/:owner/:name", getRepo) - e.GET("/api/v1/repos/:owner/:name/raw/:commit/:file", getRepoFile) - e.POST("/api/v1/repos/:owner/:name/hooks", createRepoHook) - e.GET("/api/v1/user/repos", getUserRepos) - - return e -} - -func getRepo(c *gin.Context) { - switch c.Param("name") { - case "repo_not_found": - c.String(404, "") - default: - c.String(200, repoPayload) - } -} - -func getRepoFile(c *gin.Context) { - if c.Param("file") == "file_not_found" { - c.String(404, "") - } - if c.Param("commit") == "v1.0.0" || c.Param("commit") == "9ecad50" { - c.String(200, repoFilePayload) - } - c.String(404, "") -} - -func createRepoHook(c *gin.Context) { - in := struct { - Type string `json:"type"` - Conf struct { - Type string `json:"content_type"` - URL string `json:"url"` - } `json:"config"` - }{} - _ = c.BindJSON(&in) - if in.Type != "gogs" || - in.Conf.Type != "json" || - in.Conf.URL != "http://localhost" { - c.String(500, "") - return - } - - c.String(200, "{}") -} - -func getUserRepos(c *gin.Context) { - switch c.Request.Header.Get("Authorization") { - case "token repos_not_found": - c.String(404, "") - default: - c.String(200, userRepoPayload) - } -} - -const repoPayload = ` -{ - "id": 5, - "owner": { - "username": "test_name", - "email": "octocat@github.com", - "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" - }, - "full_name": "test_name\/repo_name", - "private": true, - "html_url": "http:\/\/localhost\/test_name\/repo_name", - "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", - "permissions": { - "admin": true, - "push": true, - "pull": true - } -} -` - -const repoFilePayload = `{ platform: linux/amd64 }` - -const userRepoPayload = ` -[ - { - "id": 5, - "owner": { - "username": "test_name", - "email": "octocat@github.com", - "avatar_url": "https:\/\/secure.gravatar.com\/avatar\/8c58a0be77ee441bb8f8595b7f1b4e87" - }, - "full_name": "test_name\/repo_name", - "private": true, - "html_url": "http:\/\/localhost\/test_name\/repo_name", - "clone_url": "http:\/\/localhost\/test_name\/repo_name.git", - "permissions": { - "admin": true, - "push": true, - "pull": true - } - } -] -` diff --git a/server/forge/gogs/fixtures/hooks.go b/server/forge/gogs/fixtures/hooks.go deleted file mode 100644 index 2f5ac87fe..000000000 --- a/server/forge/gogs/fixtures/hooks.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2018 Drone.IO Inc. -// -// 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 fixtures - -// Sample Gogs push hook -var HookPush = ` -{ - "ref": "refs/heads/master", - "before": "4b2626259b5a97b6b4eab5e6cca66adb986b672b", - "after": "ef98532add3b2feb7a137426bba1248724367df5", - "compare_url": "http://gogs.golang.org/gordon/hello-world/compare/4b2626259b5a97b6b4eab5e6cca66adb986b672b...ef98532add3b2feb7a137426bba1248724367df5", - "commits": [ - { - "id": "ef98532add3b2feb7a137426bba1248724367df5", - "message": "bump\n", - "url": "http://gogs.golang.org/gordon/hello-world/commit/ef98532add3b2feb7a137426bba1248724367df5", - "author": { - "name": "Gordon the Gopher", - "email": "gordon@golang.org", - "username": "gordon" - } - } - ], - "repository": { - "id": 1, - "name": "hello-world", - "full_name": "gordon/hello-world", - "html_url": "http://gogs.golang.org/gordon/hello-world", - "ssh_url": "git@gogs.golang.org:gordon/hello-world.git", - "clone_url": "http://gogs.golang.org/gordon/hello-world.git", - "description": "", - "website": "", - "watchers": 1, - "owner": { - "name": "gordon", - "email": "gordon@golang.org", - "username": "gordon" - }, - "private": true, - "permissions": { - "admin": true, - "push": true, - "pull": true - } - }, - "pusher": { - "name": "gordon", - "email": "gordon@golang.org", - "username": "gordon" - }, - "sender": { - "login": "gordon", - "id": 1, - "email": "gordon@golang.org", - "avatar_url": "http://gogs.golang.org///1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87" - } -} -` - -// Sample Gogs tag hook -var HookPushTag = `{ - "secret": "l26Un7G7HXogLAvsyf2hOA4EMARSTsR3", - "ref": "v1.0.0", - "ref_type": "tag", - "repository": { - "id": 1, - "owner": { - "id": 1, - "username": "gordon", - "full_name": "Gordon the Gopher", - "email": "gordon@golang.org", - "avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87" - }, - "name": "hello-world", - "full_name": "gordon/hello-world", - "description": "", - "private": true, - "fork": false, - "html_url": "http://gogs.golang.org/gordon/hello-world", - "ssh_url": "git@gogs.golang.org:gordon/hello-world.git", - "clone_url": "http://gogs.golang.org/gordon/hello-world.git", - "default_branch": "master", - "created_at": "2015-10-22T19:32:44Z", - "updated_at": "2016-11-24T13:37:16Z", - "permissions": { - "admin": true, - "push": true, - "pull": true - } - }, - "sender": { - "id": 1, - "username": "gordon", - "full_name": "Gordon the Gopher", - "email": "gordon@golang.org", - "avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87" - } -}` - -// HookPullRequest is a sample pull_request webhook payload -var HookPullRequest = `{ - "action": "opened", - "number": 1, - "pull_request": { - "html_url": "http://gogs.golang.org/gordon/hello-world/pull/1", - "state": "open", - "title": "Update the README with new information", - "body": "please merge", - "user": { - "id": 1, - "username": "gordon", - "full_name": "Gordon the Gopher", - "email": "gordon@golang.org", - "avatar_url": "http://gogs.golang.org///1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87" - }, - "base_branch": "master", - "base": { - "label": "master", - "ref": "master", - "sha": "9353195a19e45482665306e466c832c46560532d" - }, - "head_branch": "feature/changes", - "head": { - "label": "feature/changes", - "ref": "feature/changes", - "sha": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c" - } - }, - "repository": { - "id": 35129377, - "name": "hello-world", - "full_name": "gordon/hello-world", - "owner": { - "id": 1, - "username": "gordon", - "full_name": "Gordon the Gopher", - "email": "gordon@golang.org", - "avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87" - }, - "private": true, - "html_url": "http://gogs.golang.org/gordon/hello-world", - "clone_url": "https://gogs.golang.org/gordon/hello-world.git", - "default_branch": "master", - "permissions": { - "admin": true, - "push": true, - "pull": true - } - }, - "sender": { - "id": 1, - "login": "gordon", - "username": "gordon", - "full_name": "Gordon the Gopher", - "email": "gordon@golang.org", - "avatar_url": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87" - } -}` diff --git a/server/forge/gogs/gogs.go b/server/forge/gogs/gogs.go deleted file mode 100644 index 45ce79adf..000000000 --- a/server/forge/gogs/gogs.go +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2022 Woodpecker Authors -// Copyright 2018 Drone.IO Inc. -// -// 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 gogs - -import ( - "context" - "crypto/tls" - "fmt" - "net" - "net/http" - "net/url" - "strings" - - "github.com/gogits/go-gogs-client" - - "github.com/woodpecker-ci/woodpecker/server/forge" - "github.com/woodpecker-ci/woodpecker/server/forge/common" - forge_types "github.com/woodpecker-ci/woodpecker/server/forge/types" - "github.com/woodpecker-ci/woodpecker/server/model" -) - -// Opts defines configuration options. -type Opts struct { - URL string // Gogs server url. - Username string // Optional machine account username. - Password string // Optional machine account password. - SkipVerify bool // Skip ssl verification. -} - -type client struct { - URL string - Username string - Password string - SkipVerify bool -} - -// New returns a Forge implementation that integrates with Gogs, an open -// source Git service written in Go. See https://gogs.io/ -func New(opts Opts) (forge.Forge, error) { - u, err := url.Parse(opts.URL) - if err != nil { - return nil, err - } - host, _, err := net.SplitHostPort(u.Host) - if err == nil { - u.Host = host - } - return &client{ - URL: opts.URL, - Username: opts.Username, - Password: opts.Password, - SkipVerify: opts.SkipVerify, - }, nil -} - -// Name returns the string name of this driver -func (c *client) Name() string { - return "gogs" -} - -// Login authenticates an account with Gogs using basic authentication. The -// Gogs account details are returned when the user is successfully authenticated. -func (c *client) Login(_ context.Context, res http.ResponseWriter, req *http.Request) (*model.User, error) { - var ( - username = req.FormValue("username") - password = req.FormValue("password") - ) - - // if the username or password is empty we re-direct to the login screen. - if len(username) == 0 || len(password) == 0 { - http.Redirect(res, req, "/login/form", http.StatusSeeOther) - return nil, nil - } - - client := c.newClient() - - // try to fetch woodpecker token if it exists - var accessToken string - tokens, err := client.ListAccessTokens(username, password) - if err == nil { - for _, token := range tokens { - if token.Name == "woodpecker" { - accessToken = token.Sha1 - break - } - } - } - - // if woodpecker token not found, create it - if accessToken == "" { - token, terr := client.CreateAccessToken( - username, - password, - gogs.CreateAccessTokenOption{Name: "woodpecker"}, - ) - if terr != nil { - return nil, terr - } - accessToken = token.Sha1 - } - - client = c.newClientToken(accessToken) - account, err := client.GetUserInfo(username) - if err != nil { - return nil, err - } - - return &model.User{ - Token: accessToken, - Login: account.UserName, - Email: account.Email, - Avatar: expandAvatar(c.URL, account.AvatarUrl), - ForgeRemoteID: model.ForgeRemoteID(fmt.Sprint(account.ID)), - }, nil -} - -// Auth is not supported by the Gogs driver. -func (c *client) Auth(_ context.Context, _, _ string) (string, error) { - return "", forge_types.ErrNotImplemented -} - -// Teams is not supported by the Gogs driver. -func (c *client) Teams(_ context.Context, u *model.User) ([]*model.Team, error) { - client := c.newClientToken(u.Token) - orgs, err := client.ListMyOrgs() - if err != nil { - return nil, err - } - - var teams []*model.Team - for _, org := range orgs { - teams = append(teams, toTeam(org, c.URL)) - } - return teams, nil -} - -// Repo returns the named Gogs repository. -func (c *client) Repo(_ context.Context, u *model.User, _ model.ForgeRemoteID, owner, name string) (*model.Repo, error) { - client := c.newClientToken(u.Token) - repo, err := client.GetRepo(owner, name) - if err != nil { - return nil, err - } - return toRepo(repo), nil -} - -// Repos returns a list of all repositories for the Gogs account, including -// organization repositories. -func (c *client) Repos(_ context.Context, u *model.User) ([]*model.Repo, error) { - var repos []*model.Repo - - client := c.newClientToken(u.Token) - all, err := client.ListMyRepos() - if err != nil { - return repos, err - } - - for _, repo := range all { - repos = append(repos, toRepo(repo)) - } - return repos, err -} - -// File fetches the file from the Gogs repository and returns its contents. -func (c *client) File(_ context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { - client := c.newClientToken(u.Token) - ref := b.Commit - - // TODO gogs does not yet return a sha with the pull request - // so unfortunately we need to use the pull request branch. - if b.Event == model.EventPull { - ref = b.Branch - } - if ref == "" { - // Remove refs/tags or refs/heads, Gogs needs a short ref - ref = strings.TrimPrefix( - strings.TrimPrefix( - b.Ref, - "refs/heads/", - ), - "refs/tags/", - ) - } - cfg, err := client.GetFile(r.Owner, r.Name, ref, f) - return cfg, err -} - -func (c *client) Dir(_ context.Context, _ *model.User, _ *model.Repo, _ *model.Pipeline, _ string) ([]*forge_types.FileMeta, error) { - return nil, forge_types.ErrNotImplemented -} - -// Status is not supported by the Gogs driver. -func (c *client) Status(_ context.Context, _ *model.User, _ *model.Repo, _ *model.Pipeline, _ *model.Step) error { - return nil -} - -// Netrc returns a netrc file capable of authenticating Gogs requests and -// cloning Gogs repositories. The netrc will use the global machine account -// when configured. -func (c *client) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { - host, err := common.ExtractHostFromCloneURL(r.Clone) - if err != nil { - return nil, err - } - - if c.Password != "" { - return &model.Netrc{ - Login: c.Username, - Password: c.Password, - Machine: host, - }, nil - } - return &model.Netrc{ - Login: u.Token, - Password: "x-oauth-basic", - Machine: host, - }, nil -} - -// Activate activates the repository by registering post-commit hooks with -// the Gogs repository. -func (c *client) Activate(_ context.Context, u *model.User, r *model.Repo, link string) error { - config := map[string]string{ - "url": link, - "secret": r.Hash, - "content_type": "json", - } - hook := gogs.CreateHookOption{ - Type: "gogs", - Config: config, - Events: []string{"push", "create", "pull_request"}, - Active: true, - } - - client := c.newClientToken(u.Token) - _, err := client.CreateRepoHook(r.Owner, r.Name, hook) - return err -} - -// Deactivate is not supported by the Gogs driver. -func (c *client) Deactivate(_ context.Context, _ *model.User, _ *model.Repo, _ string) error { - return nil -} - -// Branches returns the names of all branches for the named repository. -func (c *client) Branches(_ context.Context, u *model.User, r *model.Repo, _ *model.ListOptions) ([]string, error) { - token := "" - if u != nil { - token = u.Token - } - client := c.newClientToken(token) - gogsBranches, err := client.ListRepoBranches(r.Owner, r.Name) - if err != nil { - return nil, err - } - - branches := make([]string, 0) - for _, branch := range gogsBranches { - branches = append(branches, branch.Name) - } - return branches, nil -} - -// BranchHead returns sha of commit on top of the specified branch -func (c *client) BranchHead(_ context.Context, u *model.User, r *model.Repo, branch string) (string, error) { - token := "" - if u != nil { - token = u.Token - } - b, err := c.newClientToken(token).GetRepoBranch(r.Owner, r.Name, branch) - if err != nil { - return "", err - } - return b.Commit.ID, nil -} - -func (c *client) PullRequests(_ context.Context, _ *model.User, _ *model.Repo, _ *model.ListOptions) ([]*model.PullRequest, error) { - return nil, forge_types.ErrNotImplemented -} - -// Hook parses the incoming Gogs hook and returns the Repository and Pipeline -// details. If the hook is unsupported nil values are returned. -func (c *client) Hook(_ context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { - return parseHook(r) -} - -// OrgMembership returns if user is member of organization and if user -// is admin/owner in this organization. -func (c *client) OrgMembership(_ context.Context, u *model.User, owner string) (*model.OrgPerm, error) { - client := c.newClientToken(u.Token) - - orgs, err := client.ListMyOrgs() - if err != nil { - return nil, err - } - - for _, org := range orgs { - if org.UserName == owner { - // TODO: API does not support checking if user is admin/owner of org - return &model.OrgPerm{Member: true}, nil - } - } - return &model.OrgPerm{}, nil -} - -// helper function to return the Gogs client -func (c *client) newClient() *gogs.Client { - return c.newClientToken("") -} - -// helper function to return the Gogs client -func (c *client) newClientToken(token string) *gogs.Client { - client := gogs.NewClient(c.URL, token) - if c.SkipVerify { - httpClient := &http.Client{} - httpClient.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - client.SetHTTPClient(httpClient) - } - return client -} diff --git a/server/forge/gogs/gogs_test.go b/server/forge/gogs/gogs_test.go deleted file mode 100644 index 217ee6511..000000000 --- a/server/forge/gogs/gogs_test.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2022 Woodpecker Authors -// Copyright 2018 Drone.IO Inc. -// -// 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 gogs - -import ( - "context" - "net/http/httptest" - "testing" - - "github.com/franela/goblin" - "github.com/gin-gonic/gin" - - "github.com/woodpecker-ci/woodpecker/server/forge/gogs/fixtures" - "github.com/woodpecker-ci/woodpecker/server/model" -) - -func Test_gogs(t *testing.T) { - gin.SetMode(gin.TestMode) - - s := httptest.NewServer(fixtures.Handler()) - c, _ := New(Opts{ - URL: s.URL, - SkipVerify: true, - }) - - ctx := context.Background() - g := goblin.Goblin(t) - g.Describe("Gogs", func() { - g.After(func() { - s.Close() - }) - - g.Describe("Creating a forge", func() { - g.It("Should return client with specified options", func() { - forge, _ := New(Opts{ - URL: "http://localhost:8080", - Username: "someuser", - Password: "password", - SkipVerify: true, - }) - g.Assert(forge.(*client).URL).Equal("http://localhost:8080") - g.Assert(forge.(*client).Username).Equal("someuser") - g.Assert(forge.(*client).Password).Equal("password") - g.Assert(forge.(*client).SkipVerify).Equal(true) - }) - g.It("Should handle malformed url", func() { - _, err := New(Opts{URL: "%gh&%ij"}) - g.Assert(err).IsNotNil() - }) - }) - - g.Describe("Generating a netrc file", func() { - g.It("Should return a netrc with the user token", func() { - forge, _ := New(Opts{}) - netrc, _ := forge.Netrc(fakeUser, fakeRepo) - g.Assert(netrc.Machine).Equal("gogs.com") - g.Assert(netrc.Login).Equal(fakeUser.Token) - g.Assert(netrc.Password).Equal("x-oauth-basic") - }) - g.It("Should return a netrc with the machine account", func() { - forge, _ := New(Opts{ - Username: "someuser", - Password: "password", - }) - netrc, _ := forge.Netrc(nil, fakeRepo) - g.Assert(netrc.Machine).Equal("gogs.com") - g.Assert(netrc.Login).Equal("someuser") - g.Assert(netrc.Password).Equal("password") - }) - }) - - g.Describe("Requesting a repository", func() { - g.It("Should return the repository details", func() { - repo, err := c.Repo(ctx, fakeUser, fakeRepo.ForgeRemoteID, fakeRepo.Owner, fakeRepo.Name) - g.Assert(err).IsNil() - g.Assert(repo.Owner).Equal(fakeRepo.Owner) - g.Assert(repo.Name).Equal(fakeRepo.Name) - g.Assert(repo.FullName).Equal(fakeRepo.Owner + "/" + fakeRepo.Name) - g.Assert(repo.IsSCMPrivate).IsTrue() - g.Assert(repo.Clone).Equal("http://localhost/test_name/repo_name.git") - g.Assert(repo.Link).Equal("http://localhost/test_name/repo_name") - }) - g.It("Should handle a not found error", func() { - _, err := c.Repo(ctx, fakeUser, "0", fakeRepoNotFound.Owner, fakeRepoNotFound.Name) - g.Assert(err).IsNotNil() - }) - }) - - g.Describe("Requesting a repository list", func() { - g.It("Should return the repository list", func() { - repos, err := c.Repos(ctx, fakeUser) - g.Assert(err).IsNil() - g.Assert(repos[0].ForgeRemoteID).Equal(fakeRepo.ForgeRemoteID) - g.Assert(repos[0].Owner).Equal(fakeRepo.Owner) - g.Assert(repos[0].Name).Equal(fakeRepo.Name) - g.Assert(repos[0].FullName).Equal(fakeRepo.Owner + "/" + fakeRepo.Name) - }) - g.It("Should handle a not found error", func() { - _, err := c.Repos(ctx, fakeUserNoRepos) - g.Assert(err).IsNotNil() - }) - }) - - g.It("Should register repository hooks", func() { - err := c.Activate(ctx, fakeUser, fakeRepo, "http://localhost") - g.Assert(err).IsNil() - }) - - g.It("Should return a repository file", func() { - raw, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, ".woodpecker.yml") - g.Assert(err).IsNil() - g.Assert(string(raw)).Equal("{ platform: linux/amd64 }") - }) - - g.It("Should return a repository file from a ref", func() { - raw, err := c.File(ctx, fakeUser, fakeRepo, fakePipelineWithRef, ".woodpecker.yml") - g.Assert(err).IsNil() - g.Assert(string(raw)).Equal("{ platform: linux/amd64 }") - }) - - g.Describe("Given an authentication request", func() { - g.It("Should redirect to login form") - g.It("Should create an access token") - g.It("Should handle an access token error") - g.It("Should return the authenticated user") - }) - - g.Describe("Given a repository hook", func() { - g.It("Should skip non-push events") - g.It("Should return push details") - g.It("Should handle a parsing error") - }) - - g.It("Should return no-op for unsupported features", func() { - _, err1 := c.Auth(ctx, "octocat", "4vyW6b49Z") - err2 := c.Status(ctx, nil, nil, nil, nil) - err3 := c.Deactivate(ctx, nil, nil, "") - g.Assert(err1).IsNotNil() - g.Assert(err2).IsNil() - g.Assert(err3).IsNil() - }) - }) -} - -var ( - fakeUser = &model.User{ - Login: "someuser", - Token: "cfcd2084", - } - - fakeUserNoRepos = &model.User{ - Login: "someuser", - Token: "repos_not_found", - } - - fakeRepo = &model.Repo{ - ForgeRemoteID: "5", - Clone: "http://gogs.com/test_name/repo_name.git", - Owner: "test_name", - Name: "repo_name", - FullName: "test_name/repo_name", - } - - fakeRepoNotFound = &model.Repo{ - Owner: "test_name", - Name: "repo_not_found", - FullName: "test_name/repo_not_found", - } - - fakePipeline = &model.Pipeline{ - Commit: "9ecad50", - } - - fakePipelineWithRef = &model.Pipeline{ - Ref: "refs/tags/v1.0.0", - } -) diff --git a/server/forge/gogs/helper.go b/server/forge/gogs/helper.go deleted file mode 100644 index 7198ebe4e..000000000 --- a/server/forge/gogs/helper.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2022 Woodpecker Authors -// Copyright 2018 Drone.IO Inc. -// -// 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 gogs - -import ( - "encoding/json" - "fmt" - "io" - "net/url" - "strings" - "time" - - "github.com/gogits/go-gogs-client" - - "github.com/woodpecker-ci/woodpecker/server/model" -) - -// helper function that converts a Gogs repository to a Woodpecker repository. -func toRepo(from *gogs.Repository) *model.Repo { - name := strings.Split(from.FullName, "/")[1] - avatar := expandAvatar( - from.HTMLURL, - from.Owner.AvatarUrl, - ) - return &model.Repo{ - ForgeRemoteID: model.ForgeRemoteID(fmt.Sprint(from.ID)), - SCMKind: model.RepoGit, - Name: name, - Owner: from.Owner.UserName, - FullName: from.FullName, - Avatar: avatar, - Link: from.HTMLURL, - IsSCMPrivate: from.Private, - Clone: from.CloneURL, - Branch: from.DefaultBranch, - Perm: toPerm(from.Permissions), - } -} - -// helper function that converts a Gogs permission to a Woodpecker permission. -func toPerm(from *gogs.Permission) *model.Perm { - return &model.Perm{ - Pull: from.Pull, - Push: from.Push, - Admin: from.Admin, - } -} - -// helper function that converts a Gogs team to a Woodpecker team. -func toTeam(from *gogs.Organization, link string) *model.Team { - return &model.Team{ - Login: from.UserName, - Avatar: expandAvatar(link, from.AvatarUrl), - } -} - -// helper function that extracts the Pipeline data from a Gogs push hook -func pipelineFromPush(hook *pushHook) *model.Pipeline { - avatar := expandAvatar( - hook.Repo.HTMLURL, - fixMalformedAvatar(hook.Sender.AvatarUrl), - ) - author := hook.Sender.Login - if author == "" { - author = hook.Sender.UserName - } - sender := hook.Sender.UserName - if sender == "" { - sender = hook.Sender.Login - } - - return &model.Pipeline{ - Event: model.EventPush, - Commit: hook.After, - Ref: hook.Ref, - Link: hook.Compare, - Branch: strings.TrimPrefix(hook.Ref, "refs/heads/"), - Message: hook.Commits[0].Message, - Avatar: avatar, - Author: author, - Email: hook.Sender.Email, - Timestamp: time.Now().UTC().Unix(), - Sender: sender, - } -} - -// helper function that extracts the pipeline data from a Gogs tag hook -func pipelineFromTag(hook *pushHook) *model.Pipeline { - avatar := expandAvatar( - hook.Repo.HTMLURL, - fixMalformedAvatar(hook.Sender.AvatarUrl), - ) - author := hook.Sender.Login - if author == "" { - author = hook.Sender.UserName - } - sender := hook.Sender.UserName - if sender == "" { - sender = hook.Sender.Login - } - - return &model.Pipeline{ - Event: model.EventTag, - Commit: hook.After, - Ref: fmt.Sprintf("refs/tags/%s", hook.Ref), - Link: fmt.Sprintf("%s/src/%s", hook.Repo.HTMLURL, hook.Ref), - Branch: fmt.Sprintf("refs/tags/%s", hook.Ref), - Message: fmt.Sprintf("created tag %s", hook.Ref), - Avatar: avatar, - Author: author, - Sender: sender, - Timestamp: time.Now().UTC().Unix(), - } -} - -// helper function that extracts the Pipeline data from a Gogs pull_request hook -func pipelineFromPullRequest(hook *pullRequestHook) *model.Pipeline { - avatar := expandAvatar( - hook.Repo.HTMLURL, - fixMalformedAvatar(hook.PullRequest.User.AvatarUrl), - ) - sender := hook.Sender.UserName - if sender == "" { - sender = hook.Sender.Login - } - pipeline := &model.Pipeline{ - Event: model.EventPull, - Commit: hook.PullRequest.Head.Sha, - Link: hook.PullRequest.URL, - Ref: fmt.Sprintf("refs/pull/%d/head", hook.Number), - Branch: hook.PullRequest.BaseBranch, - Message: hook.PullRequest.Title, - Author: hook.PullRequest.User.UserName, - Avatar: avatar, - Sender: sender, - Title: hook.PullRequest.Title, - Refspec: fmt.Sprintf("%s:%s", - hook.PullRequest.HeadBranch, - hook.PullRequest.BaseBranch, - ), - } - return pipeline -} - -// helper function that parses a push hook from a read closer. -func parsePush(r io.Reader) (*pushHook, error) { - push := new(pushHook) - err := json.NewDecoder(r).Decode(push) - return push, err -} - -func parsePullRequest(r io.Reader) (*pullRequestHook, error) { - pr := new(pullRequestHook) - err := json.NewDecoder(r).Decode(pr) - return pr, err -} - -// fixMalformedAvatar is a helper function that fixes an avatar url if malformed -// (currently a known bug with gogs) -func fixMalformedAvatar(url string) string { - index := strings.Index(url, "///") - if index != -1 { - return url[index+1:] - } - index = strings.Index(url, "//avatars/") - if index != -1 { - return strings.Replace(url, "//avatars/", "/avatars/", -1) - } - return url -} - -// expandAvatar is a helper function that converts a relative avatar URL to the -// absolute url. -func expandAvatar(repo, rawurl string) string { - aurl, err := url.Parse(rawurl) - if err != nil { - return rawurl - } - if aurl.IsAbs() { - // Url is already absolute - return aurl.String() - } - - // Resolve to base - burl, err := url.Parse(repo) - if err != nil { - return rawurl - } - aurl = burl.ResolveReference(aurl) - - return aurl.String() -} diff --git a/server/forge/gogs/helper_test.go b/server/forge/gogs/helper_test.go deleted file mode 100644 index 9749a2f52..000000000 --- a/server/forge/gogs/helper_test.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2022 Woodpecker Authors -// Copyright 2018 Drone.IO Inc. -// -// 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 gogs - -import ( - "bytes" - "testing" - - "github.com/franela/goblin" - "github.com/gogits/go-gogs-client" - - "github.com/woodpecker-ci/woodpecker/server/forge/gogs/fixtures" - "github.com/woodpecker-ci/woodpecker/server/model" -) - -func Test_parse(t *testing.T) { - g := goblin.Goblin(t) - g.Describe("Gogs", func() { - g.It("Should parse push hook payload", func() { - buf := bytes.NewBufferString(fixtures.HookPush) - hook, err := parsePush(buf) - g.Assert(err).IsNil() - g.Assert(hook.Ref).Equal("refs/heads/master") - g.Assert(hook.After).Equal("ef98532add3b2feb7a137426bba1248724367df5") - g.Assert(hook.Before).Equal("4b2626259b5a97b6b4eab5e6cca66adb986b672b") - g.Assert(hook.Compare).Equal("http://gogs.golang.org/gordon/hello-world/compare/4b2626259b5a97b6b4eab5e6cca66adb986b672b...ef98532add3b2feb7a137426bba1248724367df5") - g.Assert(hook.Repo.Name).Equal("hello-world") - g.Assert(hook.Repo.HTMLURL).Equal("http://gogs.golang.org/gordon/hello-world") - g.Assert(hook.Repo.FullName).Equal("gordon/hello-world") - g.Assert(hook.Repo.Owner.Email).Equal("gordon@golang.org") - g.Assert(hook.Repo.Owner.UserName).Equal("gordon") - g.Assert(hook.Repo.Private).Equal(true) - g.Assert(hook.Pusher.Email).Equal("gordon@golang.org") - g.Assert(hook.Pusher.UserName).Equal("gordon") - g.Assert(hook.Sender.Login).Equal("gordon") - g.Assert(hook.Sender.AvatarUrl).Equal("http://gogs.golang.org///1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") - }) - - g.It("Should parse tag hook payload", func() { - buf := bytes.NewBufferString(fixtures.HookPushTag) - hook, err := parsePush(buf) - g.Assert(err).IsNil() - g.Assert(hook.Ref).Equal("v1.0.0") - g.Assert(hook.Repo.Name).Equal("hello-world") - g.Assert(hook.Repo.HTMLURL).Equal("http://gogs.golang.org/gordon/hello-world") - g.Assert(hook.Repo.FullName).Equal("gordon/hello-world") - g.Assert(hook.Repo.Owner.Email).Equal("gordon@golang.org") - g.Assert(hook.Repo.Owner.UserName).Equal("gordon") - g.Assert(hook.Repo.Private).Equal(true) - g.Assert(hook.Sender.UserName).Equal("gordon") - g.Assert(hook.Sender.AvatarUrl).Equal("https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") - }) - - g.It("Should parse pull_request hook payload", func() { - buf := bytes.NewBufferString(fixtures.HookPullRequest) - hook, err := parsePullRequest(buf) - g.Assert(err).IsNil() - g.Assert(hook.Action).Equal("opened") - g.Assert(hook.Number).Equal(int64(1)) - - g.Assert(hook.Repo.Name).Equal("hello-world") - g.Assert(hook.Repo.HTMLURL).Equal("http://gogs.golang.org/gordon/hello-world") - g.Assert(hook.Repo.FullName).Equal("gordon/hello-world") - g.Assert(hook.Repo.Owner.Email).Equal("gordon@golang.org") - g.Assert(hook.Repo.Owner.UserName).Equal("gordon") - g.Assert(hook.Repo.Private).Equal(true) - g.Assert(hook.Sender.UserName).Equal("gordon") - g.Assert(hook.Sender.AvatarUrl).Equal("https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") - - g.Assert(hook.PullRequest.Title).Equal("Update the README with new information") - g.Assert(hook.PullRequest.Body).Equal("please merge") - g.Assert(hook.PullRequest.State).Equal("open") - g.Assert(hook.PullRequest.User.UserName).Equal("gordon") - g.Assert(hook.PullRequest.Base.Label).Equal("master") - g.Assert(hook.PullRequest.Base.Ref).Equal("master") - g.Assert(hook.PullRequest.Head.Label).Equal("feature/changes") - g.Assert(hook.PullRequest.Head.Ref).Equal("feature/changes") - }) - - g.It("Should return a Pipeline struct from a push hook", func() { - buf := bytes.NewBufferString(fixtures.HookPush) - hook, _ := parsePush(buf) - pipeline := pipelineFromPush(hook) - g.Assert(pipeline.Event).Equal(model.EventPush) - g.Assert(pipeline.Commit).Equal(hook.After) - g.Assert(pipeline.Ref).Equal(hook.Ref) - g.Assert(pipeline.Link).Equal(hook.Compare) - g.Assert(pipeline.Branch).Equal("master") - g.Assert(pipeline.Message).Equal(hook.Commits[0].Message) - g.Assert(pipeline.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") - g.Assert(pipeline.Author).Equal(hook.Sender.Login) - }) - - g.It("Should return a Repo struct from a push hook", func() { - buf := bytes.NewBufferString(fixtures.HookPush) - hook, _ := parsePush(buf) - repo := toRepo(hook.Repo) - g.Assert(repo.Name).Equal(hook.Repo.Name) - g.Assert(repo.Owner).Equal(hook.Repo.Owner.UserName) - g.Assert(repo.FullName).Equal("gordon/hello-world") - g.Assert(repo.Link).Equal(hook.Repo.HTMLURL) - }) - - g.It("Should return a Pipeline struct from a pull_request hook", func() { - buf := bytes.NewBufferString(fixtures.HookPullRequest) - hook, _ := parsePullRequest(buf) - pipeline := pipelineFromPullRequest(hook) - g.Assert(pipeline.Event).Equal(model.EventPull) - g.Assert(pipeline.Commit).Equal(hook.PullRequest.Head.Sha) - g.Assert(pipeline.Ref).Equal("refs/pull/1/head") - g.Assert(pipeline.Link).Equal(hook.PullRequest.URL) - g.Assert(pipeline.Branch).Equal("master") - g.Assert(pipeline.Message).Equal(hook.PullRequest.Title) - g.Assert(pipeline.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") - g.Assert(pipeline.Author).Equal(hook.PullRequest.User.UserName) - }) - - g.It("Should return a Repo struct from a pull_request hook", func() { - buf := bytes.NewBufferString(fixtures.HookPullRequest) - hook, _ := parsePullRequest(buf) - repo := toRepo(hook.Repo) - g.Assert(repo.Name).Equal(hook.Repo.Name) - g.Assert(repo.Owner).Equal(hook.Repo.Owner.UserName) - g.Assert(repo.FullName).Equal("gordon/hello-world") - g.Assert(repo.Link).Equal(hook.Repo.HTMLURL) - }) - - g.It("Should return a Perm struct from a Gogs Perm", func() { - perms := []*gogs.Permission{ - {Admin: true, Pull: true, Push: true}, - {Admin: true, Pull: true, Push: false}, - {Admin: true, Push: false, Pull: false}, - } - for _, from := range perms { - perm := toPerm(from) - g.Assert(perm.Pull).Equal(from.Pull) - g.Assert(perm.Push).Equal(from.Push) - g.Assert(perm.Admin).Equal(from.Admin) - } - }) - - g.It("Should return a Team struct from a Gogs Org", func() { - from := &gogs.Organization{ - UserName: "woodpecker", - AvatarUrl: "/avatars/1", - } - - to := toTeam(from, "http://localhost:80") - g.Assert(to.Login).Equal(from.UserName) - g.Assert(to.Avatar).Equal("http://localhost:80/avatars/1") - }) - - g.It("Should return a Repo struct from a Gogs Repo", func() { - from := gogs.Repository{ - FullName: "gophers/hello-world", - Owner: &gogs.User{ - UserName: "gordon", - AvatarUrl: "http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87", - }, - CloneURL: "http://gogs.golang.org/gophers/hello-world.git", - HTMLURL: "http://gogs.golang.org/gophers/hello-world", - Private: true, - DefaultBranch: "master", - Permissions: &gogs.Permission{Admin: true}, - } - repo := toRepo(&from) - g.Assert(repo.FullName).Equal(from.FullName) - g.Assert(repo.Owner).Equal(from.Owner.UserName) - g.Assert(repo.Name).Equal("hello-world") - g.Assert(repo.Branch).Equal("master") - g.Assert(repo.Link).Equal(from.HTMLURL) - g.Assert(repo.Clone).Equal(from.CloneURL) - g.Assert(repo.Avatar).Equal(from.Owner.AvatarUrl) - g.Assert(repo.IsSCMPrivate).Equal(from.Private) - g.Assert(repo.Perm.Admin).IsTrue() - }) - - g.It("Should correct a malformed avatar url", func() { - urls := []struct { - Before string - After string - }{ - { - "http://gogs.golang.org///1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87", - "//1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87", - }, - { - "//1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87", - "//1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87", - }, - { - "http://gogs.golang.org/avatars/1", - "http://gogs.golang.org/avatars/1", - }, - { - "http://gogs.golang.org//avatars/1", - "http://gogs.golang.org/avatars/1", - }, - } - - for _, url := range urls { - got := fixMalformedAvatar(url.Before) - g.Assert(got).Equal(url.After) - } - }) - - g.It("Should expand the avatar url", func() { - urls := []struct { - Before string - After string - }{ - { - "/avatars/1", - "http://gogs.io/avatars/1", - }, - { - "//1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87", - "http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87", - }, - { - "/gogs/avatars/2", - "http://gogs.io/gogs/avatars/2", - }, - } - - repo := "http://gogs.io/foo/bar" - for _, url := range urls { - got := expandAvatar(repo, url.Before) - g.Assert(got).Equal(url.After) - } - }) - }) -} diff --git a/server/forge/gogs/parse.go b/server/forge/gogs/parse.go deleted file mode 100644 index 1ab4455eb..000000000 --- a/server/forge/gogs/parse.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2022 Woodpecker Authors -// Copyright 2018 Drone.IO Inc. -// -// 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 gogs - -import ( - "io" - "net/http" - - "github.com/woodpecker-ci/woodpecker/server/model" -) - -const ( - hookEvent = "X-Gogs-Event" - hookPush = "push" - hookCreated = "create" - hookPullRequest = "pull_request" - - actionOpen = "opened" - actionSync = "synchronized" - - stateOpen = "open" - - refBranch = "branch" - refTag = "tag" -) - -// parseHook parses a Bitbucket hook from an http.Request request and returns -// Repo and Pipeline detail. If a hook type is unsupported nil values are returned. -func parseHook(r *http.Request) (*model.Repo, *model.Pipeline, error) { - switch r.Header.Get(hookEvent) { - case hookPush: - return parsePushHook(r.Body) - case hookCreated: - return parseCreatedHook(r.Body) - case hookPullRequest: - return parsePullRequestHook(r.Body) - } - return nil, nil, nil -} - -// parsePushHook parses a push hook and returns the Repo and Pipeline details. -// If the commit type is unsupported nil values are returned. -func parsePushHook(payload io.Reader) (*model.Repo, *model.Pipeline, error) { - var ( - repo *model.Repo - pipeline *model.Pipeline - ) - - push, err := parsePush(payload) - if err != nil { - return nil, nil, err - } - - // is this even needed? - if push.RefType == refBranch { - return nil, nil, nil - } - - repo = toRepo(push.Repo) - pipeline = pipelineFromPush(push) - return repo, pipeline, err -} - -// parseCreatedHook parses a push hook and returns the Repo and Pipeline details. -// If the commit type is unsupported nil values are returned. -func parseCreatedHook(payload io.Reader) (*model.Repo, *model.Pipeline, error) { - var ( - repo *model.Repo - pipeline *model.Pipeline - ) - - push, err := parsePush(payload) - if err != nil { - return nil, nil, err - } - - if push.RefType != refTag { - return nil, nil, nil - } - - repo = toRepo(push.Repo) - pipeline = pipelineFromTag(push) - return repo, pipeline, err -} - -// parsePullRequestHook parses a pull_request hook and returns the Repo and Pipeline details. -func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Pipeline, error) { - var ( - repo *model.Repo - pipeline *model.Pipeline - ) - - pr, err := parsePullRequest(payload) - if err != nil { - return nil, nil, err - } - - // Don't trigger pipelines for non-code changes, or if PR is not open - if pr.Action != actionOpen && pr.Action != actionSync { - return nil, nil, nil - } - if pr.PullRequest.State != stateOpen { - return nil, nil, nil - } - - repo = toRepo(pr.Repo) - pipeline = pipelineFromPullRequest(pr) - return repo, pipeline, err -} diff --git a/server/forge/gogs/types.go b/server/forge/gogs/types.go deleted file mode 100644 index fa63e9e99..000000000 --- a/server/forge/gogs/types.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2022 Woodpecker Authors -// Copyright 2018 Drone.IO Inc. -// -// 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 gogs - -import "github.com/gogits/go-gogs-client" - -type pushHook struct { - Ref string `json:"ref"` - Before string `json:"before"` - After string `json:"after"` - Compare string `json:"compare_url"` - RefType string `json:"ref_type"` - - Pusher *gogs.User `json:"pusher"` - - Repo *gogs.Repository `json:"repository"` - - Commits []gogs.PayloadCommit `json:"commits"` - - Sender *gogs.User `json:"sender"` -} - -type pullRequestHook struct { - Action string `json:"action"` - Number int64 `json:"number"` - PullRequest struct { - ID int64 `json:"id"` - User *gogs.User `json:"user"` - Title string `json:"title"` - Body string `json:"body"` - State string `json:"state"` - URL string `json:"html_url"` - Mergeable bool `json:"mergeable"` - Merged bool `json:"merged"` - MergeBase string `json:"merge_base"` - BaseBranch string `json:"base_branch"` - Base struct { - Label string `json:"label"` - Ref string `json:"ref"` - Sha string `json:"sha"` - Repo *gogs.Repository `json:"repo"` - } `json:"base"` - HeadBranch string `json:"head_branch"` - Head struct { - Label string `json:"label"` - Ref string `json:"ref"` - Sha string `json:"sha"` - Repo *gogs.Repository `json:"repo"` - } `json:"head"` - } `json:"pull_request"` - Repo *gogs.Repository `json:"repository"` - Sender *gogs.User `json:"sender"` -}