mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-22 16:36:30 +00:00
Allow login using multiple forges (#3822)
This commit is contained in:
parent
a26c7a475b
commit
b12d676546
19 changed files with 1182 additions and 97 deletions
|
@ -265,13 +265,6 @@ func run(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupEvilGlobals(c *cli.Context, s store.Store) error {
|
func setupEvilGlobals(c *cli.Context, s store.Store) error {
|
||||||
// secrets
|
|
||||||
var err error
|
|
||||||
server.Config.Server.JWTSecret, err = setupJWTSecret(s)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not setup jwt secret: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// services
|
// services
|
||||||
server.Config.Services.Queue = setupQueue(c, s)
|
server.Config.Services.Queue = setupQueue(c, s)
|
||||||
server.Config.Services.Logs = logging.New()
|
server.Config.Services.Logs = logging.New()
|
||||||
|
@ -319,6 +312,10 @@ func setupEvilGlobals(c *cli.Context, s store.Store) error {
|
||||||
server.Config.Pipeline.Proxy.HTTPS = c.String("backend-https-proxy")
|
server.Config.Pipeline.Proxy.HTTPS = c.String("backend-https-proxy")
|
||||||
|
|
||||||
// server configuration
|
// server configuration
|
||||||
|
server.Config.Server.JWTSecret, err = setupJWTSecret(s)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not setup jwt secret: %w", err)
|
||||||
|
}
|
||||||
server.Config.Server.Cert = c.String("server-cert")
|
server.Config.Server.Cert = c.String("server-cert")
|
||||||
server.Config.Server.Key = c.String("server-key")
|
server.Config.Server.Key = c.String("server-key")
|
||||||
server.Config.Server.AgentToken = c.String("agent-secret")
|
server.Config.Server.AgentToken = c.String("agent-secret")
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.34.2
|
// protoc-gen-go v1.34.1
|
||||||
// protoc v4.25.1
|
// protoc v4.25.1
|
||||||
// source: woodpecker.proto
|
// source: woodpecker.proto
|
||||||
|
|
||||||
|
@ -1312,7 +1312,7 @@ func file_woodpecker_proto_rawDescGZIP() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_woodpecker_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
|
var file_woodpecker_proto_msgTypes = make([]protoimpl.MessageInfo, 21)
|
||||||
var file_woodpecker_proto_goTypes = []any{
|
var file_woodpecker_proto_goTypes = []interface{}{
|
||||||
(*StepState)(nil), // 0: proto.StepState
|
(*StepState)(nil), // 0: proto.StepState
|
||||||
(*WorkflowState)(nil), // 1: proto.WorkflowState
|
(*WorkflowState)(nil), // 1: proto.WorkflowState
|
||||||
(*LogEntry)(nil), // 2: proto.LogEntry
|
(*LogEntry)(nil), // 2: proto.LogEntry
|
||||||
|
@ -1380,7 +1380,7 @@ func file_woodpecker_proto_init() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !protoimpl.UnsafeEnabled {
|
if !protoimpl.UnsafeEnabled {
|
||||||
file_woodpecker_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*StepState); i {
|
switch v := v.(*StepState); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1392,7 +1392,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*WorkflowState); i {
|
switch v := v.(*WorkflowState); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1404,7 +1404,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*LogEntry); i {
|
switch v := v.(*LogEntry); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1416,7 +1416,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Filter); i {
|
switch v := v.(*Filter); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1428,7 +1428,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Workflow); i {
|
switch v := v.(*Workflow); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1440,7 +1440,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[5].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*NextRequest); i {
|
switch v := v.(*NextRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1452,7 +1452,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[6].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*InitRequest); i {
|
switch v := v.(*InitRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1464,7 +1464,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[7].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*WaitRequest); i {
|
switch v := v.(*WaitRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1476,7 +1476,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[8].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*DoneRequest); i {
|
switch v := v.(*DoneRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1488,7 +1488,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[9].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*ExtendRequest); i {
|
switch v := v.(*ExtendRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1500,7 +1500,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[10].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*UpdateRequest); i {
|
switch v := v.(*UpdateRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1512,7 +1512,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[11].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*LogRequest); i {
|
switch v := v.(*LogRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1524,7 +1524,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[12].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*Empty); i {
|
switch v := v.(*Empty); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1536,7 +1536,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[13].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*ReportHealthRequest); i {
|
switch v := v.(*ReportHealthRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1548,7 +1548,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[14].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*RegisterAgentRequest); i {
|
switch v := v.(*RegisterAgentRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1560,7 +1560,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[15].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*VersionResponse); i {
|
switch v := v.(*VersionResponse); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1572,7 +1572,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[16].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*NextResponse); i {
|
switch v := v.(*NextResponse); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1584,7 +1584,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[17].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*RegisterAgentResponse); i {
|
switch v := v.(*RegisterAgentResponse); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1596,7 +1596,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[18].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*AuthRequest); i {
|
switch v := v.(*AuthRequest); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
@ -1608,7 +1608,7 @@ func file_woodpecker_proto_init() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_woodpecker_proto_msgTypes[19].Exporter = func(v any, i int) any {
|
file_woodpecker_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
|
||||||
switch v := v.(*AuthResponse); i {
|
switch v := v.(*AuthResponse); i {
|
||||||
case 0:
|
case 0:
|
||||||
return &v.state
|
return &v.state
|
||||||
|
|
|
@ -104,18 +104,47 @@ func BlockTilQueueHasRunningItem(c *gin.Context) {
|
||||||
func PostHook(c *gin.Context) {
|
func PostHook(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
|
|
||||||
_forge, err := server.Config.Services.Manager.ForgeByID(1) // TODO: get the forge for the specific repo somehow
|
//
|
||||||
|
// 1. Check if the webhook is valid and authorized
|
||||||
|
//
|
||||||
|
|
||||||
|
var repo *model.Repo
|
||||||
|
|
||||||
|
_, err := token.ParseRequest([]token.Type{token.HookToken}, c.Request, func(t *token.Token) (string, error) {
|
||||||
|
var err error
|
||||||
|
repo, err = getRepoFromToken(_store, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Cannot get main forge")
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo.Hash, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
msg := "failure to parse token from hook"
|
||||||
|
log.Error().Err(err).Msg(msg)
|
||||||
|
c.String(http.StatusBadRequest, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if repo == nil {
|
||||||
|
msg := "failure to get repo from token"
|
||||||
|
log.Error().Msg(msg)
|
||||||
|
c.String(http.StatusBadRequest, msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_forge, err := server.Config.Services.Manager.ForgeFromRepo(repo)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Int64("repo-id", repo.ID).Msgf("Cannot get forge with id: %d", repo.ForgeID)
|
||||||
c.AbortWithStatus(http.StatusInternalServerError)
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// 1. Parse webhook
|
// 2. Parse the webhook data
|
||||||
//
|
//
|
||||||
|
|
||||||
tmpRepo, tmpPipeline, err := _forge.Hook(c, c.Request)
|
repoFromForge, pipelineFromForge, err := _forge.Hook(c, c.Request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, &types.ErrIgnoreEvent{}) {
|
if errors.Is(err, &types.ErrIgnoreEvent{}) {
|
||||||
msg := fmt.Sprintf("forge driver: %s", err)
|
msg := fmt.Sprintf("forge driver: %s", err)
|
||||||
|
@ -130,13 +159,13 @@ func PostHook(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if tmpPipeline == nil {
|
if pipelineFromForge == nil {
|
||||||
msg := "ignoring hook: hook parsing resulted in empty pipeline"
|
msg := "ignoring hook: hook parsing resulted in empty pipeline"
|
||||||
log.Debug().Msg(msg)
|
log.Debug().Msg(msg)
|
||||||
c.String(http.StatusOK, msg)
|
c.String(http.StatusOK, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if tmpRepo == nil {
|
if repoFromForge == nil {
|
||||||
msg := "failure to ascertain repo from hook"
|
msg := "failure to ascertain repo from hook"
|
||||||
log.Debug().Msg(msg)
|
log.Debug().Msg(msg)
|
||||||
c.String(http.StatusBadRequest, msg)
|
c.String(http.StatusBadRequest, msg)
|
||||||
|
@ -144,21 +173,24 @@ func PostHook(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// 2. Get related repo from store and take repo renaming into account
|
// 3. Check the repo from the token is matching the repo returned by the forge
|
||||||
//
|
//
|
||||||
|
|
||||||
repo, err := _store.GetRepoNameFallback(tmpRepo.ForgeRemoteID, tmpRepo.FullName)
|
if repo.ForgeRemoteID != repoFromForge.ForgeRemoteID {
|
||||||
if err != nil {
|
log.Warn().Msgf("ignoring hook: repo %s does not match the repo from the token", repo.FullName)
|
||||||
log.Error().Err(err).Msgf("failure to get repo %s from store", tmpRepo.FullName)
|
c.String(http.StatusBadRequest, "failure to parse token from hook")
|
||||||
handleDBError(c, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 4. Check if the repo is active and has an owner
|
||||||
|
//
|
||||||
|
|
||||||
if !repo.IsActive {
|
if !repo.IsActive {
|
||||||
log.Debug().Msgf("ignoring hook: repo %s is inactive", tmpRepo.FullName)
|
log.Debug().Msgf("ignoring hook: repo %s is inactive", repoFromForge.FullName)
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
currentRepoFullName := repo.FullName
|
|
||||||
|
|
||||||
if repo.UserID == 0 {
|
if repo.UserID == 0 {
|
||||||
log.Warn().Msgf("ignoring hook. repo %s has no owner.", repo.FullName)
|
log.Warn().Msgf("ignoring hook. repo %s has no owner.", repo.FullName)
|
||||||
|
@ -174,44 +206,10 @@ func PostHook(c *gin.Context) {
|
||||||
forge.Refresh(c, _forge, _store, user)
|
forge.Refresh(c, _forge, _store, user)
|
||||||
|
|
||||||
//
|
//
|
||||||
// 3. Check if the webhook is a valid and authorized one
|
// 4. Update the repo
|
||||||
//
|
//
|
||||||
|
|
||||||
// get the token and verify the hook is authorized
|
if repo.FullName != repoFromForge.FullName {
|
||||||
parsedToken, err := token.ParseRequest([]token.Type{token.HookToken}, c.Request, func(_ *token.Token) (string, error) {
|
|
||||||
return repo.Hash, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
msg := fmt.Sprintf("failure to parse token from hook for %s", repo.FullName)
|
|
||||||
log.Error().Err(err).Msg(msg)
|
|
||||||
c.String(http.StatusBadRequest, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove fallback for text full name in next major release
|
|
||||||
verifiedKey := parsedToken.Get("repo-id") == strconv.FormatInt(repo.ID, 10) || parsedToken.Get("text") == currentRepoFullName
|
|
||||||
if !verifiedKey {
|
|
||||||
verifiedKey, err = _store.HasRedirectionForRepo(repo.ID, repo.FullName)
|
|
||||||
if err != nil {
|
|
||||||
msg := "failure to verify token from hook. Could not check for redirections of the repo"
|
|
||||||
log.Error().Err(err).Msg(msg)
|
|
||||||
c.String(http.StatusInternalServerError, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !verifiedKey {
|
|
||||||
msg := fmt.Sprintf("failure to verify token from hook. Expected %s, got %s", repo.FullName, parsedToken.Get("text"))
|
|
||||||
log.Debug().Msg(msg)
|
|
||||||
c.String(http.StatusForbidden, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// 4. Update repo
|
|
||||||
//
|
|
||||||
|
|
||||||
if currentRepoFullName != tmpRepo.FullName {
|
|
||||||
// create a redirection
|
// create a redirection
|
||||||
err = _store.CreateRedirection(&model.Redirection{RepoID: repo.ID, FullName: repo.FullName})
|
err = _store.CreateRedirection(&model.Redirection{RepoID: repo.ID, FullName: repo.FullName})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -220,7 +218,7 @@ func PostHook(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.Update(tmpRepo)
|
repo.Update(repoFromForge)
|
||||||
err = _store.UpdateRepo(repo)
|
err = _store.UpdateRepo(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusInternalServerError, err.Error())
|
c.String(http.StatusInternalServerError, err.Error())
|
||||||
|
@ -231,7 +229,7 @@ func PostHook(c *gin.Context) {
|
||||||
// 5. Check if pull requests are allowed for this repo
|
// 5. Check if pull requests are allowed for this repo
|
||||||
//
|
//
|
||||||
|
|
||||||
if (tmpPipeline.Event == model.EventPull || tmpPipeline.Event == model.EventPullClosed) && !repo.AllowPull {
|
if (pipelineFromForge.Event == model.EventPull || pipelineFromForge.Event == model.EventPullClosed) && !repo.AllowPull {
|
||||||
log.Debug().Str("repo", repo.FullName).Msg("ignoring hook: pull requests are disabled for this repo in woodpecker")
|
log.Debug().Str("repo", repo.FullName).Msg("ignoring hook: pull requests are disabled for this repo in woodpecker")
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
|
@ -241,10 +239,22 @@ func PostHook(c *gin.Context) {
|
||||||
// 6. Finally create a pipeline
|
// 6. Finally create a pipeline
|
||||||
//
|
//
|
||||||
|
|
||||||
pl, err := pipeline.Create(c, _store, repo, tmpPipeline)
|
pl, err := pipeline.Create(c, _store, repo, pipelineFromForge)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handlePipelineErr(c, err)
|
handlePipelineErr(c, err)
|
||||||
} else {
|
} else {
|
||||||
c.JSON(http.StatusOK, pl)
|
c.JSON(http.StatusOK, pl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRepoFromToken(store store.Store, t *token.Token) (*model.Repo, error) {
|
||||||
|
// try to get the repo by the repo-id
|
||||||
|
repoID, err := strconv.ParseInt(t.Get("repo-id"), 10, 64)
|
||||||
|
if err == nil {
|
||||||
|
return store.GetRepo(repoID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to get the repo by the repo name or by its redirection
|
||||||
|
repoName := t.Get("text")
|
||||||
|
return store.GetRepoName(repoName)
|
||||||
|
}
|
||||||
|
|
104
server/api/hook_test.go
Normal file
104
server/api/hook_test.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package api_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/franela/goblin"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/server"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/server/api"
|
||||||
|
mocks_forge "go.woodpecker-ci.org/woodpecker/v2/server/forge/mocks"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||||
|
mocks_config_service "go.woodpecker-ci.org/woodpecker/v2/server/services/config/mocks"
|
||||||
|
mocks_services "go.woodpecker-ci.org/woodpecker/v2/server/services/mocks"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/server/services/permissions"
|
||||||
|
mocks_registry_service "go.woodpecker-ci.org/woodpecker/v2/server/services/registry/mocks"
|
||||||
|
mocks_secret_service "go.woodpecker-ci.org/woodpecker/v2/server/services/secret/mocks"
|
||||||
|
mocks_store "go.woodpecker-ci.org/woodpecker/v2/server/store/mocks"
|
||||||
|
"go.woodpecker-ci.org/woodpecker/v2/shared/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHook(t *testing.T) {
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
g := goblin.Goblin(t)
|
||||||
|
g.Describe("Hook", func() {
|
||||||
|
g.It("should handle a correct webhook payload", func() {
|
||||||
|
_manager := mocks_services.NewManager(t)
|
||||||
|
_forge := mocks_forge.NewForge(t)
|
||||||
|
_store := mocks_store.NewStore(t)
|
||||||
|
_configService := mocks_config_service.NewService(t)
|
||||||
|
_secretService := mocks_secret_service.NewService(t)
|
||||||
|
_registryService := mocks_registry_service.NewService(t)
|
||||||
|
server.Config.Services.Manager = _manager
|
||||||
|
server.Config.Permissions.Open = true
|
||||||
|
server.Config.Permissions.Orgs = permissions.NewOrgs(nil)
|
||||||
|
server.Config.Permissions.Admins = permissions.NewAdmins(nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
c, _ := gin.CreateTestContext(w)
|
||||||
|
c.Set("store", _store)
|
||||||
|
user := &model.User{
|
||||||
|
ID: 123,
|
||||||
|
}
|
||||||
|
repo := &model.Repo{
|
||||||
|
ID: 123,
|
||||||
|
ForgeRemoteID: "123",
|
||||||
|
Owner: "owner",
|
||||||
|
Name: "name",
|
||||||
|
IsActive: true,
|
||||||
|
UserID: user.ID,
|
||||||
|
Hash: "secret-123-this-is-a-secret",
|
||||||
|
}
|
||||||
|
pipeline := &model.Pipeline{
|
||||||
|
ID: 123,
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Event: model.EventPush,
|
||||||
|
}
|
||||||
|
|
||||||
|
repoToken := token.New(token.HookToken)
|
||||||
|
repoToken.Set("repo-id", fmt.Sprintf("%d", repo.ID))
|
||||||
|
signedToken, err := repoToken.Sign("secret-123-this-is-a-secret")
|
||||||
|
if err != nil {
|
||||||
|
g.Fail(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
header := http.Header{}
|
||||||
|
header.Set("Authorization", fmt.Sprintf("Bearer %s", signedToken))
|
||||||
|
c.Request = &http.Request{
|
||||||
|
Header: header,
|
||||||
|
URL: &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_manager.On("ForgeFromRepo", repo).Return(_forge, nil)
|
||||||
|
_forge.On("Hook", mock.Anything, mock.Anything).Return(repo, pipeline, nil)
|
||||||
|
_store.On("GetRepo", repo.ID).Return(repo, nil)
|
||||||
|
_store.On("GetUser", user.ID).Return(user, nil)
|
||||||
|
_store.On("UpdateRepo", repo).Return(nil)
|
||||||
|
_store.On("CreatePipeline", mock.Anything).Return(nil)
|
||||||
|
_manager.On("ConfigServiceFromRepo", repo).Return(_configService)
|
||||||
|
_configService.On("Fetch", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
|
||||||
|
_forge.On("Netrc", mock.Anything, mock.Anything).Return(&model.Netrc{}, nil)
|
||||||
|
_store.On("GetPipelineLastBefore", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil)
|
||||||
|
_manager.On("SecretServiceFromRepo", repo).Return(_secretService)
|
||||||
|
_secretService.On("SecretListPipeline", repo, mock.Anything, mock.Anything).Return(nil, nil)
|
||||||
|
_manager.On("RegistryServiceFromRepo", repo).Return(_registryService)
|
||||||
|
_registryService.On("RegistryListPipeline", repo, mock.Anything).Return(nil, nil)
|
||||||
|
_manager.On("EnvironmentService").Return(nil)
|
||||||
|
_store.On("DeletePipeline", mock.Anything).Return(nil)
|
||||||
|
|
||||||
|
api.PostHook(c)
|
||||||
|
|
||||||
|
assert.Equal(g, http.StatusNoContent, c.Writer.Status())
|
||||||
|
assert.Equal(g, "true", w.Header().Get("Pipeline-Filtered"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
|
@ -62,10 +62,10 @@ func HandleAuth(c *gin.Context) {
|
||||||
code := c.Request.FormValue("code")
|
code := c.Request.FormValue("code")
|
||||||
state := c.Request.FormValue("state")
|
state := c.Request.FormValue("state")
|
||||||
isCallback := code != "" && state != ""
|
isCallback := code != "" && state != ""
|
||||||
forgeID := int64(1) // TODO: replace with forge id when multiple forges are supported
|
var forgeID int64
|
||||||
|
|
||||||
if isCallback { // validate the state token
|
if isCallback { // validate the state token
|
||||||
_, err := token.Parse([]token.Type{token.OAuthStateToken}, state, func(_ *token.Token) (string, error) {
|
stateToken, err := token.Parse([]token.Type{token.OAuthStateToken}, state, func(_ *token.Token) (string, error) {
|
||||||
return server.Config.Server.JWTSecret, nil
|
return server.Config.Server.JWTSecret, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -73,8 +73,29 @@ func HandleAuth(c *gin.Context) {
|
||||||
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=invalid_state")
|
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=invalid_state")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_forgeID := stateToken.Get("forge-id")
|
||||||
|
forgeID, err = strconv.ParseInt(_forgeID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("forge-id of state token invalid")
|
||||||
|
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=invalid_state")
|
||||||
|
return
|
||||||
|
}
|
||||||
} else { // only generate a state token if not a callback
|
} else { // only generate a state token if not a callback
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
_forgeID := c.Request.FormValue("forge_id")
|
||||||
|
if _forgeID == "" {
|
||||||
|
forgeID = 1 // fallback to main forge
|
||||||
|
} else {
|
||||||
|
forgeID, err = strconv.ParseInt(_forgeID, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("forge-id of state token invalid")
|
||||||
|
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=invalid_state")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
jwtSecret := server.Config.Server.JWTSecret
|
jwtSecret := server.Config.Server.JWTSecret
|
||||||
exp := time.Now().Add(stateTokenDuration).Unix()
|
exp := time.Now().Add(stateTokenDuration).Unix()
|
||||||
stateToken := token.New(token.OAuthStateToken)
|
stateToken := token.New(token.OAuthStateToken)
|
||||||
|
@ -208,6 +229,7 @@ func HandleAuth(c *gin.Context) {
|
||||||
user.Secret = userFromForge.Secret
|
user.Secret = userFromForge.Secret
|
||||||
user.Email = userFromForge.Email
|
user.Email = userFromForge.Email
|
||||||
user.Avatar = userFromForge.Avatar
|
user.Avatar = userFromForge.Avatar
|
||||||
|
user.ForgeID = forgeID
|
||||||
user.ForgeRemoteID = userFromForge.ForgeRemoteID
|
user.ForgeRemoteID = userFromForge.ForgeRemoteID
|
||||||
user.Login = userFromForge.Login
|
user.Login = userFromForge.Login
|
||||||
user.Admin = user.Admin || server.Config.Permissions.Admins.IsAdmin(userFromForge)
|
user.Admin = user.Admin || server.Config.Permissions.Admins.IsAdmin(userFromForge)
|
||||||
|
@ -280,7 +302,7 @@ func GetLogout(c *gin.Context) {
|
||||||
func DeprecatedGetLoginToken(c *gin.Context) {
|
func DeprecatedGetLoginToken(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
|
|
||||||
_forge, err := server.Config.Services.Manager.ForgeByID(1) // TODO: get selected forge from auth request
|
_forge, err := server.Config.Services.Manager.ForgeByID(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Cannot get main forge")
|
log.Error().Err(err).Msg("Cannot get main forge")
|
||||||
c.AbortWithStatus(http.StatusInternalServerError)
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
|
|
63
server/services/config/mocks/service.go
Normal file
63
server/services/config/mocks/service.go
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
// Code generated by mockery. DO NOT EDIT.
|
||||||
|
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
forge "go.woodpecker-ci.org/woodpecker/v2/server/forge"
|
||||||
|
|
||||||
|
model "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||||
|
|
||||||
|
types "go.woodpecker-ci.org/woodpecker/v2/server/forge/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service is an autogenerated mock type for the Service type
|
||||||
|
type Service struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch provides a mock function with given fields: ctx, _a1, user, repo, pipeline, oldConfigData, restart
|
||||||
|
func (_m *Service) Fetch(ctx context.Context, _a1 forge.Forge, user *model.User, repo *model.Repo, pipeline *model.Pipeline, oldConfigData []*types.FileMeta, restart bool) ([]*types.FileMeta, error) {
|
||||||
|
ret := _m.Called(ctx, _a1, user, repo, pipeline, oldConfigData, restart)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for Fetch")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*types.FileMeta
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, forge.Forge, *model.User, *model.Repo, *model.Pipeline, []*types.FileMeta, bool) ([]*types.FileMeta, error)); ok {
|
||||||
|
return rf(ctx, _a1, user, repo, pipeline, oldConfigData, restart)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, forge.Forge, *model.User, *model.Repo, *model.Pipeline, []*types.FileMeta, bool) []*types.FileMeta); ok {
|
||||||
|
r0 = rf(ctx, _a1, user, repo, pipeline, oldConfigData, restart)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*types.FileMeta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, forge.Forge, *model.User, *model.Repo, *model.Pipeline, []*types.FileMeta, bool) error); ok {
|
||||||
|
r1 = rf(ctx, _a1, user, repo, pipeline, oldConfigData, restart)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewService creates a new instance of Service. 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 NewService(t interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}) *Service {
|
||||||
|
mock := &Service{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
|
@ -22,6 +22,8 @@ import (
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
"go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:generate mockery --name Service --output mocks --case underscore
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
Fetch(ctx context.Context, forge forge.Forge, user *model.User, repo *model.Repo, pipeline *model.Pipeline, oldConfigData []*types.FileMeta, restart bool) (configData []*types.FileMeta, err error)
|
Fetch(ctx context.Context, forge forge.Forge, user *model.User, repo *model.Repo, pipeline *model.Pipeline, oldConfigData []*types.FileMeta, restart bool) (configData []*types.FileMeta, err error)
|
||||||
}
|
}
|
||||||
|
|
57
server/services/environment/mocks/service.go
Normal file
57
server/services/environment/mocks/service.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Code generated by mockery. DO NOT EDIT.
|
||||||
|
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
model "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service is an autogenerated mock type for the Service type
|
||||||
|
type Service struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvironList provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) EnvironList(_a0 *model.Repo) ([]*model.Environ, error) {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for EnvironList")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Environ
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo) ([]*model.Environ, error)); ok {
|
||||||
|
return rf(_a0)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo) []*model.Environ); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Environ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.Repo) error); ok {
|
||||||
|
r1 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewService creates a new instance of Service. 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 NewService(t interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}) *Service {
|
||||||
|
mock := &Service{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
|
@ -16,6 +16,8 @@ package environment
|
||||||
|
|
||||||
import "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
import "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||||
|
|
||||||
|
//go:generate mockery --name Service --output mocks --case underscore
|
||||||
|
|
||||||
// Service defines a service for managing environment variables.
|
// Service defines a service for managing environment variables.
|
||||||
type Service interface {
|
type Service interface {
|
||||||
EnvironList(*model.Repo) ([]*model.Environ, error)
|
EnvironList(*model.Repo) ([]*model.Environ, error)
|
||||||
|
|
|
@ -46,7 +46,7 @@ type Manager interface {
|
||||||
EnvironmentService() environment.Service
|
EnvironmentService() environment.Service
|
||||||
ForgeFromRepo(repo *model.Repo) (forge.Forge, error)
|
ForgeFromRepo(repo *model.Repo) (forge.Forge, error)
|
||||||
ForgeFromUser(user *model.User) (forge.Forge, error)
|
ForgeFromUser(user *model.User) (forge.Forge, error)
|
||||||
ForgeByID(id int64) (forge.Forge, error)
|
ForgeByID(forgeID int64) (forge.Forge, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type manager struct {
|
type manager struct {
|
||||||
|
|
|
@ -68,9 +68,9 @@ func (_m *Manager) EnvironmentService() environment.Service {
|
||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForgeByID provides a mock function with given fields: id
|
// ForgeByID provides a mock function with given fields: forgeID
|
||||||
func (_m *Manager) ForgeByID(id int64) (forge.Forge, error) {
|
func (_m *Manager) ForgeByID(forgeID int64) (forge.Forge, error) {
|
||||||
ret := _m.Called(id)
|
ret := _m.Called(forgeID)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for ForgeByID")
|
panic("no return value specified for ForgeByID")
|
||||||
|
@ -79,10 +79,10 @@ func (_m *Manager) ForgeByID(id int64) (forge.Forge, error) {
|
||||||
var r0 forge.Forge
|
var r0 forge.Forge
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(0).(func(int64) (forge.Forge, error)); ok {
|
if rf, ok := ret.Get(0).(func(int64) (forge.Forge, error)); ok {
|
||||||
return rf(id)
|
return rf(forgeID)
|
||||||
}
|
}
|
||||||
if rf, ok := ret.Get(0).(func(int64) forge.Forge); ok {
|
if rf, ok := ret.Get(0).(func(int64) forge.Forge); ok {
|
||||||
r0 = rf(id)
|
r0 = rf(forgeID)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).(forge.Forge)
|
r0 = ret.Get(0).(forge.Forge)
|
||||||
|
@ -90,7 +90,7 @@ func (_m *Manager) ForgeByID(id int64) (forge.Forge, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if rf, ok := ret.Get(1).(func(int64) error); ok {
|
if rf, ok := ret.Get(1).(func(int64) error); ok {
|
||||||
r1 = rf(id)
|
r1 = rf(forgeID)
|
||||||
} else {
|
} else {
|
||||||
r1 = ret.Error(1)
|
r1 = ret.Error(1)
|
||||||
}
|
}
|
||||||
|
|
399
server/services/registry/mocks/service.go
Normal file
399
server/services/registry/mocks/service.go
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
// Code generated by mockery. DO NOT EDIT.
|
||||||
|
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
model "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service is an autogenerated mock type for the Service type
|
||||||
|
type Service struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalRegistryCreate provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalRegistryCreate(_a0 *model.Registry) error {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalRegistryCreate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Registry) error); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalRegistryDelete provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalRegistryDelete(_a0 string) error {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalRegistryDelete")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(string) error); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalRegistryFind provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalRegistryFind(_a0 string) (*model.Registry, error) {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalRegistryFind")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 *model.Registry
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(string) (*model.Registry, error)); ok {
|
||||||
|
return rf(_a0)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(string) *model.Registry); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.Registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||||
|
r1 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalRegistryList provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalRegistryList(_a0 *model.ListOptions) ([]*model.Registry, error) {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalRegistryList")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Registry
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.ListOptions) ([]*model.Registry, error)); ok {
|
||||||
|
return rf(_a0)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.ListOptions) []*model.Registry); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.ListOptions) error); ok {
|
||||||
|
r1 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalRegistryUpdate provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalRegistryUpdate(_a0 *model.Registry) error {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalRegistryUpdate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Registry) error); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgRegistryCreate provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgRegistryCreate(_a0 int64, _a1 *model.Registry) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgRegistryCreate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, *model.Registry) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgRegistryDelete provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgRegistryDelete(_a0 int64, _a1 string) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgRegistryDelete")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, string) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgRegistryFind provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgRegistryFind(_a0 int64, _a1 string) (*model.Registry, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgRegistryFind")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 *model.Registry
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, string) (*model.Registry, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, string) *model.Registry); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.Registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(int64, string) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgRegistryList provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgRegistryList(_a0 int64, _a1 *model.ListOptions) ([]*model.Registry, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgRegistryList")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Registry
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) ([]*model.Registry, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) []*model.Registry); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(int64, *model.ListOptions) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgRegistryUpdate provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgRegistryUpdate(_a0 int64, _a1 *model.Registry) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgRegistryUpdate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, *model.Registry) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryCreate provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) RegistryCreate(_a0 *model.Repo, _a1 *model.Registry) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for RegistryCreate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.Registry) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryDelete provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) RegistryDelete(_a0 *model.Repo, _a1 string) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for RegistryDelete")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, string) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryFind provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) RegistryFind(_a0 *model.Repo, _a1 string) (*model.Registry, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for RegistryFind")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 *model.Registry
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, string) (*model.Registry, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, string) *model.Registry); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.Registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.Repo, string) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryList provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) RegistryList(_a0 *model.Repo, _a1 *model.ListOptions) ([]*model.Registry, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for RegistryList")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Registry
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) ([]*model.Registry, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) []*model.Registry); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.Repo, *model.ListOptions) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryListPipeline provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) RegistryListPipeline(_a0 *model.Repo, _a1 *model.Pipeline) ([]*model.Registry, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for RegistryListPipeline")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Registry
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.Pipeline) ([]*model.Registry, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.Pipeline) []*model.Registry); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Registry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.Repo, *model.Pipeline) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegistryUpdate provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) RegistryUpdate(_a0 *model.Repo, _a1 *model.Registry) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for RegistryUpdate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.Registry) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewService creates a new instance of Service. 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 NewService(t interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}) *Service {
|
||||||
|
mock := &Service{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
|
@ -16,6 +16,8 @@ package registry
|
||||||
|
|
||||||
import "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
import "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||||
|
|
||||||
|
//go:generate mockery --name Service --output mocks --case underscore
|
||||||
|
|
||||||
// Service defines a service for managing registries.
|
// Service defines a service for managing registries.
|
||||||
type Service interface {
|
type Service interface {
|
||||||
RegistryListPipeline(*model.Repo, *model.Pipeline) ([]*model.Registry, error)
|
RegistryListPipeline(*model.Repo, *model.Pipeline) ([]*model.Registry, error)
|
||||||
|
|
399
server/services/secret/mocks/service.go
Normal file
399
server/services/secret/mocks/service.go
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
// Code generated by mockery. DO NOT EDIT.
|
||||||
|
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
model "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service is an autogenerated mock type for the Service type
|
||||||
|
type Service struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalSecretCreate provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalSecretCreate(_a0 *model.Secret) error {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalSecretCreate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Secret) error); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalSecretDelete provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalSecretDelete(_a0 string) error {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalSecretDelete")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(string) error); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalSecretFind provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalSecretFind(_a0 string) (*model.Secret, error) {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalSecretFind")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 *model.Secret
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(string) (*model.Secret, error)); ok {
|
||||||
|
return rf(_a0)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(string) *model.Secret); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.Secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||||
|
r1 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalSecretList provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalSecretList(_a0 *model.ListOptions) ([]*model.Secret, error) {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalSecretList")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Secret
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.ListOptions) ([]*model.Secret, error)); ok {
|
||||||
|
return rf(_a0)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.ListOptions) []*model.Secret); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.ListOptions) error); ok {
|
||||||
|
r1 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalSecretUpdate provides a mock function with given fields: _a0
|
||||||
|
func (_m *Service) GlobalSecretUpdate(_a0 *model.Secret) error {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for GlobalSecretUpdate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Secret) error); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgSecretCreate provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgSecretCreate(_a0 int64, _a1 *model.Secret) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgSecretCreate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, *model.Secret) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgSecretDelete provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgSecretDelete(_a0 int64, _a1 string) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgSecretDelete")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, string) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgSecretFind provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgSecretFind(_a0 int64, _a1 string) (*model.Secret, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgSecretFind")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 *model.Secret
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, string) (*model.Secret, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, string) *model.Secret); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.Secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(int64, string) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgSecretList provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgSecretList(_a0 int64, _a1 *model.ListOptions) ([]*model.Secret, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgSecretList")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Secret
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) ([]*model.Secret, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, *model.ListOptions) []*model.Secret); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(int64, *model.ListOptions) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrgSecretUpdate provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) OrgSecretUpdate(_a0 int64, _a1 *model.Secret) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for OrgSecretUpdate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(int64, *model.Secret) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretCreate provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) SecretCreate(_a0 *model.Repo, _a1 *model.Secret) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for SecretCreate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.Secret) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretDelete provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) SecretDelete(_a0 *model.Repo, _a1 string) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for SecretDelete")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, string) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretFind provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) SecretFind(_a0 *model.Repo, _a1 string) (*model.Secret, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for SecretFind")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 *model.Secret
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, string) (*model.Secret, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, string) *model.Secret); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*model.Secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.Repo, string) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretList provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) SecretList(_a0 *model.Repo, _a1 *model.ListOptions) ([]*model.Secret, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for SecretList")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Secret
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) ([]*model.Secret, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.ListOptions) []*model.Secret); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.Repo, *model.ListOptions) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretListPipeline provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) SecretListPipeline(_a0 *model.Repo, _a1 *model.Pipeline) ([]*model.Secret, error) {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for SecretListPipeline")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 []*model.Secret
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.Pipeline) ([]*model.Secret, error)); ok {
|
||||||
|
return rf(_a0, _a1)
|
||||||
|
}
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.Pipeline) []*model.Secret); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.Secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.Repo, *model.Pipeline) error); ok {
|
||||||
|
r1 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretUpdate provides a mock function with given fields: _a0, _a1
|
||||||
|
func (_m *Service) SecretUpdate(_a0 *model.Repo, _a1 *model.Secret) error {
|
||||||
|
ret := _m.Called(_a0, _a1)
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
panic("no return value specified for SecretUpdate")
|
||||||
|
}
|
||||||
|
|
||||||
|
var r0 error
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Repo, *model.Secret) error); ok {
|
||||||
|
r0 = rf(_a0, _a1)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Error(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewService creates a new instance of Service. 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 NewService(t interface {
|
||||||
|
mock.TestingT
|
||||||
|
Cleanup(func())
|
||||||
|
}) *Service {
|
||||||
|
mock := &Service{}
|
||||||
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||||
|
|
||||||
|
return mock
|
||||||
|
}
|
|
@ -16,6 +16,8 @@ package secret
|
||||||
|
|
||||||
import "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
import "go.woodpecker-ci.org/woodpecker/v2/server/model"
|
||||||
|
|
||||||
|
//go:generate mockery --name Service --output mocks --case underscore
|
||||||
|
|
||||||
// Service defines a service for managing secrets.
|
// Service defines a service for managing secrets.
|
||||||
type Service interface {
|
type Service interface {
|
||||||
SecretListPipeline(*model.Repo, *model.Pipeline) ([]*model.Secret, error)
|
SecretListPipeline(*model.Repo, *model.Pipeline) ([]*model.Secret, error)
|
||||||
|
|
|
@ -30,7 +30,7 @@ func (s storage) GetUserRemoteID(remoteID model.ForgeRemoteID, login string) (*m
|
||||||
user := new(model.User)
|
user := new(model.User)
|
||||||
err := wrapGet(sess.Where("forge_remote_id = ?", remoteID).Get(user))
|
err := wrapGet(sess.Where("forge_remote_id = ?", remoteID).Get(user))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
user, err = s.getUserLogin(sess, login)
|
return s.getUserLogin(sess, login)
|
||||||
}
|
}
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
|
"login_with": "Login with {forge}",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"welcome": "Welcome to Woodpecker",
|
"welcome": "Welcome to Woodpecker",
|
||||||
"repos": "Repos",
|
"repos": "Repos",
|
||||||
|
|
|
@ -7,11 +7,11 @@ export default () =>
|
||||||
|
|
||||||
user: useConfig().user,
|
user: useConfig().user,
|
||||||
|
|
||||||
authenticate(url?: string) {
|
authenticate(url?: string, forgeId?: number) {
|
||||||
if (url !== undefined) {
|
if (url !== undefined) {
|
||||||
const config = useUserConfig();
|
const config = useUserConfig();
|
||||||
config.setUserConfig('redirectUrl', url);
|
config.setUserConfig('redirectUrl', url);
|
||||||
}
|
}
|
||||||
window.location.href = `${useConfig().rootPath}/authorize`;
|
window.location.href = `${useConfig().rootPath}/authorize?forge_id=${forgeId}`;
|
||||||
},
|
},
|
||||||
}) as const;
|
}) as const;
|
||||||
|
|
|
@ -21,7 +21,16 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-center items-center flex-col md:w-2/5 min-h-48 gap-4 text-center">
|
<div class="flex justify-center items-center flex-col md:w-2/5 min-h-48 gap-4 text-center">
|
||||||
<h1 class="text-xl text-wp-text-100">{{ $t('welcome') }}</h1>
|
<h1 class="text-xl text-wp-text-100">{{ $t('welcome') }}</h1>
|
||||||
<Button @click="doLogin">{{ $t('login') }}</Button>
|
<div class="flex flex-col gap-2">
|
||||||
|
<Button
|
||||||
|
v-for="forge in forges"
|
||||||
|
:key="forge.id"
|
||||||
|
:start-icon="forge.type === 'addon' ? 'repo' : forge.type"
|
||||||
|
@click="doLogin(forge.id)"
|
||||||
|
>
|
||||||
|
{{ $t('login_with', { forge: getHostFromUrl(forge) }) }}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -35,16 +44,30 @@ import { useRoute, useRouter } from 'vue-router';
|
||||||
import WoodpeckerLogo from '~/assets/logo.svg?component';
|
import WoodpeckerLogo from '~/assets/logo.svg?component';
|
||||||
import Button from '~/components/atomic/Button.vue';
|
import Button from '~/components/atomic/Button.vue';
|
||||||
import Error from '~/components/atomic/Error.vue';
|
import Error from '~/components/atomic/Error.vue';
|
||||||
|
import useApiClient from '~/compositions/useApiClient';
|
||||||
import useAuthentication from '~/compositions/useAuthentication';
|
import useAuthentication from '~/compositions/useAuthentication';
|
||||||
|
import type { Forge } from '~/lib/api/types';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const authentication = useAuthentication();
|
const authentication = useAuthentication();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
const apiClient = useApiClient();
|
||||||
|
|
||||||
function doLogin() {
|
const forges = ref<Forge[]>([]);
|
||||||
|
|
||||||
|
function getHostFromUrl(forge: Forge) {
|
||||||
|
if (!forge.url) {
|
||||||
|
return forge.type.charAt(0).toUpperCase() + forge.type.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = new URL(forge.url);
|
||||||
|
return url.hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doLogin(forgeId?: number) {
|
||||||
const url = typeof route.query.url === 'string' ? route.query.url : '';
|
const url = typeof route.query.url === 'string' ? route.query.url : '';
|
||||||
authentication.authenticate(url);
|
authentication.authenticate(url, forgeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const authErrorMessages = {
|
const authErrorMessages = {
|
||||||
|
@ -65,6 +88,8 @@ onMounted(async () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forges.value = (await apiClient.getForges()) ?? [];
|
||||||
|
|
||||||
if (route.query.error) {
|
if (route.query.error) {
|
||||||
const error = route.query.error as keyof typeof authErrorMessages;
|
const error = route.query.error as keyof typeof authErrorMessages;
|
||||||
errorMessage.value = authErrorMessages[error] ?? error;
|
errorMessage.value = authErrorMessages[error] ?? error;
|
||||||
|
|
Loading…
Reference in a new issue