mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-30 12:20:33 +00:00
Drop Gogs support (#1752)
Gogs support is broken (and we won't fix it because we don't care about
it...) because it does not support OAuth, at least after we introduced
the new Vue UI.
See:
77d830d5b5/server/forge/gogs/gogs.go (L84)
This route is not present in the new UI.
This commit is contained in:
parent
fb5b259856
commit
2ccf7c6f1a
16 changed files with 15 additions and 1570 deletions
|
@ -318,37 +318,6 @@ var flags = []cli.Flag{
|
||||||
Usage: "github skip ssl verification",
|
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
|
// Gitea
|
||||||
//
|
//
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
|
|
|
@ -42,7 +42,6 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/forge/gitea"
|
"github.com/woodpecker-ci/woodpecker/server/forge/gitea"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/forge/github"
|
"github.com/woodpecker-ci/woodpecker/server/forge/github"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/forge/gitlab"
|
"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/model"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/plugins/environments"
|
"github.com/woodpecker-ci/woodpecker/server/plugins/environments"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/plugins/registry"
|
"github.com/woodpecker-ci/woodpecker/server/plugins/registry"
|
||||||
|
@ -196,8 +195,6 @@ func setupForge(c *cli.Context) (forge.Forge, error) {
|
||||||
return setupBitbucket(c)
|
return setupBitbucket(c)
|
||||||
case c.Bool("stash"):
|
case c.Bool("stash"):
|
||||||
return setupStash(c)
|
return setupStash(c)
|
||||||
case c.Bool("gogs"):
|
|
||||||
return setupGogs(c)
|
|
||||||
case c.Bool("gitea"):
|
case c.Bool("gitea"):
|
||||||
return setupGitea(c)
|
return setupGitea(c)
|
||||||
default:
|
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) {
|
func setupBitbucket(c *cli.Context) (forge.Forge, error) {
|
||||||
opts := &bitbucket.Opts{
|
opts := &bitbucket.Opts{
|
||||||
Client: c.String("bitbucket-client"),
|
Client: c.String("bitbucket-client"),
|
||||||
|
@ -215,19 +212,7 @@ func setupBitbucket(c *cli.Context) (forge.Forge, error) {
|
||||||
return bitbucket.New(opts)
|
return bitbucket.New(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function to setup the Gogs forge from the CLI arguments.
|
// setupGitea helper function to setup the Gitea 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.
|
|
||||||
func setupGitea(c *cli.Context) (forge.Forge, error) {
|
func setupGitea(c *cli.Context) (forge.Forge, error) {
|
||||||
server, err := url.Parse(c.String("gitea-server"))
|
server, err := url.Parse(c.String("gitea-server"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -246,7 +231,7 @@ func setupGitea(c *cli.Context) (forge.Forge, error) {
|
||||||
return gitea.New(opts)
|
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) {
|
func setupStash(c *cli.Context) (forge.Forge, error) {
|
||||||
opts := bitbucketserver.Opts{
|
opts := bitbucketserver.Opts{
|
||||||
URL: c.String("stash-server"),
|
URL: c.String("stash-server"),
|
||||||
|
@ -261,7 +246,7 @@ func setupStash(c *cli.Context) (forge.Forge, error) {
|
||||||
return bitbucketserver.New(opts)
|
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) {
|
func setupGitLab(c *cli.Context) (forge.Forge, error) {
|
||||||
return gitlab.New(gitlab.Opts{
|
return gitlab.New(gitlab.Opts{
|
||||||
URL: c.String("gitlab-server"),
|
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) {
|
func setupGitHub(c *cli.Context) (forge.Forge, error) {
|
||||||
opts := github.Opts{
|
opts := github.Opts{
|
||||||
URL: c.String("github-server"),
|
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) {
|
func setupSignatureKeys(_store store.Store) (crypto.PrivateKey, crypto.PublicKey) {
|
||||||
privKeyID := "signature-private-key"
|
privKeyID := "signature-private-key"
|
||||||
|
|
||||||
|
|
|
@ -422,10 +422,6 @@ Example: `WOODPECKER_ROOT_URL=/woodpecker`
|
||||||
|
|
||||||
See [GitHub configuration](forges/github/#configuration)
|
See [GitHub configuration](forges/github/#configuration)
|
||||||
|
|
||||||
### `WOODPECKER_GOGS_...`
|
|
||||||
|
|
||||||
See [Gogs configuration](forges/gogs/#configuration)
|
|
||||||
|
|
||||||
### `WOODPECKER_GITEA_...`
|
### `WOODPECKER_GITEA_...`
|
||||||
|
|
||||||
See [Gitea configuration](forges/gitea/#configuration)
|
See [Gitea configuration](forges/gitea/#configuration)
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
|
|
||||||
## Supported features
|
## Supported features
|
||||||
|
|
||||||
| Feature | [GitHub](github/) | [Gitea / Forgejo](gitea/) | [Gitlab](gitlab/) | [Bitbucket](bitbucket/) | [Bitbucket Server](bitbucket_server/) | [Gogs](gogs/) |
|
| 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: | :white_check_mark: |
|
| 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: | :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: | :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: | :x: |
|
| Event: Deploy | :white_check_mark: | :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: |
|
||||||
| [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: |
|
||||||
| [when.path filter](../../20-usage/20-pipeline-syntax.md#path) | :white_check_mark: | :white_check_mark:¹ | :white_check_mark: | :x: | :x: | :x: |
|
|
||||||
|
|
||||||
¹ for pull requests at least Gitea version 1.17 is required
|
¹ for pull requests at least Gitea version 1.17 is required
|
||||||
|
|
|
@ -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.
|
|
|
@ -15,9 +15,8 @@ Some versions need some changes to the server configuration or the pipeline conf
|
||||||
- Updated Prometheus gauge `*_job_*` to `*_step_*`
|
- Updated Prometheus gauge `*_job_*` to `*_step_*`
|
||||||
- Renamed config env `WOODPECKER_MAX_PROCS` to `WOODPECKER_MAX_WORKFLOWS` (still available as fallback)
|
- 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`
|
- 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`
|
- `/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
|
## 0.15.0
|
||||||
|
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -20,7 +20,6 @@ require (
|
||||||
github.com/gin-gonic/gin v1.9.0
|
github.com/gin-gonic/gin v1.9.0
|
||||||
github.com/go-ap/httpsig v0.0.0-20221203064646-3647b4d88fdf
|
github.com/go-ap/httpsig v0.0.0-20221203064646-3647b4d88fdf
|
||||||
github.com/go-sql-driver/mysql v1.7.1
|
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/golang-jwt/jwt/v4 v4.5.0
|
||||||
github.com/google/go-github/v39 v39.2.0
|
github.com/google/go-github/v39 v39.2.0
|
||||||
github.com/google/tink/go v1.7.0
|
github.com/google/tink/go v1.7.0
|
||||||
|
|
2
go.sum
2
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/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 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/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/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.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
`
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}`
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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",
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -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()
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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"`
|
|
||||||
}
|
|
Loading…
Reference in a new issue