mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-25 11:21:02 +00:00
Use forge from db (#1417)
This is the first step towards support for multiple forges (#138). It inserts a forge using the currently existing env varaibles into db and uses this forge from db later on in all places of the code. closes #621 addresses #138 # TODO - [x] add forges table - [x] add id of forge to repo - [x] use forge of repo - [x] add forge from env vars to db if not exists - [x] migrate repo.ForgeID to the newly generated forge - [x] support cache with forge from repo - [x] maybe add forge loading cache? (use LRU cache for forges, I expect users to have less than 10 forges normally) --------- Co-authored-by: qwerty287 <80460567+qwerty287@users.noreply.github.com>
This commit is contained in:
parent
0a38fb89db
commit
d494b6a959
48 changed files with 1291 additions and 405 deletions
|
@ -3891,6 +3891,9 @@ const docTemplate = `{
|
|||
"Org": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"forge_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
@ -4122,6 +4125,9 @@ const docTemplate = `{
|
|||
"default_branch": {
|
||||
"type": "string"
|
||||
},
|
||||
"forge_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"forge_remote_id": {
|
||||
"description": "ForgeRemoteID is the unique identifier for the repository on the forge.",
|
||||
"type": "string"
|
||||
|
@ -4418,6 +4424,9 @@ const docTemplate = `{
|
|||
"description": "Email is the email address for this user.\n\nrequired: true",
|
||||
"type": "string"
|
||||
},
|
||||
"forge_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"description": "the id for this user.\n\nrequired: true",
|
||||
"type": "integer"
|
||||
|
|
|
@ -246,11 +246,6 @@ var flags = append([]cli.Flag{
|
|||
Usage: "Disable version check in admin web ui.",
|
||||
Name: "skip-version-check",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_ADDON_FORGE"},
|
||||
Name: "addon-forge",
|
||||
Usage: "forge addon",
|
||||
},
|
||||
//
|
||||
// backend options for pipeline compiler
|
||||
//
|
||||
|
@ -309,6 +304,35 @@ var flags = append([]cli.Flag{
|
|||
Usage: "set the cpus allowed to execute containers",
|
||||
},
|
||||
//
|
||||
&cli.StringFlag{
|
||||
Name: "forge-url",
|
||||
Usage: "url of the forge",
|
||||
EnvVars: []string{"WOODPECKER_FORGE_URL", "WOODPECKER_GITHUB_URL", "WOODPECKER_GITLAB_URL", "WOODPECKER_GITEA_URL", "WOODPECKER_BITBUCKET_URL"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "forge-oauth-client",
|
||||
Usage: "oauth2 client id",
|
||||
EnvVars: []string{"WOODPECKER_FORGE_CLIENT", "WOODPECKER_GITHUB_CLIENT", "WOODPECKER_GITLAB_CLIENT", "WOODPECKER_GITEA_CLIENT", "WOODPECKER_BITBUCKET_CLIENT", "WOODPECKER_BITBUCKET_DC_CLIENT_ID"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "forge-oauth-secret",
|
||||
Usage: "oauth2 client secret",
|
||||
EnvVars: []string{"WOODPECKER_FORGE_SECRET", "WOODPECKER_GITHUB_SECRET", "WOODPECKER_GITLAB_SECRET", "WOODPECKER_GITEA_SECRET", "WOODPECKER_BITBUCKET_SECRET", "WOODPECKER_BITBUCKET_DC_CLIENT_SECRET"},
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "forge-skip-verify",
|
||||
Usage: "skip ssl verification",
|
||||
EnvVars: []string{"WOODPECKER_FORGE_SKIP_VERIFY", "WOODPECKER_GITHUB_SKIP_VERIFY", "WOODPECKER_GITLAB_SKIP_VERIFY", "WOODPECKER_GITEA_SKIP_VERIFY", "WOODPECKER_BITBUCKET_SKIP_VERIFY"},
|
||||
},
|
||||
//
|
||||
// Addon
|
||||
//
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_ADDON_FORGE"},
|
||||
Name: "addon-forge",
|
||||
Usage: "path to forge addon executable",
|
||||
},
|
||||
//
|
||||
// GitHub
|
||||
//
|
||||
&cli.BoolFlag{
|
||||
|
@ -316,24 +340,6 @@ var flags = append([]cli.Flag{
|
|||
Name: "github",
|
||||
Usage: "github driver is enabled",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITHUB_URL"},
|
||||
Name: "github-server",
|
||||
Usage: "github server address",
|
||||
Value: "https://github.com",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITHUB_CLIENT"},
|
||||
Name: "github-client",
|
||||
Usage: "github oauth2 client id",
|
||||
FilePath: os.Getenv("WOODPECKER_GITHUB_CLIENT_FILE"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITHUB_SECRET"},
|
||||
Name: "github-secret",
|
||||
Usage: "github oauth2 client secret",
|
||||
FilePath: os.Getenv("WOODPECKER_GITHUB_SECRET_FILE"),
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITHUB_MERGE_REF"},
|
||||
Name: "github-merge-ref",
|
||||
|
@ -346,11 +352,6 @@ var flags = append([]cli.Flag{
|
|||
Usage: "github tokens should only get access to public repos",
|
||||
Value: false,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITHUB_SKIP_VERIFY"},
|
||||
Name: "github-skip-verify",
|
||||
Usage: "github skip ssl verification",
|
||||
},
|
||||
//
|
||||
// Gitea
|
||||
//
|
||||
|
@ -359,29 +360,6 @@ var flags = append([]cli.Flag{
|
|||
Name: "gitea",
|
||||
Usage: "gitea driver is enabled",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITEA_URL"},
|
||||
Name: "gitea-server",
|
||||
Usage: "gitea server address",
|
||||
Value: "https://try.gitea.io",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITEA_CLIENT"},
|
||||
Name: "gitea-client",
|
||||
Usage: "gitea oauth2 client id",
|
||||
FilePath: os.Getenv("WOODPECKER_GITEA_CLIENT_FILE"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITEA_SECRET"},
|
||||
Name: "gitea-secret",
|
||||
Usage: "gitea oauth2 client secret",
|
||||
FilePath: os.Getenv("WOODPECKER_GITEA_SECRET_FILE"),
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITEA_SKIP_VERIFY"},
|
||||
Name: "gitea-skip-verify",
|
||||
Usage: "gitea skip ssl verification",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_DEV_GITEA_OAUTH_URL"},
|
||||
Name: "gitea-oauth-server",
|
||||
|
@ -395,18 +373,6 @@ var flags = append([]cli.Flag{
|
|||
Name: "bitbucket",
|
||||
Usage: "bitbucket driver is enabled",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BITBUCKET_CLIENT"},
|
||||
Name: "bitbucket-client",
|
||||
Usage: "bitbucket oauth2 client id",
|
||||
FilePath: os.Getenv("WOODPECKER_BITBUCKET_CLIENT_FILE"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BITBUCKET_SECRET"},
|
||||
Name: "bitbucket-secret",
|
||||
Usage: "bitbucket oauth2 client secret",
|
||||
FilePath: os.Getenv("WOODPECKER_BITBUCKET_SECRET_FILE"),
|
||||
},
|
||||
//
|
||||
// Gitlab
|
||||
//
|
||||
|
@ -415,29 +381,6 @@ var flags = append([]cli.Flag{
|
|||
Name: "gitlab",
|
||||
Usage: "gitlab driver is enabled",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITLAB_URL"},
|
||||
Name: "gitlab-server",
|
||||
Usage: "gitlab server address",
|
||||
Value: "https://gitlab.com",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITLAB_CLIENT"},
|
||||
Name: "gitlab-client",
|
||||
Usage: "gitlab oauth2 client id",
|
||||
FilePath: os.Getenv("WOODPECKER_GITLAB_CLIENT_FILE"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITLAB_SECRET"},
|
||||
Name: "gitlab-secret",
|
||||
Usage: "gitlab oauth2 client secret",
|
||||
FilePath: os.Getenv("WOODPECKER_GITLAB_SECRET_FILE"),
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
EnvVars: []string{"WOODPECKER_GITLAB_SKIP_VERIFY"},
|
||||
Name: "gitlab-skip-verify",
|
||||
Usage: "gitlab skip ssl verification",
|
||||
},
|
||||
//
|
||||
// Bitbucket DataCenter/Server (previously Stash)
|
||||
//
|
||||
|
@ -446,23 +389,6 @@ var flags = append([]cli.Flag{
|
|||
Name: "bitbucket-dc",
|
||||
Usage: "Bitbucket DataCenter/Server driver is enabled",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BITBUCKET_DC_URL"},
|
||||
Name: "bitbucket-dc-server",
|
||||
Usage: "Bitbucket DataCenter/Server server address",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BITBUCKET_DC_CLIENT_ID"},
|
||||
Name: "bitbucket-dc-client-id",
|
||||
Usage: "Bitbucket DataCenter/Server OAuth 2.0 client id",
|
||||
FilePath: os.Getenv("WOODPECKER_BITBUCKET_DC_CLIENT_ID_FILE"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BITBUCKET_DC_CLIENT_SECRET"},
|
||||
Name: "bitbucket-dc-client-secret",
|
||||
Usage: "Bitbucket DataCenter/Server OAuth 2.0 client secret",
|
||||
FilePath: os.Getenv("WOODPECKER_BITBUCKET_DC_CLIENT_SECRET_FILE"),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_BITBUCKET_DC_GIT_USERNAME"},
|
||||
Name: "bitbucket-dc-git-username",
|
||||
|
|
|
@ -38,7 +38,7 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/cron"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/setup"
|
||||
woodpeckerGrpcServer "go.woodpecker-ci.org/woodpecker/v2/server/grpc"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/logging"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
|
@ -82,11 +82,6 @@ func run(c *cli.Context) error {
|
|||
)
|
||||
}
|
||||
|
||||
_forge, err := setupForge(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't setup forge: %w", err)
|
||||
}
|
||||
|
||||
_store, err := setupStore(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't setup store: %w", err)
|
||||
|
@ -97,7 +92,7 @@ func run(c *cli.Context) error {
|
|||
}
|
||||
}()
|
||||
|
||||
err = setupEvilGlobals(c, _store, _forge)
|
||||
err = setupEvilGlobals(c, _store)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't setup globals: %w", err)
|
||||
}
|
||||
|
@ -107,7 +102,7 @@ func run(c *cli.Context) error {
|
|||
setupMetrics(&g, _store)
|
||||
|
||||
g.Go(func() error {
|
||||
return cron.Start(c.Context, _store, _forge)
|
||||
return cron.Start(c.Context, _store)
|
||||
})
|
||||
|
||||
// start the grpc server
|
||||
|
@ -130,7 +125,6 @@ func run(c *cli.Context) error {
|
|||
)
|
||||
|
||||
woodpeckerServer := woodpeckerGrpcServer.NewWoodpeckerServer(
|
||||
_forge,
|
||||
server.Config.Services.Queue,
|
||||
server.Config.Services.Logs,
|
||||
server.Config.Services.Pubsub,
|
||||
|
@ -270,17 +264,13 @@ func run(c *cli.Context) error {
|
|||
return g.Wait()
|
||||
}
|
||||
|
||||
func setupEvilGlobals(c *cli.Context, s store.Store, f forge.Forge) error {
|
||||
// forge
|
||||
server.Config.Services.Forge = f
|
||||
|
||||
func setupEvilGlobals(c *cli.Context, s store.Store) error {
|
||||
// services
|
||||
server.Config.Services.Queue = setupQueue(c, s)
|
||||
server.Config.Services.Logs = logging.New()
|
||||
server.Config.Services.Pubsub = pubsub.New()
|
||||
server.Config.Services.Membership = setupMembershipService(c, f)
|
||||
|
||||
serviceMangager, err := services.NewManager(c, s)
|
||||
server.Config.Services.Membership = setupMembershipService(c, s)
|
||||
serviceMangager, err := services.NewManager(c, s, setup.Forge)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not setup service manager: %w", err)
|
||||
}
|
||||
|
|
|
@ -18,9 +18,7 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
@ -31,13 +29,6 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/cache"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/addon"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/bitbucket"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/bitbucketdatacenter"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/gitea"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/github"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/gitlab"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/queue"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/store/datastore"
|
||||
|
@ -100,103 +91,8 @@ func setupQueue(c *cli.Context, s store.Store) queue.Queue {
|
|||
return queue.WithTaskStore(queue.New(c.Context), s)
|
||||
}
|
||||
|
||||
func setupMembershipService(_ *cli.Context, r forge.Forge) cache.MembershipService {
|
||||
return cache.NewMembershipService(r)
|
||||
}
|
||||
|
||||
// setupForge helper function to set up the forge from the CLI arguments.
|
||||
func setupForge(c *cli.Context) (forge.Forge, error) {
|
||||
switch {
|
||||
case c.String("addon-forge") != "":
|
||||
return addon.Load(c.String("addon-forge"))
|
||||
case c.Bool("github"):
|
||||
return setupGitHub(c)
|
||||
case c.Bool("gitlab"):
|
||||
return setupGitLab(c)
|
||||
case c.Bool("bitbucket"):
|
||||
return setupBitbucket(c)
|
||||
case c.Bool("bitbucket-dc"):
|
||||
return setupBitbucketDatacenter(c)
|
||||
case c.Bool("gitea"):
|
||||
return setupGitea(c)
|
||||
default:
|
||||
return nil, fmt.Errorf("version control system not configured")
|
||||
}
|
||||
}
|
||||
|
||||
// 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"),
|
||||
Secret: c.String("bitbucket-secret"),
|
||||
}
|
||||
log.Trace().Msgf("forge (bitbucket) opts: %#v", opts)
|
||||
return bitbucket.New(opts)
|
||||
}
|
||||
|
||||
// setupGitea helper function to set up 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 {
|
||||
return nil, err
|
||||
}
|
||||
oauth2Server := c.String("gitea-oauth-server")
|
||||
if oauth2Server != "" {
|
||||
oauth2URL, err := url.Parse(oauth2Server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
oauth2Server = strings.TrimRight(oauth2URL.String(), "/")
|
||||
}
|
||||
opts := gitea.Opts{
|
||||
URL: strings.TrimRight(server.String(), "/"),
|
||||
OAuth2URL: oauth2Server,
|
||||
Client: c.String("gitea-client"),
|
||||
Secret: c.String("gitea-secret"),
|
||||
SkipVerify: c.Bool("gitea-skip-verify"),
|
||||
}
|
||||
if len(opts.URL) == 0 {
|
||||
return nil, fmt.Errorf("WOODPECKER_GITEA_URL must be set")
|
||||
}
|
||||
log.Trace().Msgf("forge (gitea) opts: %#v", opts)
|
||||
return gitea.New(opts)
|
||||
}
|
||||
|
||||
// setupBitbucketDatacenter helper function to setup the Bitbucket DataCenter/Server forge from the CLI arguments.
|
||||
func setupBitbucketDatacenter(c *cli.Context) (forge.Forge, error) {
|
||||
opts := bitbucketdatacenter.Opts{
|
||||
URL: c.String("bitbucket-dc-server"),
|
||||
Username: c.String("bitbucket-dc-git-username"),
|
||||
Password: c.String("bitbucket-dc-git-password"),
|
||||
ClientID: c.String("bitbucket-dc-client-id"),
|
||||
ClientSecret: c.String("bitbucket-dc-client-secret"),
|
||||
}
|
||||
log.Trace().Msgf("Forge (bitbucketdatacenter) opts: %#v", opts)
|
||||
return bitbucketdatacenter.New(opts)
|
||||
}
|
||||
|
||||
// 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"),
|
||||
ClientID: c.String("gitlab-client"),
|
||||
ClientSecret: c.String("gitlab-secret"),
|
||||
SkipVerify: c.Bool("gitlab-skip-verify"),
|
||||
})
|
||||
}
|
||||
|
||||
// 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"),
|
||||
Client: c.String("github-client"),
|
||||
Secret: c.String("github-secret"),
|
||||
SkipVerify: c.Bool("github-skip-verify"),
|
||||
MergeRef: c.Bool("github-merge-ref"),
|
||||
OnlyPublic: c.Bool("github-public-only"),
|
||||
}
|
||||
log.Trace().Msgf("forge (github) opts: %#v", opts)
|
||||
return github.New(opts)
|
||||
func setupMembershipService(_ *cli.Context, _store store.Store) cache.MembershipService {
|
||||
return cache.NewMembershipService(_store)
|
||||
}
|
||||
|
||||
func setupMetrics(g *errgroup.Group, _store store.Store) {
|
||||
|
|
|
@ -1,18 +1,3 @@
|
|||
// Copyright 2021 Woodpecker Authors
|
||||
// Copyright 2011 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.
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
|
@ -74,7 +59,7 @@ func NewWoodpeckerClient(cc grpc.ClientConnInterface) WoodpeckerClient {
|
|||
|
||||
func (c *woodpeckerClient) Version(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*VersionResponse, error) {
|
||||
out := new(VersionResponse)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_Version_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/Version", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -83,7 +68,7 @@ func (c *woodpeckerClient) Version(ctx context.Context, in *Empty, opts ...grpc.
|
|||
|
||||
func (c *woodpeckerClient) Next(ctx context.Context, in *NextRequest, opts ...grpc.CallOption) (*NextResponse, error) {
|
||||
out := new(NextResponse)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_Next_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/Next", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -92,7 +77,7 @@ func (c *woodpeckerClient) Next(ctx context.Context, in *NextRequest, opts ...gr
|
|||
|
||||
func (c *woodpeckerClient) Init(ctx context.Context, in *InitRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_Init_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/Init", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -101,7 +86,7 @@ func (c *woodpeckerClient) Init(ctx context.Context, in *InitRequest, opts ...gr
|
|||
|
||||
func (c *woodpeckerClient) Wait(ctx context.Context, in *WaitRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_Wait_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/Wait", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -110,7 +95,7 @@ func (c *woodpeckerClient) Wait(ctx context.Context, in *WaitRequest, opts ...gr
|
|||
|
||||
func (c *woodpeckerClient) Done(ctx context.Context, in *DoneRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_Done_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/Done", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -119,7 +104,7 @@ func (c *woodpeckerClient) Done(ctx context.Context, in *DoneRequest, opts ...gr
|
|||
|
||||
func (c *woodpeckerClient) Extend(ctx context.Context, in *ExtendRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_Extend_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/Extend", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -128,7 +113,7 @@ func (c *woodpeckerClient) Extend(ctx context.Context, in *ExtendRequest, opts .
|
|||
|
||||
func (c *woodpeckerClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_Update_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/Update", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -137,7 +122,7 @@ func (c *woodpeckerClient) Update(ctx context.Context, in *UpdateRequest, opts .
|
|||
|
||||
func (c *woodpeckerClient) Log(ctx context.Context, in *LogRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_Log_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/Log", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -146,7 +131,7 @@ func (c *woodpeckerClient) Log(ctx context.Context, in *LogRequest, opts ...grpc
|
|||
|
||||
func (c *woodpeckerClient) RegisterAgent(ctx context.Context, in *RegisterAgentRequest, opts ...grpc.CallOption) (*RegisterAgentResponse, error) {
|
||||
out := new(RegisterAgentResponse)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_RegisterAgent_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/RegisterAgent", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -164,7 +149,7 @@ func (c *woodpeckerClient) UnregisterAgent(ctx context.Context, in *Empty, opts
|
|||
|
||||
func (c *woodpeckerClient) ReportHealth(ctx context.Context, in *ReportHealthRequest, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, Woodpecker_ReportHealth_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.Woodpecker/ReportHealth", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -249,7 +234,7 @@ func _Woodpecker_Version_Handler(srv interface{}, ctx context.Context, dec func(
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_Version_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/Version",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).Version(ctx, req.(*Empty))
|
||||
|
@ -267,7 +252,7 @@ func _Woodpecker_Next_Handler(srv interface{}, ctx context.Context, dec func(int
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_Next_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/Next",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).Next(ctx, req.(*NextRequest))
|
||||
|
@ -285,7 +270,7 @@ func _Woodpecker_Init_Handler(srv interface{}, ctx context.Context, dec func(int
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_Init_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/Init",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).Init(ctx, req.(*InitRequest))
|
||||
|
@ -303,7 +288,7 @@ func _Woodpecker_Wait_Handler(srv interface{}, ctx context.Context, dec func(int
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_Wait_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/Wait",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).Wait(ctx, req.(*WaitRequest))
|
||||
|
@ -321,7 +306,7 @@ func _Woodpecker_Done_Handler(srv interface{}, ctx context.Context, dec func(int
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_Done_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/Done",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).Done(ctx, req.(*DoneRequest))
|
||||
|
@ -339,7 +324,7 @@ func _Woodpecker_Extend_Handler(srv interface{}, ctx context.Context, dec func(i
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_Extend_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/Extend",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).Extend(ctx, req.(*ExtendRequest))
|
||||
|
@ -357,7 +342,7 @@ func _Woodpecker_Update_Handler(srv interface{}, ctx context.Context, dec func(i
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_Update_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/Update",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).Update(ctx, req.(*UpdateRequest))
|
||||
|
@ -375,7 +360,7 @@ func _Woodpecker_Log_Handler(srv interface{}, ctx context.Context, dec func(inte
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_Log_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/Log",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).Log(ctx, req.(*LogRequest))
|
||||
|
@ -393,7 +378,7 @@ func _Woodpecker_RegisterAgent_Handler(srv interface{}, ctx context.Context, dec
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_RegisterAgent_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/RegisterAgent",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).RegisterAgent(ctx, req.(*RegisterAgentRequest))
|
||||
|
@ -429,7 +414,7 @@ func _Woodpecker_ReportHealth_Handler(srv interface{}, ctx context.Context, dec
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Woodpecker_ReportHealth_FullMethodName,
|
||||
FullMethod: "/proto.Woodpecker/ReportHealth",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerServer).ReportHealth(ctx, req.(*ReportHealthRequest))
|
||||
|
@ -493,10 +478,6 @@ var Woodpecker_ServiceDesc = grpc.ServiceDesc{
|
|||
Metadata: "woodpecker.proto",
|
||||
}
|
||||
|
||||
const (
|
||||
WoodpeckerAuth_Auth_FullMethodName = "/proto.WoodpeckerAuth/Auth"
|
||||
)
|
||||
|
||||
// WoodpeckerAuthClient is the client API for WoodpeckerAuth service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
|
@ -514,7 +495,7 @@ func NewWoodpeckerAuthClient(cc grpc.ClientConnInterface) WoodpeckerAuthClient {
|
|||
|
||||
func (c *woodpeckerAuthClient) Auth(ctx context.Context, in *AuthRequest, opts ...grpc.CallOption) (*AuthResponse, error) {
|
||||
out := new(AuthResponse)
|
||||
err := c.cc.Invoke(ctx, WoodpeckerAuth_Auth_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/proto.WoodpeckerAuth/Auth", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -559,7 +540,7 @@ func _WoodpeckerAuth_Auth_Handler(srv interface{}, ctx context.Context, dec func
|
|||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: WoodpeckerAuth_Auth_FullMethodName,
|
||||
FullMethod: "/proto.WoodpeckerAuth/Auth",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WoodpeckerAuthServer).Auth(ctx, req.(*AuthRequest))
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
cronScheduler "go.woodpecker-ci.org/woodpecker/v2/server/cron"
|
||||
|
@ -80,7 +81,7 @@ func RunCron(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
repo, newPipeline, err := cronScheduler.CreatePipeline(c, _store, server.Config.Services.Forge, cron)
|
||||
repo, newPipeline, err := cronScheduler.CreatePipeline(c, _store, cron)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Error creating pipeline for cron %q. %s", id, err)
|
||||
return
|
||||
|
@ -109,7 +110,12 @@ func PostCron(c *gin.Context) {
|
|||
repo := session.Repo(c)
|
||||
user := session.User(c)
|
||||
_store := store.FromContext(c)
|
||||
forge := server.Config.Services.Forge
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
in := new(model.Cron)
|
||||
if err := c.Bind(in); err != nil {
|
||||
|
@ -137,7 +143,7 @@ func PostCron(c *gin.Context) {
|
|||
|
||||
if in.Branch != "" {
|
||||
// check if branch exists on forge
|
||||
_, err := forge.BranchHead(c, user, repo, in.Branch)
|
||||
_, err := _forge.BranchHead(c, user, repo, in.Branch)
|
||||
if err != nil {
|
||||
c.String(http.StatusBadRequest, "Error inserting cron. branch not resolved: %s", err)
|
||||
return
|
||||
|
@ -166,7 +172,12 @@ func PatchCron(c *gin.Context) {
|
|||
repo := session.Repo(c)
|
||||
user := session.User(c)
|
||||
_store := store.FromContext(c)
|
||||
forge := server.Config.Services.Forge
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseInt(c.Param("cron"), 10, 64)
|
||||
if err != nil {
|
||||
|
@ -188,7 +199,7 @@ func PatchCron(c *gin.Context) {
|
|||
}
|
||||
if in.Branch != "" {
|
||||
// check if branch exists on forge
|
||||
_, err := forge.BranchHead(c, user, repo, in.Branch)
|
||||
_, err := _forge.BranchHead(c, user, repo, in.Branch)
|
||||
if err != nil {
|
||||
c.String(http.StatusBadRequest, "Error inserting cron. branch not resolved: %s", err)
|
||||
return
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
|
@ -54,7 +55,12 @@ func handleDBError(c *gin.Context, err error) {
|
|||
// If the forge has a refresh token, the current access token may be stale.
|
||||
// Therefore, we should refresh prior to dispatching the job.
|
||||
func refreshUserToken(c *gin.Context, user *model.User) {
|
||||
_forge := server.Config.Services.Forge
|
||||
_store := store.FromContext(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromUser(user)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from user")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
forge.Refresh(c, _forge, _store, user)
|
||||
}
|
||||
|
|
|
@ -104,7 +104,13 @@ func BlockTilQueueHasRunningItem(c *gin.Context) {
|
|||
// @Param hook body object true "the webhook payload; forge is automatically detected"
|
||||
func PostHook(c *gin.Context) {
|
||||
_store := store.FromContext(c)
|
||||
_forge := server.Config.Services.Forge
|
||||
|
||||
_forge, err := server.Config.Services.Manager.ForgeMain() // TODO: get the forge for the specific repo somehow
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get main forge")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// 1. Parse webhook
|
||||
|
|
|
@ -43,7 +43,12 @@ func HandleLogin(c *gin.Context) {
|
|||
|
||||
func HandleAuth(c *gin.Context) {
|
||||
_store := store.FromContext(c)
|
||||
_forge := server.Config.Services.Forge
|
||||
_forge, err := server.Config.Services.Manager.ForgeMain()
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
forgeID := int64(1) // TODO: replace with forge id when multiple forges are supported
|
||||
|
||||
// when dealing with redirects, we may need to adjust the content type. I
|
||||
// cannot, however, remember why, so need to revisit this line.
|
||||
|
@ -68,12 +73,12 @@ func HandleAuth(c *gin.Context) {
|
|||
|
||||
// get the user from the database
|
||||
u, err := _store.GetUserRemoteID(tmpuser.ForgeRemoteID, tmpuser.Login)
|
||||
if err != nil {
|
||||
if !errors.Is(err, types.RecordNotExist) {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
if err != nil && !errors.Is(err, types.RecordNotExist) {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
if errors.Is(err, types.RecordNotExist) {
|
||||
// if self-registration is disabled we should return a not authorized error
|
||||
if !server.Config.Permissions.Open && !server.Config.Permissions.Admins.IsAdmin(tmpuser) {
|
||||
log.Error().Msgf("cannot register %s. registration closed", tmpuser.Login)
|
||||
|
@ -100,6 +105,7 @@ func HandleAuth(c *gin.Context) {
|
|||
Secret: tmpuser.Secret,
|
||||
Email: tmpuser.Email,
|
||||
Avatar: tmpuser.Avatar,
|
||||
ForgeID: forgeID,
|
||||
Hash: base32.StdEncoding.EncodeToString(
|
||||
securecookie.GenerateRandomKey(32),
|
||||
),
|
||||
|
@ -129,6 +135,7 @@ func HandleAuth(c *gin.Context) {
|
|||
Name: u.Login,
|
||||
IsUser: true,
|
||||
Private: false,
|
||||
ForgeID: u.ForgeID,
|
||||
}
|
||||
if err := _store.OrgCreate(org); err != nil {
|
||||
log.Error().Err(err).Msgf("on user creation, could create org for user")
|
||||
|
@ -228,14 +235,21 @@ func GetLogout(c *gin.Context) {
|
|||
func GetLoginToken(c *gin.Context) {
|
||||
_store := store.FromContext(c)
|
||||
|
||||
_forge, err := server.Config.Services.Manager.ForgeMain() // TODO: get selected forge from auth request
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get main forge")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
in := &tokenPayload{}
|
||||
err := c.Bind(in)
|
||||
err = c.Bind(in)
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
login, err := server.Config.Services.Forge.Auth(c, in.Access, in.Refresh)
|
||||
login, err := _forge.Auth(c, in.Access, in.Refresh)
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusUnauthorized, err)
|
||||
return
|
||||
|
|
|
@ -68,6 +68,13 @@ func GetOrgPermissions(c *gin.Context) {
|
|||
user := session.User(c)
|
||||
_store := store.FromContext(c)
|
||||
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromUser(user)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from user")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
orgID, err := strconv.ParseInt(c.Param("org_id"), 10, 64)
|
||||
if err != nil {
|
||||
c.String(http.StatusBadRequest, "Error parsing org id. %s", err)
|
||||
|
@ -96,7 +103,7 @@ func GetOrgPermissions(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
perm, err := server.Config.Services.Membership.Get(c, user, org.Name)
|
||||
perm, err := server.Config.Services.Membership.Get(c, _forge, user, org.Name)
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Error getting membership for %d. %s", orgID, err)
|
||||
return
|
||||
|
@ -116,6 +123,13 @@ func GetOrgPermissions(c *gin.Context) {
|
|||
// @Param org_full_name path string true "the organizations full-name / slug"
|
||||
func LookupOrg(c *gin.Context) {
|
||||
_store := store.FromContext(c)
|
||||
user := session.User(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromUser(user)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from user")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
orgFullName := strings.TrimLeft(c.Param("org_full_name"), "/")
|
||||
|
||||
|
@ -137,7 +151,7 @@ func LookupOrg(c *gin.Context) {
|
|||
c.AbortWithStatus(http.StatusNotFound)
|
||||
return
|
||||
} else if !user.Admin {
|
||||
perm, err := server.Config.Services.Membership.Get(c, user, org.Name)
|
||||
perm, err := server.Config.Services.Membership.Get(c, _forge, user, org.Name)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to check membership")
|
||||
c.Status(http.StatusInternalServerError)
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
|
@ -48,10 +49,16 @@ import (
|
|||
func CreatePipeline(c *gin.Context) {
|
||||
_store := store.FromContext(c)
|
||||
repo := session.Repo(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// parse create options
|
||||
var opts model.PipelineOptions
|
||||
err := json.NewDecoder(c.Request.Body).Decode(&opts)
|
||||
err = json.NewDecoder(c.Request.Body).Decode(&opts)
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusBadRequest, err)
|
||||
return
|
||||
|
@ -59,7 +66,7 @@ func CreatePipeline(c *gin.Context) {
|
|||
|
||||
user := session.User(c)
|
||||
|
||||
lastCommit, _ := server.Config.Services.Forge.BranchHead(c, user, repo, opts.Branch)
|
||||
lastCommit, _ := _forge.BranchHead(c, user, repo, opts.Branch)
|
||||
|
||||
tmpPipeline := createTmpPipeline(model.EventManual, lastCommit, user, &opts)
|
||||
|
||||
|
@ -332,6 +339,13 @@ func CancelPipeline(c *gin.Context) {
|
|||
_store := store.FromContext(c)
|
||||
repo := session.Repo(c)
|
||||
user := session.User(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
||||
|
||||
pl, err := _store.GetPipelineNumber(repo, num)
|
||||
|
@ -340,7 +354,7 @@ func CancelPipeline(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := pipeline.Cancel(c, _store, repo, user, pl); err != nil {
|
||||
if err := pipeline.Cancel(c, _forge, _store, repo, user, pl); err != nil {
|
||||
handlePipelineErr(c, err)
|
||||
} else {
|
||||
c.Status(http.StatusNoContent)
|
||||
|
|
|
@ -45,9 +45,14 @@ import (
|
|||
// @Param Authorization header string true "Insert your personal access token" default(Bearer <personal access token>)
|
||||
// @Param forge_remote_id query string true "the id of a repository at the forge"
|
||||
func PostRepo(c *gin.Context) {
|
||||
forge := server.Config.Services.Forge
|
||||
_store := store.FromContext(c)
|
||||
user := session.User(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromUser(user)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from user")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
forgeRemoteID := model.ForgeRemoteID(c.Query("forge_remote_id"))
|
||||
if !forgeRemoteID.IsValid() {
|
||||
|
@ -67,7 +72,7 @@ func PostRepo(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
from, err := forge.Repo(c, user, forgeRemoteID, "", "")
|
||||
from, err := _forge.Repo(c, user, forgeRemoteID, "", "")
|
||||
if err != nil {
|
||||
c.String(http.StatusInternalServerError, "Could not fetch repository from forge.")
|
||||
return
|
||||
|
@ -138,7 +143,7 @@ func PostRepo(c *gin.Context) {
|
|||
|
||||
// create an org if it doesn't exist yet
|
||||
if errors.Is(err, types.RecordNotExist) {
|
||||
org, err = forge.Org(c, user, repo.Owner)
|
||||
org, err = _forge.Org(c, user, repo.Owner)
|
||||
if err != nil {
|
||||
msg := "could not fetch organization from forge."
|
||||
log.Error().Err(err).Msg(msg)
|
||||
|
@ -146,6 +151,7 @@ func PostRepo(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
org.ForgeID = user.ForgeID
|
||||
err = _store.OrgCreate(org)
|
||||
if err != nil {
|
||||
msg := "could not create organization in store."
|
||||
|
@ -157,7 +163,7 @@ func PostRepo(c *gin.Context) {
|
|||
|
||||
repo.OrgID = org.ID
|
||||
|
||||
err = forge.Activate(c, user, repo, hookURL)
|
||||
err = _forge.Activate(c, user, repo, hookURL)
|
||||
if err != nil {
|
||||
msg := "could not create webhook in forge."
|
||||
log.Error().Err(err).Msg(msg)
|
||||
|
@ -168,6 +174,7 @@ func PostRepo(c *gin.Context) {
|
|||
if enabledOnce {
|
||||
err = _store.UpdateRepo(repo)
|
||||
} else {
|
||||
repo.ForgeID = user.ForgeID // TODO: allow to use other connected forges of the user
|
||||
err = _store.CreateRepo(repo)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -342,9 +349,14 @@ func GetRepoPermissions(c *gin.Context) {
|
|||
func GetRepoBranches(c *gin.Context) {
|
||||
repo := session.Repo(c)
|
||||
user := session.User(c)
|
||||
f := server.Config.Services.Forge
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
branches, err := f.Branches(c, user, repo, session.Pagination(c))
|
||||
branches, err := _forge.Branches(c, user, repo, session.Pagination(c))
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
|
@ -367,9 +379,14 @@ func GetRepoBranches(c *gin.Context) {
|
|||
func GetRepoPullRequests(c *gin.Context) {
|
||||
repo := session.Repo(c)
|
||||
user := session.User(c)
|
||||
f := server.Config.Services.Forge
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
prs, err := f.PullRequests(c, user, repo, session.Pagination(c))
|
||||
prs, err := _forge.PullRequests(c, user, repo, session.Pagination(c))
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
|
@ -390,9 +407,14 @@ func GetRepoPullRequests(c *gin.Context) {
|
|||
func DeleteRepo(c *gin.Context) {
|
||||
remove, _ := strconv.ParseBool(c.Query("remove"))
|
||||
_store := store.FromContext(c)
|
||||
|
||||
repo := session.Repo(c)
|
||||
user := session.User(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
repo.IsActive = false
|
||||
repo.UserID = 0
|
||||
|
@ -409,7 +431,7 @@ func DeleteRepo(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
if err := server.Config.Services.Forge.Deactivate(c, user, repo, server.Config.Server.WebhookHost); err != nil {
|
||||
if err := _forge.Deactivate(c, user, repo, server.Config.Server.WebhookHost); err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -445,10 +467,15 @@ func RepairRepo(c *gin.Context) {
|
|||
// @Param repo_id path int true "the repository id"
|
||||
// @Param to query string true "the username to move the repository to"
|
||||
func MoveRepo(c *gin.Context) {
|
||||
forge := server.Config.Services.Forge
|
||||
_store := store.FromContext(c)
|
||||
repo := session.Repo(c)
|
||||
user := session.User(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
to, exists := c.GetQuery("to")
|
||||
if !exists {
|
||||
|
@ -463,7 +490,7 @@ func MoveRepo(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
from, err := forge.Repo(c, user, "", owner, name)
|
||||
from, err := _forge.Repo(c, user, "", owner, name)
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
|
@ -508,10 +535,10 @@ func MoveRepo(c *gin.Context) {
|
|||
sig,
|
||||
)
|
||||
|
||||
if err := forge.Deactivate(c, user, repo, host); err != nil {
|
||||
if err := _forge.Deactivate(c, user, repo, host); err != nil {
|
||||
log.Trace().Err(err).Msgf("deactivate repo '%s' for move to activate later, got an error", repo.FullName)
|
||||
}
|
||||
if err := forge.Activate(c, user, repo, hookURL); err != nil {
|
||||
if err := _forge.Activate(c, user, repo, hookURL); err != nil {
|
||||
c.String(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
@ -571,8 +598,13 @@ func RepairAllRepos(c *gin.Context) {
|
|||
}
|
||||
|
||||
func repairRepo(c *gin.Context, repo *model.Repo, withPerms, skipOnErr bool) {
|
||||
forge := server.Config.Services.Forge
|
||||
_store := store.FromContext(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := _store.GetUser(repo.UserID)
|
||||
if err != nil {
|
||||
|
@ -603,7 +635,7 @@ func repairRepo(c *gin.Context, repo *model.Repo, withPerms, skipOnErr bool) {
|
|||
sig,
|
||||
)
|
||||
|
||||
from, err := forge.Repo(c, user, repo.ForgeRemoteID, repo.Owner, repo.Name)
|
||||
from, err := _forge.Repo(c, user, repo.ForgeRemoteID, repo.Owner, repo.Name)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("get repo '%s/%s' from forge", repo.Owner, repo.Name)
|
||||
if !skipOnErr {
|
||||
|
@ -636,10 +668,10 @@ func repairRepo(c *gin.Context, repo *model.Repo, withPerms, skipOnErr bool) {
|
|||
}
|
||||
}
|
||||
|
||||
if err := forge.Deactivate(c, user, repo, host); err != nil {
|
||||
if err := _forge.Deactivate(c, user, repo, host); err != nil {
|
||||
log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName)
|
||||
}
|
||||
if err := forge.Activate(c, user, repo, hookURL); err != nil {
|
||||
if err := _forge.Activate(c, user, repo, hookURL); err != nil {
|
||||
c.String(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/securecookie"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
|
@ -86,9 +87,14 @@ func GetFeed(c *gin.Context) {
|
|||
// @Param all query bool false "query all repos, including inactive ones"
|
||||
func GetRepos(c *gin.Context) {
|
||||
_store := store.FromContext(c)
|
||||
_forge := server.Config.Services.Forge
|
||||
|
||||
user := session.User(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromUser(user)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from user")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
all, _ := strconv.ParseBool(c.Query("all"))
|
||||
|
||||
if all {
|
||||
|
|
|
@ -132,6 +132,8 @@ func PostUser(c *gin.Context) {
|
|||
Hash: base32.StdEncoding.EncodeToString(
|
||||
securecookie.GenerateRandomKey(32),
|
||||
),
|
||||
ForgeID: 1, // TODO: replace with forge id when multiple forges are supported
|
||||
ForgeRemoteID: model.ForgeRemoteID("0"), // TODO: search for the user in the forge and get the remote id
|
||||
}
|
||||
if err = user.Validate(); err != nil {
|
||||
c.String(http.StatusBadRequest, err.Error())
|
||||
|
|
16
server/cache/membership.go
vendored
16
server/cache/membership.go
vendored
|
@ -23,39 +23,39 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||
)
|
||||
|
||||
// MembershipService is a service to check for user membership.
|
||||
type MembershipService interface {
|
||||
// Get returns if the user is a member of the organization.
|
||||
Get(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error)
|
||||
Get(ctx context.Context, _forge forge.Forge, u *model.User, org string) (*model.OrgPerm, error)
|
||||
}
|
||||
|
||||
type membershipCache struct {
|
||||
forge forge.Forge
|
||||
cache *ttlcache.Cache[string, *model.OrgPerm]
|
||||
store store.Store
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
// NewMembershipService creates a new membership service.
|
||||
func NewMembershipService(f forge.Forge) MembershipService {
|
||||
//nolint:gomnd
|
||||
func NewMembershipService(_store store.Store) MembershipService {
|
||||
return &membershipCache{
|
||||
ttl: 10 * time.Minute,
|
||||
forge: f,
|
||||
ttl: 10 * time.Minute, //nolint: gomnd
|
||||
store: _store,
|
||||
cache: ttlcache.New(ttlcache.WithDisableTouchOnHit[string, *model.OrgPerm]()),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns if the user is a member of the organization.
|
||||
func (c *membershipCache) Get(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error) {
|
||||
func (c *membershipCache) Get(ctx context.Context, _forge forge.Forge, u *model.User, org string) (*model.OrgPerm, error) {
|
||||
key := fmt.Sprintf("%s-%s", u.ForgeRemoteID, org)
|
||||
item := c.cache.Get(key)
|
||||
if item != nil && !item.IsExpired() {
|
||||
return item.Value(), nil
|
||||
}
|
||||
|
||||
perm, err := c.forge.OrgMembership(ctx, u, org)
|
||||
perm, err := _forge.OrgMembership(ctx, u, org)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
"time"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/cache"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/logging"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/pubsub"
|
||||
|
@ -35,9 +34,8 @@ var Config = struct {
|
|||
Pubsub *pubsub.Publisher
|
||||
Queue queue.Queue
|
||||
Logs logging.Log
|
||||
Forge forge.Forge
|
||||
Membership cache.MembershipService
|
||||
Manager *services.Manager
|
||||
Manager services.Manager
|
||||
}
|
||||
Server struct {
|
||||
Key string
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/robfig/cron"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/pipeline"
|
||||
|
@ -37,7 +38,7 @@ const (
|
|||
)
|
||||
|
||||
// Start starts the cron scheduler loop
|
||||
func Start(ctx context.Context, store store.Store, forge forge.Forge) error {
|
||||
func Start(ctx context.Context, store store.Store) error {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
@ -54,7 +55,7 @@ func Start(ctx context.Context, store store.Store, forge forge.Forge) error {
|
|||
}
|
||||
|
||||
for _, cron := range crons {
|
||||
if err := runCron(ctx, store, forge, cron, now); err != nil {
|
||||
if err := runCron(ctx, store, cron, now); err != nil {
|
||||
log.Error().Err(err).Int64("cronID", cron.ID).Msg("run cron failed")
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +78,7 @@ func CalcNewNext(schedule string, now time.Time) (time.Time, error) {
|
|||
return c.Next(now), nil
|
||||
}
|
||||
|
||||
func runCron(ctx context.Context, store store.Store, forge forge.Forge, cron *model.Cron, now time.Time) error {
|
||||
func runCron(ctx context.Context, store store.Store, cron *model.Cron, now time.Time) error {
|
||||
log.Trace().Msgf("cron: run id[%d]", cron.ID)
|
||||
|
||||
newNext, err := CalcNewNext(cron.Schedule, now)
|
||||
|
@ -95,7 +96,7 @@ func runCron(ctx context.Context, store store.Store, forge forge.Forge, cron *mo
|
|||
return nil
|
||||
}
|
||||
|
||||
repo, newPipeline, err := CreatePipeline(ctx, store, forge, cron)
|
||||
repo, newPipeline, err := CreatePipeline(ctx, store, cron)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -104,12 +105,17 @@ func runCron(ctx context.Context, store store.Store, forge forge.Forge, cron *mo
|
|||
return err
|
||||
}
|
||||
|
||||
func CreatePipeline(ctx context.Context, store store.Store, f forge.Forge, cron *model.Cron) (*model.Repo, *model.Pipeline, error) {
|
||||
func CreatePipeline(ctx context.Context, store store.Store, cron *model.Cron) (*model.Repo, *model.Pipeline, error) {
|
||||
repo, err := store.GetRepo(cron.RepoID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if cron.Branch == "" {
|
||||
// fallback to the repos default branch
|
||||
cron.Branch = repo.Branch
|
||||
|
@ -123,9 +129,9 @@ func CreatePipeline(ctx context.Context, store store.Store, f forge.Forge, cron
|
|||
// If the forge has a refresh token, the current access token
|
||||
// may be stale. Therefore, we should refresh prior to dispatching
|
||||
// the pipeline.
|
||||
forge.Refresh(ctx, f, store, creator)
|
||||
forge.Refresh(ctx, _forge, store, creator)
|
||||
|
||||
commit, err := f.BranchHead(ctx, creator, repo, cron.Branch)
|
||||
commit, err := _forge.BranchHead(ctx, creator, repo, cron.Branch)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
|
@ -22,13 +22,16 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
mocks_forge "go.woodpecker-ci.org/woodpecker/v2/server/forge/mocks"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
mocks_manager "go.woodpecker-ci.org/woodpecker/v2/server/services/mocks"
|
||||
mocks_store "go.woodpecker-ci.org/woodpecker/v2/server/store/mocks"
|
||||
)
|
||||
|
||||
func TestCreateBuild(t *testing.T) {
|
||||
forge := mocks_forge.NewForge(t)
|
||||
func TestCreatePipeline(t *testing.T) {
|
||||
_manager := mocks_manager.NewManager(t)
|
||||
_forge := mocks_forge.NewForge(t)
|
||||
store := mocks_store.NewStore(t)
|
||||
ctx := context.Background()
|
||||
|
||||
|
@ -47,12 +50,14 @@ func TestCreateBuild(t *testing.T) {
|
|||
// mock things
|
||||
store.On("GetRepo", mock.Anything).Return(repo1, nil)
|
||||
store.On("GetUser", mock.Anything).Return(creator, nil)
|
||||
forge.On("BranchHead", mock.Anything, creator, repo1, "default").Return(&model.Commit{
|
||||
_forge.On("BranchHead", mock.Anything, creator, repo1, "default").Return(&model.Commit{
|
||||
ForgeURL: "https://example.com/sha1",
|
||||
SHA: "sha1",
|
||||
}, nil)
|
||||
_manager.On("ForgeFromRepo", repo1).Return(_forge, nil)
|
||||
server.Config.Services.Manager = _manager
|
||||
|
||||
_, pipeline, err := CreatePipeline(ctx, store, forge, &model.Cron{
|
||||
_, pipeline, err := CreatePipeline(ctx, store, &model.Cron{
|
||||
Name: "test",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
|
134
server/forge/setup/setup.go
Normal file
134
server/forge/setup/setup.go
Normal file
|
@ -0,0 +1,134 @@
|
|||
package setup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/addon"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/bitbucket"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/bitbucketdatacenter"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/gitea"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/github"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge/gitlab"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
)
|
||||
|
||||
func Forge(forge *model.Forge) (forge.Forge, error) {
|
||||
switch forge.Type {
|
||||
case model.ForgeTypeAddon:
|
||||
return setupAddon(forge)
|
||||
case model.ForgeTypeGithub:
|
||||
return setupGitHub(forge)
|
||||
case model.ForgeTypeGitlab:
|
||||
return setupGitLab(forge)
|
||||
case model.ForgeTypeBitbucket:
|
||||
return setupBitbucket(forge)
|
||||
case model.ForgeTypeGitea:
|
||||
return setupGitea(forge)
|
||||
case model.ForgeTypeBitbucketDatacenter:
|
||||
return setupBitbucketDatacenter(forge)
|
||||
default:
|
||||
return nil, fmt.Errorf("forge not configured")
|
||||
}
|
||||
}
|
||||
|
||||
func setupBitbucket(forge *model.Forge) (forge.Forge, error) {
|
||||
opts := &bitbucket.Opts{
|
||||
Client: forge.Client,
|
||||
Secret: forge.ClientSecret,
|
||||
}
|
||||
log.Trace().Msgf("Forge (bitbucket) opts: %#v", opts)
|
||||
return bitbucket.New(opts)
|
||||
}
|
||||
|
||||
func setupGitea(forge *model.Forge) (forge.Forge, error) {
|
||||
server, err := url.Parse(forge.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oauthURL, ok := forge.AdditionalOptions["oauth-server"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing oauth-server")
|
||||
}
|
||||
|
||||
opts := gitea.Opts{
|
||||
URL: strings.TrimRight(server.String(), "/"),
|
||||
Client: forge.Client,
|
||||
Secret: forge.ClientSecret,
|
||||
SkipVerify: forge.SkipVerify,
|
||||
OAuth2URL: oauthURL,
|
||||
}
|
||||
if len(opts.URL) == 0 {
|
||||
return nil, fmt.Errorf("WOODPECKER_GITEA_URL must be set")
|
||||
}
|
||||
log.Trace().Msgf("Forge (gitea) opts: %#v", opts)
|
||||
return gitea.New(opts)
|
||||
}
|
||||
|
||||
func setupGitLab(forge *model.Forge) (forge.Forge, error) {
|
||||
return gitlab.New(gitlab.Opts{
|
||||
URL: forge.URL,
|
||||
ClientID: forge.Client,
|
||||
ClientSecret: forge.ClientSecret,
|
||||
SkipVerify: forge.SkipVerify,
|
||||
})
|
||||
}
|
||||
|
||||
func setupGitHub(forge *model.Forge) (forge.Forge, error) {
|
||||
mergeRef, ok := forge.AdditionalOptions["merge-ref"].(bool)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing merge-ref")
|
||||
}
|
||||
|
||||
publicOnly, ok := forge.AdditionalOptions["public-only"].(bool)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing public-only")
|
||||
}
|
||||
|
||||
opts := github.Opts{
|
||||
URL: forge.URL,
|
||||
Client: forge.Client,
|
||||
Secret: forge.ClientSecret,
|
||||
SkipVerify: forge.SkipVerify,
|
||||
MergeRef: mergeRef,
|
||||
OnlyPublic: publicOnly,
|
||||
}
|
||||
log.Trace().Msgf("Forge (github) opts: %#v", opts)
|
||||
return github.New(opts)
|
||||
}
|
||||
|
||||
func setupBitbucketDatacenter(forge *model.Forge) (forge.Forge, error) {
|
||||
gitUsername, ok := forge.AdditionalOptions["git-username"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing git-username")
|
||||
}
|
||||
gitPassword, ok := forge.AdditionalOptions["git-password"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing git-password")
|
||||
}
|
||||
|
||||
opts := bitbucketdatacenter.Opts{
|
||||
URL: forge.URL,
|
||||
ClientID: forge.Client,
|
||||
ClientSecret: forge.ClientSecret,
|
||||
Username: gitUsername,
|
||||
Password: gitPassword,
|
||||
}
|
||||
log.Trace().Msgf("Forge (bitbucketdatacenter) opts: %#v", opts)
|
||||
return bitbucketdatacenter.New(opts)
|
||||
}
|
||||
|
||||
func setupAddon(forge *model.Forge) (forge.Forge, error) {
|
||||
executable, ok := forge.AdditionalOptions["executable"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing git-username")
|
||||
}
|
||||
|
||||
log.Trace().Msgf("Forge (addon) executable: %#v", executable)
|
||||
return addon.Load(executable)
|
||||
}
|
|
@ -31,6 +31,7 @@ import (
|
|||
grpcMetadata "google.golang.org/grpc/metadata"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/logging"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
|
@ -41,7 +42,6 @@ import (
|
|||
)
|
||||
|
||||
type RPC struct {
|
||||
forge forge.Forge
|
||||
queue queue.Queue
|
||||
pubsub *pubsub.Publisher
|
||||
logger logging.Log
|
||||
|
@ -418,11 +418,17 @@ func (s *RPC) updateForgeStatus(ctx context.Context, repo *model.Repo, pipeline
|
|||
return
|
||||
}
|
||||
|
||||
forge.Refresh(ctx, s.forge, s.store, user)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("can not get forge for repo '%s'", repo.FullName)
|
||||
return
|
||||
}
|
||||
|
||||
forge.Refresh(ctx, _forge, s.store, user)
|
||||
|
||||
// only do status updates for parent steps
|
||||
if workflow != nil {
|
||||
err = s.forge.Status(ctx, user, repo, pipeline, workflow)
|
||||
err = _forge.Status(ctx, user, repo, pipeline, workflow)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, pipeline.Number)
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import (
|
|||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/rpc/proto"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/logging"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/pubsub"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/queue"
|
||||
|
@ -37,7 +36,7 @@ type WoodpeckerServer struct {
|
|||
peer RPC
|
||||
}
|
||||
|
||||
func NewWoodpeckerServer(forge forge.Forge, queue queue.Queue, logger logging.Log, pubsub *pubsub.Publisher, store store.Store) proto.WoodpeckerServer {
|
||||
func NewWoodpeckerServer(queue queue.Queue, logger logging.Log, pubsub *pubsub.Publisher, store store.Store) proto.WoodpeckerServer {
|
||||
pipelineTime := promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: "woodpecker",
|
||||
Name: "pipeline_time",
|
||||
|
@ -49,7 +48,6 @@ func NewWoodpeckerServer(forge forge.Forge, queue queue.Queue, logger logging.Lo
|
|||
Help: "Pipeline count.",
|
||||
}, []string{"repo", "branch", "status", "pipeline"})
|
||||
peer := RPC{
|
||||
forge: forge,
|
||||
store: store,
|
||||
queue: queue,
|
||||
pubsub: pubsub,
|
||||
|
|
36
server/model/forge.go
Normal file
36
server/model/forge.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2024 Woodpecker Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package model
|
||||
|
||||
type ForgeType string
|
||||
|
||||
const (
|
||||
ForgeTypeGithub ForgeType = "github"
|
||||
ForgeTypeGitlab ForgeType = "gitlab"
|
||||
ForgeTypeGitea ForgeType = "gitea"
|
||||
ForgeTypeBitbucket ForgeType = "bitbucket"
|
||||
ForgeTypeBitbucketDatacenter ForgeType = "bitbucket-dc"
|
||||
ForgeTypeAddon ForgeType = "addon"
|
||||
)
|
||||
|
||||
type Forge struct {
|
||||
ID int64 `xorm:"pk autoincr 'id'"`
|
||||
Type ForgeType `xorm:"VARCHAR(250)"`
|
||||
URL string `xorm:"VARCHAR(500) 'url'"`
|
||||
Client string `xorm:"VARCHAR(250)"`
|
||||
ClientSecret string `xorm:"VARCHAR(250)"`
|
||||
SkipVerify bool `xorm:"bool"`
|
||||
AdditionalOptions map[string]any `xorm:"json"`
|
||||
}
|
|
@ -16,11 +16,12 @@ package model
|
|||
|
||||
// Org represents an organization.
|
||||
type Org struct {
|
||||
ID int64 `json:"id,omitempty" xorm:"pk autoincr 'id'"`
|
||||
Name string `json:"name" xorm:"UNIQUE 'name'"`
|
||||
IsUser bool `json:"is_user" xorm:"is_user"`
|
||||
ID int64 `json:"id,omitempty" xorm:"pk autoincr 'id'"`
|
||||
ForgeID int64 `json:"forge_id,omitempty" xorm:"forge_id"`
|
||||
Name string `json:"name" xorm:"UNIQUE 'name'"`
|
||||
IsUser bool `json:"is_user" xorm:"is_user"`
|
||||
// if name lookup has to check for membership or not
|
||||
Private bool `json:"-" xorm:"private"`
|
||||
Private bool `json:"-" xorm:"private"`
|
||||
} // @name Org
|
||||
|
||||
// TableName return database table name for xorm
|
||||
|
|
|
@ -22,8 +22,9 @@ import (
|
|||
|
||||
// Repo represents a repository.
|
||||
type Repo struct {
|
||||
ID int64 `json:"id,omitempty" xorm:"pk autoincr 'repo_id'"`
|
||||
UserID int64 `json:"-" xorm:"repo_user_id"`
|
||||
ID int64 `json:"id,omitempty" xorm:"pk autoincr 'repo_id'"`
|
||||
UserID int64 `json:"-" xorm:"repo_user_id"`
|
||||
ForgeID int64 `json:"forge_id,omitempty" xorm:"forge_id"`
|
||||
// ForgeRemoteID is the unique identifier for the repository on the forge.
|
||||
ForgeRemoteID ForgeRemoteID `json:"forge_remote_id" xorm:"forge_remote_id"`
|
||||
OrgID int64 `json:"org_id" xorm:"repo_org_id"`
|
||||
|
|
|
@ -34,6 +34,8 @@ type User struct {
|
|||
// required: true
|
||||
ID int64 `json:"id" xorm:"pk autoincr 'user_id'"`
|
||||
|
||||
ForgeID int64 `json:"forge_id,omitempty" xorm:"forge_id"`
|
||||
|
||||
ForgeRemoteID ForgeRemoteID `json:"-" xorm:"forge_remote_id"`
|
||||
|
||||
// Login is the username for this user.
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
forge_types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||
|
@ -32,6 +33,13 @@ func Approve(ctx context.Context, store store.Store, currentPipeline *model.Pipe
|
|||
return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot approve a pipeline with status %s", currentPipeline.Status)}
|
||||
}
|
||||
|
||||
forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failure to load forge for repo '%s'", repo.FullName)
|
||||
log.Error().Err(err).Str("repo", repo.FullName).Msg(msg)
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
// fetch the pipeline file from the database
|
||||
configs, err := store.ConfigsForPipeline(currentPipeline.ID)
|
||||
if err != nil {
|
||||
|
@ -72,7 +80,7 @@ func Approve(ctx context.Context, store store.Store, currentPipeline *model.Pipe
|
|||
}
|
||||
}
|
||||
|
||||
currentPipeline, pipelineItems, err := createPipelineItems(ctx, store, currentPipeline, user, repo, yamls, nil)
|
||||
currentPipeline, pipelineItems, err := createPipelineItems(ctx, forge, store, currentPipeline, user, repo, yamls, nil)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failure to createPipelineItems for %s", repo.FullName)
|
||||
log.Error().Err(err).Msg(msg)
|
||||
|
@ -86,9 +94,9 @@ func Approve(ctx context.Context, store store.Store, currentPipeline *model.Pipe
|
|||
return nil, err
|
||||
}
|
||||
|
||||
publishPipeline(ctx, currentPipeline, repo, user)
|
||||
publishPipeline(ctx, forge, currentPipeline, repo, user)
|
||||
|
||||
currentPipeline, err = start(ctx, store, currentPipeline, user, repo, pipelineItems)
|
||||
currentPipeline, err = start(ctx, forge, store, currentPipeline, user, repo, pipelineItems)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failure to start pipeline for %s: %v", repo.FullName, err)
|
||||
log.Error().Err(err).Msg(msg)
|
||||
|
|
|
@ -21,13 +21,14 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/queue"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||
)
|
||||
|
||||
// Cancel the pipeline and returns the status.
|
||||
func Cancel(ctx context.Context, store store.Store, repo *model.Repo, user *model.User, pipeline *model.Pipeline) error {
|
||||
func Cancel(ctx context.Context, _forge forge.Forge, store store.Store, repo *model.Repo, user *model.User, pipeline *model.Pipeline) error {
|
||||
if pipeline.Status != model.StatusRunning && pipeline.Status != model.StatusPending && pipeline.Status != model.StatusBlocked {
|
||||
return &ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked pipeline"}
|
||||
}
|
||||
|
@ -88,7 +89,7 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, user *mode
|
|||
return err
|
||||
}
|
||||
|
||||
updatePipelineStatus(ctx, killedPipeline, repo, user)
|
||||
updatePipelineStatus(ctx, _forge, killedPipeline, repo, user)
|
||||
|
||||
if killedPipeline.Workflows, err = store.WorkflowGetTree(killedPipeline); err != nil {
|
||||
return err
|
||||
|
@ -100,6 +101,7 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, user *mode
|
|||
|
||||
func cancelPreviousPipelines(
|
||||
ctx context.Context,
|
||||
_forge forge.Forge,
|
||||
_store store.Store,
|
||||
pipeline *model.Pipeline,
|
||||
repo *model.Repo,
|
||||
|
@ -150,7 +152,7 @@ func cancelPreviousPipelines(
|
|||
continue
|
||||
}
|
||||
|
||||
if err = Cancel(ctx, _store, repo, user, active); err != nil {
|
||||
if err = Cancel(ctx, _forge, _store, repo, user, active); err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("ref", active.Ref).
|
||||
|
|
|
@ -34,7 +34,6 @@ var skipPipelineRegex = regexp.MustCompile(`\[(?i:ci *skip|skip *ci)\]`)
|
|||
|
||||
// Create a new pipeline and start it
|
||||
func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline *model.Pipeline) (*model.Pipeline, error) {
|
||||
_forge := server.Config.Services.Forge
|
||||
repoUser, err := _store.GetUser(repo.UserID)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failure to find repo owner via id '%d'", repo.UserID)
|
||||
|
@ -54,6 +53,13 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
|
|||
}
|
||||
}
|
||||
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failure to load forge for repo '%s'", repo.FullName)
|
||||
log.Error().Err(err).Str("repo", repo.FullName).Msg(msg)
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
// If the forge has a refresh token, the current access token
|
||||
// may be stale. Therefore, we should refresh prior to dispatching
|
||||
// the pipeline.
|
||||
|
@ -82,13 +88,13 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
|
|||
return nil, ErrFiltered
|
||||
} else if configFetchErr != nil {
|
||||
log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("error while fetching config '%s' in '%s' with user: '%s'", repo.Config, pipeline.Ref, repoUser.Login)
|
||||
return nil, updatePipelineWithErr(ctx, _store, pipeline, repo, repoUser, fmt.Errorf("pipeline definition not found in %s", repo.FullName))
|
||||
return nil, updatePipelineWithErr(ctx, _forge, _store, pipeline, repo, repoUser, fmt.Errorf("pipeline definition not found in %s", repo.FullName))
|
||||
}
|
||||
|
||||
pipelineItems, parseErr := parsePipeline(_store, pipeline, repoUser, repo, forgeYamlConfigs, nil)
|
||||
pipelineItems, parseErr := parsePipeline(_forge, _store, pipeline, repoUser, repo, forgeYamlConfigs, nil)
|
||||
if pipeline_errors.HasBlockingErrors(parseErr) {
|
||||
log.Debug().Str("repo", repo.FullName).Err(parseErr).Msg("failed to parse yaml")
|
||||
return nil, updatePipelineWithErr(ctx, _store, pipeline, repo, repoUser, parseErr)
|
||||
return nil, updatePipelineWithErr(ctx, _forge, _store, pipeline, repo, repoUser, parseErr)
|
||||
} else if parseErr != nil {
|
||||
pipeline.Errors = pipeline_errors.GetPipelineErrors(parseErr)
|
||||
}
|
||||
|
@ -122,7 +128,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
|
|||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
if err := prepareStart(ctx, _store, pipeline, repoUser, repo); err != nil {
|
||||
if err := prepareStart(ctx, _forge, _store, pipeline, repoUser, repo); err != nil {
|
||||
log.Error().Err(err).Str("repo", repo.FullName).Msgf("error preparing pipeline for %s#%d", repo.FullName, pipeline.Number)
|
||||
return nil, err
|
||||
}
|
||||
|
@ -131,11 +137,11 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
|
|||
return pipeline, nil
|
||||
}
|
||||
|
||||
if err := updatePipelinePending(ctx, _store, pipeline, repo, repoUser); err != nil {
|
||||
if err := updatePipelinePending(ctx, _forge, _store, pipeline, repo, repoUser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipeline, err = start(ctx, _store, pipeline, repoUser, repo, pipelineItems)
|
||||
pipeline, err = start(ctx, _forge, _store, pipeline, repoUser, repo, pipelineItems)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failed to start pipeline for %s", repo.FullName)
|
||||
log.Error().Err(err).Msg(msg)
|
||||
|
@ -145,7 +151,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
|
|||
return pipeline, nil
|
||||
}
|
||||
|
||||
func updatePipelineWithErr(ctx context.Context, _store store.Store, pipeline *model.Pipeline, repo *model.Repo, repoUser *model.User, err error) error {
|
||||
func updatePipelineWithErr(ctx context.Context, _forge forge.Forge, _store store.Store, pipeline *model.Pipeline, repo *model.Repo, repoUser *model.User, err error) error {
|
||||
_pipeline, err := UpdateToStatusError(_store, *pipeline, err)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -153,12 +159,12 @@ func updatePipelineWithErr(ctx context.Context, _store store.Store, pipeline *mo
|
|||
// update value in ref
|
||||
*pipeline = *_pipeline
|
||||
|
||||
publishPipeline(ctx, pipeline, repo, repoUser)
|
||||
publishPipeline(ctx, _forge, pipeline, repo, repoUser)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updatePipelinePending(ctx context.Context, _store store.Store, pipeline *model.Pipeline, repo *model.Repo, repoUser *model.User) error {
|
||||
func updatePipelinePending(ctx context.Context, _forge forge.Forge, _store store.Store, pipeline *model.Pipeline, repo *model.Repo, repoUser *model.User) error {
|
||||
_pipeline, err := UpdateToStatusPending(_store, *pipeline, "")
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -166,7 +172,7 @@ func updatePipelinePending(ctx context.Context, _store store.Store, pipeline *mo
|
|||
// update value in ref
|
||||
*pipeline = *_pipeline
|
||||
|
||||
publishPipeline(ctx, pipeline, repo, repoUser)
|
||||
publishPipeline(ctx, _forge, pipeline, repo, repoUser)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -20,17 +20,25 @@ import (
|
|||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||
)
|
||||
|
||||
// Decline updates the status to declined for blocked pipelines because of a gated repo
|
||||
func Decline(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo) (*model.Pipeline, error) {
|
||||
forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failure to load forge for repo '%s'", repo.FullName)
|
||||
log.Error().Err(err).Str("repo", repo.FullName).Msg(msg)
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
if pipeline.Status != model.StatusBlocked {
|
||||
return nil, fmt.Errorf("cannot decline a pipeline with status %s", pipeline.Status)
|
||||
}
|
||||
|
||||
pipeline, err := UpdateToStatusDeclined(store, *pipeline, user.Login)
|
||||
pipeline, err = UpdateToStatusDeclined(store, *pipeline, user.Login)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error updating pipeline. %w", err)
|
||||
}
|
||||
|
@ -53,7 +61,7 @@ func Decline(ctx context.Context, store store.Store, pipeline *model.Pipeline, u
|
|||
}
|
||||
}
|
||||
|
||||
updatePipelineStatus(ctx, pipeline, repo, user)
|
||||
updatePipelineStatus(ctx, forge, pipeline, repo, user)
|
||||
|
||||
publishToTopic(pipeline, repo)
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@ import (
|
|||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
)
|
||||
|
||||
func updatePipelineStatus(ctx context.Context, pipeline *model.Pipeline, repo *model.Repo, user *model.User) {
|
||||
func updatePipelineStatus(ctx context.Context, forge forge.Forge, pipeline *model.Pipeline, repo *model.Repo, user *model.User) {
|
||||
for _, workflow := range pipeline.Workflows {
|
||||
err := server.Config.Services.Forge.Status(ctx, user, repo, pipeline, workflow)
|
||||
err := forge.Status(ctx, user, repo, pipeline, workflow)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, pipeline.Number)
|
||||
return
|
||||
|
|
|
@ -24,14 +24,15 @@ import (
|
|||
pipeline_errors "go.woodpecker-ci.org/woodpecker/v2/pipeline/errors"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline/frontend/yaml/compiler"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
forge_types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/pipeline/stepbuilder"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||
)
|
||||
|
||||
func parsePipeline(store store.Store, currentPipeline *model.Pipeline, user *model.User, repo *model.Repo, yamls []*forge_types.FileMeta, envs map[string]string) ([]*stepbuilder.Item, error) {
|
||||
netrc, err := server.Config.Services.Forge.Netrc(user, repo)
|
||||
func parsePipeline(forge forge.Forge, store store.Store, currentPipeline *model.Pipeline, user *model.User, repo *model.Repo, yamls []*forge_types.FileMeta, envs map[string]string) ([]*stepbuilder.Item, error) {
|
||||
netrc, err := forge.Netrc(user, repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to generate netrc file")
|
||||
}
|
||||
|
@ -80,7 +81,7 @@ func parsePipeline(store store.Store, currentPipeline *model.Pipeline, user *mod
|
|||
Envs: envs,
|
||||
Host: server.Config.Server.Host,
|
||||
Yamls: yamls,
|
||||
Forge: server.Config.Services.Forge,
|
||||
Forge: forge,
|
||||
ProxyOpts: compiler.ProxyOptions{
|
||||
NoProxy: server.Config.Pipeline.Proxy.No,
|
||||
HTTPProxy: server.Config.Pipeline.Proxy.HTTP,
|
||||
|
@ -90,23 +91,23 @@ func parsePipeline(store store.Store, currentPipeline *model.Pipeline, user *mod
|
|||
return b.Build()
|
||||
}
|
||||
|
||||
func createPipelineItems(c context.Context, store store.Store,
|
||||
func createPipelineItems(c context.Context, forge forge.Forge, store store.Store,
|
||||
currentPipeline *model.Pipeline, user *model.User, repo *model.Repo,
|
||||
yamls []*forge_types.FileMeta, envs map[string]string,
|
||||
) (*model.Pipeline, []*stepbuilder.Item, error) {
|
||||
pipelineItems, err := parsePipeline(store, currentPipeline, user, repo, yamls, envs)
|
||||
pipelineItems, err := parsePipeline(forge, store, currentPipeline, user, repo, yamls, envs)
|
||||
if pipeline_errors.HasBlockingErrors(err) {
|
||||
currentPipeline, uerr := UpdateToStatusError(store, *currentPipeline, err)
|
||||
if uerr != nil {
|
||||
log.Error().Err(uerr).Msgf("error setting error status of pipeline for %s#%d", repo.FullName, currentPipeline.Number)
|
||||
} else {
|
||||
updatePipelineStatus(c, currentPipeline, repo, user)
|
||||
updatePipelineStatus(c, forge, currentPipeline, repo, user)
|
||||
}
|
||||
|
||||
return currentPipeline, nil, err
|
||||
} else if err != nil {
|
||||
currentPipeline.Errors = pipeline_errors.GetPipelineErrors(err)
|
||||
err = updatePipelinePending(c, store, currentPipeline, repo, user)
|
||||
err = updatePipelinePending(c, forge, store, currentPipeline, repo, user)
|
||||
}
|
||||
|
||||
currentPipeline = setPipelineStepsOnPipeline(currentPipeline, pipelineItems)
|
||||
|
|
|
@ -29,7 +29,13 @@ import (
|
|||
|
||||
// Restart a pipeline by creating a new one out of the old and start it
|
||||
func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipeline, user *model.User, repo *model.Repo, envs map[string]string) (*model.Pipeline, error) {
|
||||
forge := server.Config.Services.Forge
|
||||
forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failure to load forge for repo '%s'", repo.FullName)
|
||||
log.Error().Err(err).Str("repo", repo.FullName).Msg(msg)
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
switch lastPipeline.Status {
|
||||
case model.StatusDeclined,
|
||||
model.StatusBlocked:
|
||||
|
@ -72,7 +78,7 @@ func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipelin
|
|||
if uerr != nil {
|
||||
log.Debug().Err(uerr).Msg("failure to update pipeline status")
|
||||
} else {
|
||||
updatePipelineStatus(ctx, newPipeline, repo, user)
|
||||
updatePipelineStatus(ctx, forge, newPipeline, repo, user)
|
||||
}
|
||||
return newPipeline, nil
|
||||
}
|
||||
|
@ -82,20 +88,20 @@ func Restart(ctx context.Context, store store.Store, lastPipeline *model.Pipelin
|
|||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
newPipeline, pipelineItems, err := createPipelineItems(ctx, store, newPipeline, user, repo, pipelineFiles, envs)
|
||||
newPipeline, pipelineItems, err := createPipelineItems(ctx, forge, store, newPipeline, user, repo, pipelineFiles, envs)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failure to createPipelineItems for %s", repo.FullName)
|
||||
log.Error().Err(err).Msg(msg)
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
if err := prepareStart(ctx, store, newPipeline, user, repo); err != nil {
|
||||
if err := prepareStart(ctx, forge, store, newPipeline, user, repo); err != nil {
|
||||
msg := fmt.Sprintf("failure to prepare pipeline for %s", repo.FullName)
|
||||
log.Error().Err(err).Msg(msg)
|
||||
return nil, fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
newPipeline, err = start(ctx, store, newPipeline, user, repo, pipelineItems)
|
||||
newPipeline, err = start(ctx, forge, store, newPipeline, user, repo, pipelineItems)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failure to start pipeline for %s", repo.FullName)
|
||||
log.Error().Err(err).Msg(msg)
|
||||
|
|
|
@ -19,20 +19,21 @@ import (
|
|||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/pipeline/stepbuilder"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||
)
|
||||
|
||||
// start a pipeline, make sure it was stored persistent in the store before
|
||||
func start(ctx context.Context, store store.Store, activePipeline *model.Pipeline, user *model.User, repo *model.Repo, pipelineItems []*stepbuilder.Item) (*model.Pipeline, error) {
|
||||
func start(ctx context.Context, forge forge.Forge, store store.Store, activePipeline *model.Pipeline, user *model.User, repo *model.Repo, pipelineItems []*stepbuilder.Item) (*model.Pipeline, error) {
|
||||
// call to cancel previous pipelines if needed
|
||||
if err := cancelPreviousPipelines(ctx, store, activePipeline, repo, user); err != nil {
|
||||
if err := cancelPreviousPipelines(ctx, forge, store, activePipeline, repo, user); err != nil {
|
||||
// should be not breaking
|
||||
log.Error().Err(err).Msg("failed to cancel previous pipelines")
|
||||
}
|
||||
|
||||
publishPipeline(ctx, activePipeline, repo, user)
|
||||
publishPipeline(ctx, forge, activePipeline, repo, user)
|
||||
|
||||
if err := queuePipeline(ctx, repo, pipelineItems); err != nil {
|
||||
log.Error().Err(err).Msg("queuePipeline")
|
||||
|
@ -42,17 +43,17 @@ func start(ctx context.Context, store store.Store, activePipeline *model.Pipelin
|
|||
return activePipeline, nil
|
||||
}
|
||||
|
||||
func prepareStart(ctx context.Context, store store.Store, activePipeline *model.Pipeline, user *model.User, repo *model.Repo) error {
|
||||
func prepareStart(ctx context.Context, forge forge.Forge, store store.Store, activePipeline *model.Pipeline, user *model.User, repo *model.Repo) error {
|
||||
if err := store.WorkflowsCreate(activePipeline.Workflows); err != nil {
|
||||
log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting steps for %s#%d", repo.FullName, activePipeline.Number)
|
||||
return err
|
||||
}
|
||||
|
||||
publishPipeline(ctx, activePipeline, repo, user)
|
||||
publishPipeline(ctx, forge, activePipeline, repo, user)
|
||||
return nil
|
||||
}
|
||||
|
||||
func publishPipeline(ctx context.Context, pipeline *model.Pipeline, repo *model.Repo, repoUser *model.User) {
|
||||
func publishPipeline(ctx context.Context, forge forge.Forge, pipeline *model.Pipeline, repo *model.Repo, repoUser *model.User) {
|
||||
publishToTopic(pipeline, repo)
|
||||
updatePipelineStatus(ctx, pipeline, repo, repoUser)
|
||||
updatePipelineStatus(ctx, forge, pipeline, repo, repoUser)
|
||||
}
|
||||
|
|
|
@ -106,6 +106,13 @@ func SetPerm() gin.HandlerFunc {
|
|||
_store := store.FromContext(c)
|
||||
user := User(c)
|
||||
repo := Repo(c)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from repo")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
perm := new(model.Perm)
|
||||
|
||||
if user != nil {
|
||||
|
@ -116,7 +123,7 @@ func SetPerm() gin.HandlerFunc {
|
|||
user.Login, repo.FullName)
|
||||
}
|
||||
if time.Unix(perm.Synced, 0).Add(time.Hour).Before(time.Now()) {
|
||||
_repo, err := server.Config.Services.Forge.Repo(c, user, repo.ForgeRemoteID, repo.Owner, repo.Name)
|
||||
_repo, err := _forge.Repo(c, user, repo.ForgeRemoteID, repo.Owner, repo.Name)
|
||||
if err == nil {
|
||||
log.Debug().Msgf("synced user permission for %s %s", user.Login, repo.FullName)
|
||||
perm = _repo.Perm
|
||||
|
|
|
@ -145,7 +145,14 @@ func MustOrgMember(admin bool) gin.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
perm, err := server.Config.Services.Membership.Get(c, user, org.Name)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromUser(user)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Cannot get forge from user")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
perm, err := server.Config.Services.Membership.Get(c, _forge, user, org.Name)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to check membership")
|
||||
c.String(http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
package token
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||
|
@ -26,7 +28,13 @@ import (
|
|||
func Refresh(c *gin.Context) {
|
||||
user := session.User(c)
|
||||
if user != nil {
|
||||
forge.Refresh(c, server.Config.Services.Forge, store.FromContext(c), user)
|
||||
_forge, err := server.Config.Services.Manager.ForgeFromUser(user)
|
||||
if err != nil {
|
||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
forge.Refresh(c, _forge, store.FromContext(c), user)
|
||||
}
|
||||
|
||||
c.Next()
|
||||
|
|
|
@ -16,9 +16,12 @@ package services
|
|||
|
||||
import (
|
||||
"crypto"
|
||||
"time"
|
||||
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/services/config"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/services/environment"
|
||||
|
@ -27,56 +30,119 @@ import (
|
|||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
//go:generate mockery --name Manager --output mocks --case underscore
|
||||
|
||||
const forgeCacheTTL = 10 * time.Minute
|
||||
|
||||
type SetupForge func(forge *model.Forge) (forge.Forge, error)
|
||||
|
||||
type Manager interface {
|
||||
SignaturePublicKey() crypto.PublicKey
|
||||
SecretServiceFromRepo(repo *model.Repo) secret.Service
|
||||
SecretService() secret.Service
|
||||
RegistryServiceFromRepo(repo *model.Repo) registry.Service
|
||||
RegistryService() registry.Service
|
||||
ConfigServiceFromRepo(repo *model.Repo) config.Service
|
||||
EnvironmentService() environment.Service
|
||||
ForgeFromRepo(repo *model.Repo) (forge.Forge, error)
|
||||
ForgeFromUser(user *model.User) (forge.Forge, error)
|
||||
ForgeMain() (forge.Forge, error)
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
signaturePrivateKey crypto.PrivateKey
|
||||
signaturePublicKey crypto.PublicKey
|
||||
store store.Store
|
||||
secret secret.Service
|
||||
registry registry.Service
|
||||
config config.Service
|
||||
environment environment.Service
|
||||
signaturePrivateKey crypto.PrivateKey
|
||||
signaturePublicKey crypto.PublicKey
|
||||
forgeCache *ttlcache.Cache[int64, forge.Forge]
|
||||
setupForge SetupForge
|
||||
}
|
||||
|
||||
func NewManager(c *cli.Context, store store.Store) (*Manager, error) {
|
||||
func NewManager(c *cli.Context, store store.Store, setupForge SetupForge) (Manager, error) {
|
||||
signaturePrivateKey, signaturePublicKey, err := setupSignatureKeys(store)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Manager{
|
||||
err = setupForgeService(c, store)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &manager{
|
||||
signaturePrivateKey: signaturePrivateKey,
|
||||
signaturePublicKey: signaturePublicKey,
|
||||
store: store,
|
||||
secret: setupSecretService(store),
|
||||
registry: setupRegistryService(store, c.String("docker-config")),
|
||||
config: setupConfigService(c, signaturePrivateKey),
|
||||
environment: environment.Parse(c.StringSlice("environment")),
|
||||
forgeCache: ttlcache.New(ttlcache.WithDisableTouchOnHit[int64, forge.Forge]()),
|
||||
setupForge: setupForge,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *Manager) SignaturePublicKey() crypto.PublicKey {
|
||||
return e.signaturePublicKey
|
||||
func (m *manager) SignaturePublicKey() crypto.PublicKey {
|
||||
return m.signaturePublicKey
|
||||
}
|
||||
|
||||
func (e *Manager) SecretServiceFromRepo(_ *model.Repo) secret.Service {
|
||||
return e.SecretService()
|
||||
func (m *manager) SecretServiceFromRepo(_ *model.Repo) secret.Service {
|
||||
return m.SecretService()
|
||||
}
|
||||
|
||||
func (e *Manager) SecretService() secret.Service {
|
||||
return e.secret
|
||||
func (m *manager) SecretService() secret.Service {
|
||||
return m.secret
|
||||
}
|
||||
|
||||
func (e *Manager) RegistryServiceFromRepo(_ *model.Repo) registry.Service {
|
||||
return e.RegistryService()
|
||||
func (m *manager) RegistryServiceFromRepo(_ *model.Repo) registry.Service {
|
||||
return m.RegistryService()
|
||||
}
|
||||
|
||||
func (e *Manager) RegistryService() registry.Service {
|
||||
return e.registry
|
||||
func (m *manager) RegistryService() registry.Service {
|
||||
return m.registry
|
||||
}
|
||||
|
||||
func (e *Manager) ConfigServiceFromRepo(_ *model.Repo) config.Service {
|
||||
func (m *manager) ConfigServiceFromRepo(_ *model.Repo) config.Service {
|
||||
// TODO: decied based on repo property which config service to use
|
||||
return e.config
|
||||
return m.config
|
||||
}
|
||||
|
||||
func (e *Manager) EnvironmentService() environment.Service {
|
||||
return e.environment
|
||||
func (m *manager) EnvironmentService() environment.Service {
|
||||
return m.environment
|
||||
}
|
||||
|
||||
func (m *manager) ForgeFromRepo(repo *model.Repo) (forge.Forge, error) {
|
||||
return m.getForgeByID(repo.ForgeID)
|
||||
}
|
||||
|
||||
func (m *manager) ForgeFromUser(user *model.User) (forge.Forge, error) {
|
||||
return m.getForgeByID(user.ForgeID)
|
||||
}
|
||||
|
||||
func (m *manager) ForgeMain() (forge.Forge, error) {
|
||||
return m.getForgeByID(1) // main forge is always 1 and is configured via environment variables
|
||||
}
|
||||
|
||||
func (m *manager) getForgeByID(id int64) (forge.Forge, error) {
|
||||
item := m.forgeCache.Get(id)
|
||||
if item != nil && !item.IsExpired() {
|
||||
return item.Value(), nil
|
||||
}
|
||||
|
||||
forgeModel, err := m.store.ForgeGet(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
forge, err := m.setupForge(forgeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.forgeCache.Set(id, forge, forgeCacheTTL)
|
||||
|
||||
return forge, nil
|
||||
}
|
||||
|
|
270
server/services/mocks/manager.go
Normal file
270
server/services/mocks/manager.go
Normal file
|
@ -0,0 +1,270 @@
|
|||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
crypto "crypto"
|
||||
|
||||
config "go.woodpecker-ci.org/woodpecker/v2/server/services/config"
|
||||
|
||||
environment "go.woodpecker-ci.org/woodpecker/v2/server/services/environment"
|
||||
|
||||
forge "go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
model "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
|
||||
registry "go.woodpecker-ci.org/woodpecker/v2/server/services/registry"
|
||||
|
||||
secret "go.woodpecker-ci.org/woodpecker/v2/server/services/secret"
|
||||
)
|
||||
|
||||
// Manager is an autogenerated mock type for the Manager type
|
||||
type Manager struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// ConfigServiceFromRepo provides a mock function with given fields: repo
|
||||
func (_m *Manager) ConfigServiceFromRepo(repo *model.Repo) config.Service {
|
||||
ret := _m.Called(repo)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ConfigServiceFromRepo")
|
||||
}
|
||||
|
||||
var r0 config.Service
|
||||
if rf, ok := ret.Get(0).(func(*model.Repo) config.Service); ok {
|
||||
r0 = rf(repo)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(config.Service)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// EnvironmentService provides a mock function with given fields:
|
||||
func (_m *Manager) EnvironmentService() environment.Service {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for EnvironmentService")
|
||||
}
|
||||
|
||||
var r0 environment.Service
|
||||
if rf, ok := ret.Get(0).(func() environment.Service); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(environment.Service)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// ForgeFromRepo provides a mock function with given fields: repo
|
||||
func (_m *Manager) ForgeFromRepo(repo *model.Repo) (forge.Forge, error) {
|
||||
ret := _m.Called(repo)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ForgeFromRepo")
|
||||
}
|
||||
|
||||
var r0 forge.Forge
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*model.Repo) (forge.Forge, error)); ok {
|
||||
return rf(repo)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*model.Repo) forge.Forge); ok {
|
||||
r0 = rf(repo)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(forge.Forge)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*model.Repo) error); ok {
|
||||
r1 = rf(repo)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ForgeFromUser provides a mock function with given fields: user
|
||||
func (_m *Manager) ForgeFromUser(user *model.User) (forge.Forge, error) {
|
||||
ret := _m.Called(user)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ForgeFromUser")
|
||||
}
|
||||
|
||||
var r0 forge.Forge
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*model.User) (forge.Forge, error)); ok {
|
||||
return rf(user)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*model.User) forge.Forge); ok {
|
||||
r0 = rf(user)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(forge.Forge)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*model.User) error); ok {
|
||||
r1 = rf(user)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ForgeMain provides a mock function with given fields:
|
||||
func (_m *Manager) ForgeMain() (forge.Forge, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ForgeMain")
|
||||
}
|
||||
|
||||
var r0 forge.Forge
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (forge.Forge, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() forge.Forge); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(forge.Forge)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RegistryService provides a mock function with given fields:
|
||||
func (_m *Manager) RegistryService() registry.Service {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RegistryService")
|
||||
}
|
||||
|
||||
var r0 registry.Service
|
||||
if rf, ok := ret.Get(0).(func() registry.Service); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(registry.Service)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// RegistryServiceFromRepo provides a mock function with given fields: repo
|
||||
func (_m *Manager) RegistryServiceFromRepo(repo *model.Repo) registry.Service {
|
||||
ret := _m.Called(repo)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RegistryServiceFromRepo")
|
||||
}
|
||||
|
||||
var r0 registry.Service
|
||||
if rf, ok := ret.Get(0).(func(*model.Repo) registry.Service); ok {
|
||||
r0 = rf(repo)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(registry.Service)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SecretService provides a mock function with given fields:
|
||||
func (_m *Manager) SecretService() secret.Service {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SecretService")
|
||||
}
|
||||
|
||||
var r0 secret.Service
|
||||
if rf, ok := ret.Get(0).(func() secret.Service); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(secret.Service)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SecretServiceFromRepo provides a mock function with given fields: repo
|
||||
func (_m *Manager) SecretServiceFromRepo(repo *model.Repo) secret.Service {
|
||||
ret := _m.Called(repo)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SecretServiceFromRepo")
|
||||
}
|
||||
|
||||
var r0 secret.Service
|
||||
if rf, ok := ret.Get(0).(func(*model.Repo) secret.Service); ok {
|
||||
r0 = rf(repo)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(secret.Service)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SignaturePublicKey provides a mock function with given fields:
|
||||
func (_m *Manager) SignaturePublicKey() crypto.PublicKey {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SignaturePublicKey")
|
||||
}
|
||||
|
||||
var r0 crypto.PublicKey
|
||||
if rf, ok := ret.Get(0).(func() crypto.PublicKey); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(crypto.PublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewManager(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *Manager {
|
||||
mock := &Manager{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/services/config"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/services/registry"
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/services/secret"
|
||||
|
@ -93,3 +94,70 @@ func setupSignatureKeys(_store store.Store) (crypto.PrivateKey, crypto.PublicKey
|
|||
privateKey := ed25519.PrivateKey(privKeyStr)
|
||||
return privateKey, privateKey.Public(), nil
|
||||
}
|
||||
|
||||
func setupForgeService(c *cli.Context, _store store.Store) error {
|
||||
_forge, err := _store.ForgeGet(1)
|
||||
if err != nil && !errors.Is(err, types.RecordNotExist) {
|
||||
return err
|
||||
}
|
||||
forgeExists := err == nil
|
||||
if _forge == nil {
|
||||
_forge = &model.Forge{
|
||||
ID: 0,
|
||||
}
|
||||
}
|
||||
if _forge.AdditionalOptions == nil {
|
||||
_forge.AdditionalOptions = make(map[string]any)
|
||||
}
|
||||
|
||||
_forge.Client = c.String("forge-oauth-client")
|
||||
_forge.ClientSecret = c.String("forge-oauth-secret")
|
||||
_forge.URL = c.String("forge-url")
|
||||
_forge.SkipVerify = c.Bool("forge-skip-verify")
|
||||
|
||||
switch {
|
||||
case c.String("addon-forge") != "":
|
||||
_forge.Type = model.ForgeTypeAddon
|
||||
_forge.AdditionalOptions["executable"] = c.String("addon-forge")
|
||||
case c.Bool("github"):
|
||||
_forge.Type = model.ForgeTypeGithub
|
||||
_forge.AdditionalOptions["merge-ref"] = c.Bool("github-merge-ref")
|
||||
_forge.AdditionalOptions["public-only"] = c.Bool("github-public-only")
|
||||
if _forge.URL == "" {
|
||||
_forge.URL = "https://github.com"
|
||||
}
|
||||
case c.Bool("gitlab"):
|
||||
_forge.Type = model.ForgeTypeGitlab
|
||||
if _forge.URL == "" {
|
||||
_forge.URL = "https://gitlab.com"
|
||||
}
|
||||
case c.Bool("gitea"):
|
||||
_forge.Type = model.ForgeTypeGitea
|
||||
_forge.AdditionalOptions["oauth-server"] = c.String("gitea-oauth-server")
|
||||
if _forge.URL == "" {
|
||||
_forge.URL = "https://try.gitea.com"
|
||||
}
|
||||
case c.Bool("bitbucket"):
|
||||
_forge.Type = model.ForgeTypeBitbucket
|
||||
case c.Bool("bitbucket-dc"):
|
||||
_forge.Type = model.ForgeTypeBitbucketDatacenter
|
||||
_forge.AdditionalOptions["git-username"] = c.String("bitbucket-dc-git-username")
|
||||
_forge.AdditionalOptions["git-password"] = c.String("bitbucket-dc-git-password")
|
||||
default:
|
||||
return errors.New("forge not configured")
|
||||
}
|
||||
|
||||
if forgeExists {
|
||||
err := _store.ForgeUpdate(_forge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err := _store.ForgeCreate(_forge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
54
server/store/datastore/forge.go
Normal file
54
server/store/datastore/forge.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2022 Woodpecker Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
)
|
||||
|
||||
func (s storage) ForgeGet(id int64) (*model.Forge, error) {
|
||||
forge := new(model.Forge)
|
||||
return forge, wrapGet(s.engine.ID(id).Get(forge))
|
||||
}
|
||||
|
||||
func (s storage) ForgeList(p *model.ListOptions) ([]*model.Forge, error) {
|
||||
forges := make([]*model.Forge, 0, 10)
|
||||
return forges, s.paginate(p).Find(&forges)
|
||||
}
|
||||
|
||||
func (s storage) ForgeCreate(forge *model.Forge) error {
|
||||
// only Insert set auto created ID back to object
|
||||
_, err := s.engine.Insert(forge)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s storage) ForgeUpdate(forge *model.Forge) error {
|
||||
_, err := s.engine.ID(forge.ID).AllCols().Update(forge)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s storage) ForgeDelete(forge *model.Forge) error {
|
||||
sess := s.engine.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.ID(forge.ID).Delete(new(model.Forge)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
71
server/store/datastore/forge_test.go
Normal file
71
server/store/datastore/forge_test.go
Normal file
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2024 Woodpecker Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
)
|
||||
|
||||
func TestForgeCRUD(t *testing.T) {
|
||||
store, closer := newTestStore(t, new(model.Forge), new(model.Repo), new(model.User))
|
||||
defer closer()
|
||||
|
||||
forge1 := &model.Forge{
|
||||
Type: "github",
|
||||
URL: "https://github.com",
|
||||
Client: "client",
|
||||
ClientSecret: "secret",
|
||||
SkipVerify: false,
|
||||
AdditionalOptions: map[string]any{
|
||||
"foo": "bar",
|
||||
},
|
||||
}
|
||||
|
||||
// create first forge to play with
|
||||
assert.NoError(t, store.ForgeCreate(forge1))
|
||||
assert.EqualValues(t, "github", forge1.Type)
|
||||
|
||||
// retrieve it
|
||||
forgeOne, err := store.ForgeGet(forge1.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, forge1, forgeOne)
|
||||
|
||||
// change type
|
||||
assert.NoError(t, store.ForgeUpdate(&model.Forge{ID: forge1.ID, Type: "gitlab"}))
|
||||
|
||||
// find updated forge by id
|
||||
forgeOne, err = store.ForgeGet(forge1.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "gitlab", forgeOne.Type)
|
||||
|
||||
// create two more forges and repos
|
||||
someUser := &model.Forge{Type: "bitbucket"}
|
||||
assert.NoError(t, store.ForgeCreate(someUser))
|
||||
assert.NoError(t, store.ForgeCreate(&model.Forge{Type: "gitea"}))
|
||||
|
||||
// get all repos for a specific forge
|
||||
forges, err := store.ForgeList(&model.ListOptions{All: true})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, forges, 3)
|
||||
|
||||
// delete an forge and check if it's gone
|
||||
assert.NoError(t, store.ForgeDelete(forge1))
|
||||
_, err = store.ForgeGet(forge1.ID)
|
||||
assert.Error(t, err)
|
||||
}
|
46
server/store/datastore/migration/030_set_default_forge_id.go
Normal file
46
server/store/datastore/migration/030_set_default_forge_id.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2024 Woodpecker Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package migration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"src.techknowlogick.com/xormigrate"
|
||||
"xorm.io/xorm"
|
||||
|
||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||
)
|
||||
|
||||
var setForgeID = xormigrate.Migration{
|
||||
ID: "set-forge-id",
|
||||
MigrateSession: func(sess *xorm.Session) (err error) {
|
||||
if err := sess.Sync(new(model.User), new(model.Repo), new(model.Forge), new(model.Org)); err != nil {
|
||||
return fmt.Errorf("sync new models failed: %w", err)
|
||||
}
|
||||
|
||||
_, err = sess.Exec(fmt.Sprintf("UPDATE `%s` SET forge_id=1;", model.User{}.TableName()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sess.Exec(fmt.Sprintf("UPDATE `%s` SET forge_id=1;", model.Org{}.TableName()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = sess.Exec(fmt.Sprintf("UPDATE `%s` SET forge_id=1;", model.Repo{}.TableName()))
|
||||
return err
|
||||
},
|
||||
}
|
|
@ -59,6 +59,7 @@ var migrationTasks = []*xormigrate.Migration{
|
|||
&convertToNewPipelineErrorFormat,
|
||||
&renameLinkToURL,
|
||||
&cleanRegistryPipeline,
|
||||
&setForgeID,
|
||||
}
|
||||
|
||||
var allBeans = []any{
|
||||
|
@ -77,6 +78,7 @@ var allBeans = []any{
|
|||
new(model.ServerConfig),
|
||||
new(model.Cron),
|
||||
new(model.Redirection),
|
||||
new(model.Forge),
|
||||
new(model.Workflow),
|
||||
new(model.Org),
|
||||
}
|
||||
|
|
|
@ -539,6 +539,152 @@ func (_m *Store) DeleteUser(_a0 *model.User) error {
|
|||
return r0
|
||||
}
|
||||
|
||||
// ForgeCreate provides a mock function with given fields: _a0
|
||||
func (_m *Store) ForgeCreate(_a0 *model.Forge) error {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*model.Forge) error); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// ForgeDelete provides a mock function with given fields: _a0
|
||||
func (_m *Store) ForgeDelete(_a0 *model.Forge) error {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*model.Forge) error); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// ForgeFindByRepo provides a mock function with given fields: _a0
|
||||
func (_m *Store) ForgeFindByRepo(_a0 *model.Repo) (*model.Forge, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 *model.Forge
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*model.Repo) (*model.Forge, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*model.Repo) *model.Forge); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Forge)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*model.Repo) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ForgeFindByUser provides a mock function with given fields: _a0
|
||||
func (_m *Store) ForgeFindByUser(_a0 *model.User) (*model.Forge, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 *model.Forge
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*model.User) (*model.Forge, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*model.User) *model.Forge); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Forge)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*model.User) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ForgeGet provides a mock function with given fields: _a0
|
||||
func (_m *Store) ForgeGet(_a0 int64) (*model.Forge, error) {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 *model.Forge
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(int64) (*model.Forge, error)); ok {
|
||||
return rf(_a0)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(int64) *model.Forge); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Forge)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(int64) error); ok {
|
||||
r1 = rf(_a0)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ForgeList provides a mock function with given fields: p
|
||||
func (_m *Store) ForgeList(p *model.ListOptions) ([]*model.Forge, error) {
|
||||
ret := _m.Called(p)
|
||||
|
||||
var r0 []*model.Forge
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(*model.ListOptions) ([]*model.Forge, error)); ok {
|
||||
return rf(p)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*model.ListOptions) []*model.Forge); ok {
|
||||
r0 = rf(p)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.Forge)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*model.ListOptions) error); ok {
|
||||
r1 = rf(p)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ForgeUpdate provides a mock function with given fields: _a0
|
||||
func (_m *Store) ForgeUpdate(_a0 *model.Forge) error {
|
||||
ret := _m.Called(_a0)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*model.Forge) error); ok {
|
||||
r0 = rf(_a0)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetActivePipelineList provides a mock function with given fields: repo
|
||||
func (_m *Store) GetActivePipelineList(repo *model.Repo) ([]*model.Pipeline, error) {
|
||||
ret := _m.Called(repo)
|
||||
|
|
|
@ -159,6 +159,13 @@ type Store interface {
|
|||
CronListNextExecute(int64, int64) ([]*model.Cron, error)
|
||||
CronGetLock(*model.Cron, int64) (bool, error)
|
||||
|
||||
// Forge
|
||||
ForgeCreate(*model.Forge) error
|
||||
ForgeGet(int64) (*model.Forge, error)
|
||||
ForgeList(p *model.ListOptions) ([]*model.Forge, error)
|
||||
ForgeUpdate(*model.Forge) error
|
||||
ForgeDelete(*model.Forge) error
|
||||
|
||||
// Agent
|
||||
AgentCreate(*model.Agent) error
|
||||
AgentFind(int64) (*model.Agent, error)
|
||||
|
|
|
@ -39,12 +39,20 @@ func Config(c *gin.Context) {
|
|||
).Sign(user.Hash)
|
||||
}
|
||||
|
||||
// TODO: remove this and use the forge type from the corresponding repo
|
||||
mainForge, err := server.Config.Services.Manager.ForgeMain()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("could not get main forge")
|
||||
c.AbortWithStatus(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
configData := map[string]any{
|
||||
"user": user,
|
||||
"csrf": csrf,
|
||||
"version": version.String(),
|
||||
"skip_version_check": server.Config.WebUI.SkipVersionCheck,
|
||||
"forge": server.Config.Services.Forge.Name(),
|
||||
"forge": mainForge.Name(),
|
||||
"root_path": server.Config.Server.RootPath,
|
||||
"enable_swagger": server.Config.WebUI.EnableSwagger,
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ const router = useRouter();
|
|||
const i18n = useI18n();
|
||||
const config = useConfig();
|
||||
|
||||
const { forge } = useConfig();
|
||||
const { forge } = useConfig(); // TODO: remove this and use the forge type from the corresponding repo
|
||||
const repo = repoStore.getRepo(repositoryId);
|
||||
const repoPermissions = ref<RepoPermissions>();
|
||||
const pipelines = pipelineStore.getRepoPipelines(repositoryId);
|
||||
|
|
Loading…
Reference in a new issue