mirror of
https://github.com/harness/drone.git
synced 2025-05-31 11:43:15 +00:00
Merge branch 'ci_gitness' of _OKE5H2PQKOUfzFFDuD4FA/default/CODE/gitness (#273)
This commit is contained in:
commit
29c494c23f
@ -11,15 +11,19 @@ import (
|
||||
"context"
|
||||
|
||||
cliserver "github.com/harness/gitness/cli/server"
|
||||
"github.com/harness/gitness/encrypt"
|
||||
"github.com/harness/gitness/events"
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
gitrpcserver "github.com/harness/gitness/gitrpc/server"
|
||||
gitrpccron "github.com/harness/gitness/gitrpc/server/cron"
|
||||
checkcontroller "github.com/harness/gitness/internal/api/controller/check"
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
"github.com/harness/gitness/internal/api/controller/githook"
|
||||
"github.com/harness/gitness/internal/api/controller/pipeline"
|
||||
"github.com/harness/gitness/internal/api/controller/principal"
|
||||
"github.com/harness/gitness/internal/api/controller/pullreq"
|
||||
"github.com/harness/gitness/internal/api/controller/repo"
|
||||
"github.com/harness/gitness/internal/api/controller/secret"
|
||||
"github.com/harness/gitness/internal/api/controller/service"
|
||||
"github.com/harness/gitness/internal/api/controller/serviceaccount"
|
||||
"github.com/harness/gitness/internal/api/controller/space"
|
||||
@ -79,6 +83,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
|
||||
gitrpc.WireSet,
|
||||
store.WireSet,
|
||||
check.WireSet,
|
||||
encrypt.WireSet,
|
||||
cliserver.ProvideEventsConfig,
|
||||
events.WireSet,
|
||||
cliserver.ProvideWebhookConfig,
|
||||
@ -90,6 +95,9 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
|
||||
codecomments.WireSet,
|
||||
gitrpccron.WireSet,
|
||||
checkcontroller.WireSet,
|
||||
execution.WireSet,
|
||||
pipeline.WireSet,
|
||||
secret.WireSet,
|
||||
)
|
||||
return &cliserver.System{}, nil
|
||||
}
|
||||
|
@ -8,16 +8,21 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/cli/server"
|
||||
"github.com/harness/gitness/encrypt"
|
||||
"github.com/harness/gitness/events"
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
server3 "github.com/harness/gitness/gitrpc/server"
|
||||
"github.com/harness/gitness/gitrpc/server/cron"
|
||||
check2 "github.com/harness/gitness/internal/api/controller/check"
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
"github.com/harness/gitness/internal/api/controller/githook"
|
||||
"github.com/harness/gitness/internal/api/controller/pipeline"
|
||||
"github.com/harness/gitness/internal/api/controller/principal"
|
||||
"github.com/harness/gitness/internal/api/controller/pullreq"
|
||||
"github.com/harness/gitness/internal/api/controller/repo"
|
||||
"github.com/harness/gitness/internal/api/controller/secret"
|
||||
"github.com/harness/gitness/internal/api/controller/service"
|
||||
"github.com/harness/gitness/internal/api/controller/serviceaccount"
|
||||
"github.com/harness/gitness/internal/api/controller/space"
|
||||
@ -84,7 +89,17 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
return nil, err
|
||||
}
|
||||
repoController := repo.ProvideController(config, db, provider, pathUID, authorizer, pathStore, repoStore, spaceStore, principalStore, gitrpcInterface)
|
||||
spaceController := space.ProvideController(db, provider, pathUID, authorizer, pathStore, spaceStore, repoStore, principalStore, repoController, membershipStore)
|
||||
executionStore := database.ProvideExecutionStore(db)
|
||||
pipelineStore := database.ProvidePipelineStore(db)
|
||||
executionController := execution.ProvideController(db, authorizer, executionStore, pipelineStore, spaceStore)
|
||||
secretStore := database.ProvideSecretStore(db)
|
||||
spaceController := space.ProvideController(db, provider, pathUID, authorizer, pathStore, pipelineStore, secretStore, spaceStore, repoStore, principalStore, repoController, membershipStore)
|
||||
pipelineController := pipeline.ProvideController(db, pathUID, pathStore, repoStore, authorizer, pipelineStore, spaceStore)
|
||||
encrypter, err := encrypt.ProvideEncrypter(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secretController := secret.ProvideController(db, pathUID, pathStore, encrypter, secretStore, authorizer, spaceStore)
|
||||
pullReqStore := database.ProvidePullReqStore(db, principalInfoCache)
|
||||
pullReqActivityStore := database.ProvidePullReqActivityStore(db, principalInfoCache)
|
||||
codeCommentView := database.ProvideCodeCommentView(db)
|
||||
@ -138,7 +153,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
principalController := principal.ProvideController(principalStore)
|
||||
checkStore := database.ProvideCheckStore(db, principalInfoCache)
|
||||
checkController := check2.ProvideController(db, authorizer, repoStore, checkStore, gitrpcInterface)
|
||||
apiHandler := router.ProvideAPIHandler(config, authenticator, repoController, spaceController, pullreqController, webhookController, githookController, serviceaccountController, controller, principalController, checkController)
|
||||
apiHandler := router.ProvideAPIHandler(config, authenticator, repoController, executionController, spaceController, pipelineController, secretController, pullreqController, webhookController, githookController, serviceaccountController, controller, principalController, checkController)
|
||||
gitHandler := router.ProvideGitHandler(config, provider, repoStore, authenticator, authorizer, gitrpcInterface)
|
||||
webHandler := router.ProvideWebHandler(config)
|
||||
routerRouter := router.ProvideRouter(config, apiHandler, gitHandler, webHandler)
|
||||
|
84
encrypt/aesgcm.go
Normal file
84
encrypt/aesgcm.go
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright 2023 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Aesgcm provides an encrypter that uses the aesgcm encryption
|
||||
// algorithm.
|
||||
type Aesgcm struct {
|
||||
block cipher.Block
|
||||
Compat bool
|
||||
}
|
||||
|
||||
// Encrypt encrypts the plaintext using aesgcm.
|
||||
func (e *Aesgcm) Encrypt(plaintext string) ([]byte, error) {
|
||||
gcm, err := cipher.NewGCM(e.block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
_, err = io.ReadFull(rand.Reader, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gcm.Seal(nonce, nonce, []byte(plaintext), nil), nil
|
||||
}
|
||||
|
||||
// Decrypt decrypts the ciphertext using aesgcm.
|
||||
func (e *Aesgcm) Decrypt(ciphertext []byte) (string, error) {
|
||||
gcm, err := cipher.NewGCM(e.block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(ciphertext) < gcm.NonceSize() {
|
||||
// if the decryption utility is running in compatibility
|
||||
// mode, it will return the ciphertext as plain text if
|
||||
// decryption fails. This should be used when running the
|
||||
// database in mixed-mode, where there is a mix of encrypted
|
||||
// and unencrypted content.
|
||||
if e.Compat {
|
||||
return string(ciphertext), nil
|
||||
}
|
||||
return "", errors.New("malformed ciphertext")
|
||||
}
|
||||
|
||||
plaintext, err := gcm.Open(nil,
|
||||
ciphertext[:gcm.NonceSize()],
|
||||
ciphertext[gcm.NonceSize():],
|
||||
nil,
|
||||
)
|
||||
// if the decryption utility is running in compatibility
|
||||
// mode, it will return the ciphertext as plain text if
|
||||
// decryption fails. This should be used when running the
|
||||
// database in mixed-mode, where there is a mix of encrypted
|
||||
// and unencrypted content.
|
||||
if err != nil && e.Compat {
|
||||
return string(ciphertext), nil
|
||||
}
|
||||
return string(plaintext), err
|
||||
}
|
||||
|
||||
// New provides a new aesgcm encrypter
|
||||
func New(key string, compat bool) (Encrypter, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, errKeySize
|
||||
}
|
||||
b := []byte(key)
|
||||
block, err := aes.NewCipher(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Aesgcm{block: block, Compat: compat}, nil
|
||||
}
|
20
encrypt/encrypt.go
Normal file
20
encrypt/encrypt.go
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// indicates key size is too small.
|
||||
var errKeySize = errors.New("encryption key must be 32 bytes")
|
||||
|
||||
// Encrypter provides field encryption and decryption.
|
||||
// Encrypted values are currently limited to strings, which is
|
||||
// reflected in the interface design.
|
||||
type Encrypter interface {
|
||||
Encrypt(plaintext string) ([]byte, error)
|
||||
Decrypt(ciphertext []byte) (string, error)
|
||||
}
|
19
encrypt/none.go
Normal file
19
encrypt/none.go
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2023 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package encrypt
|
||||
|
||||
// none is an encryption strategy that stores secret
|
||||
// values in plain text. This is the default strategy
|
||||
// when no key is specified.
|
||||
type none struct {
|
||||
}
|
||||
|
||||
func (*none) Encrypt(plaintext string) ([]byte, error) {
|
||||
return []byte(plaintext), nil
|
||||
}
|
||||
|
||||
func (*none) Decrypt(ciphertext []byte) (string, error) {
|
||||
return string(ciphertext), nil
|
||||
}
|
19
encrypt/wire.go
Normal file
19
encrypt/wire.go
Normal file
@ -0,0 +1,19 @@
|
||||
package encrypt
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideEncrypter,
|
||||
)
|
||||
|
||||
func ProvideEncrypter(config *types.Config) (Encrypter, error) {
|
||||
if config.Encrypter.Secret == "" {
|
||||
return &none{}, nil
|
||||
}
|
||||
return New(config.Encrypter.Secret, config.Encrypter.EncryptMixedContent)
|
||||
}
|
29
internal/api/auth/pipeline.go
Normal file
29
internal/api/auth/pipeline.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckPipeline checks if a repo specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckPipeline(ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
parentPath, uid string, permission enum.Permission) error {
|
||||
scope := &types.Scope{SpacePath: parentPath}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypePipeline,
|
||||
Name: uid,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
29
internal/api/auth/secret.go
Normal file
29
internal/api/auth/secret.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// CheckSecret checks if a repo specific permission is granted for the current auth session
|
||||
// in the scope of its parent.
|
||||
// Returns nil if the permission is granted, otherwise returns an error.
|
||||
// NotAuthenticated, NotAuthorized, or any underlying error.
|
||||
func CheckSecret(ctx context.Context, authorizer authz.Authorizer, session *auth.Session,
|
||||
parentPath, uid string, permission enum.Permission) error {
|
||||
scope := &types.Scope{SpacePath: parentPath}
|
||||
resource := &types.Resource{
|
||||
Type: enum.ResourceTypeSecret,
|
||||
Name: uid,
|
||||
}
|
||||
|
||||
return Check(ctx, authorizer, session, scope, resource, permission)
|
||||
}
|
36
internal/api/controller/execution/controller.go
Normal file
36
internal/api/controller/execution/controller.go
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
db *sqlx.DB
|
||||
authorizer authz.Authorizer
|
||||
executionStore store.ExecutionStore
|
||||
pipelineStore store.PipelineStore
|
||||
spaceStore store.SpaceStore
|
||||
}
|
||||
|
||||
func NewController(
|
||||
db *sqlx.DB,
|
||||
authorizer authz.Authorizer,
|
||||
executionStore store.ExecutionStore,
|
||||
pipelineStore store.PipelineStore,
|
||||
spaceStore store.SpaceStore,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
db: db,
|
||||
authorizer: authorizer,
|
||||
executionStore: executionStore,
|
||||
pipelineStore: pipelineStore,
|
||||
spaceStore: spaceStore,
|
||||
}
|
||||
}
|
66
internal/api/controller/execution/create.go
Normal file
66
internal/api/controller/execution/create.go
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// TODO: Add more as needed.
|
||||
type CreateInput struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (c *Controller) Create(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
uid string,
|
||||
in *CreateInput,
|
||||
) (*types.Execution, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find space: %w", err)
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, uid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find pipeline: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, pipeline.UID, enum.PermissionPipelineExecute)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
pipeline, err = c.pipelineStore.IncrementSeqNum(ctx, pipeline)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to increment sequence number: %w", err)
|
||||
}
|
||||
|
||||
now := time.Now().UnixMilli()
|
||||
execution := &types.Execution{
|
||||
Number: pipeline.Seq,
|
||||
Status: in.Status,
|
||||
RepoID: pipeline.RepoID,
|
||||
PipelineID: pipeline.ID,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
Version: 0,
|
||||
}
|
||||
err = c.executionStore.Create(ctx, execution)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("execution creation failed: %w", err)
|
||||
}
|
||||
|
||||
return execution, nil
|
||||
}
|
41
internal/api/controller/execution/delete.go
Normal file
41
internal/api/controller/execution/delete.go
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Delete(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
pipelineUID string,
|
||||
executionNum int64,
|
||||
) error {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find parent space: %w", err)
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, pipelineUID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find pipeline: %w", err)
|
||||
}
|
||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, pipeline.UID, enum.PermissionPipelineDelete)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not authorize: %w", err)
|
||||
}
|
||||
err = c.executionStore.Delete(ctx, pipeline.ID, executionNum)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not delete execution: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
40
internal/api/controller/execution/find.go
Normal file
40
internal/api/controller/execution/find.go
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Find(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
pipelineUID string,
|
||||
executionNum int64,
|
||||
) (*types.Execution, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find parent space: %w", err)
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, pipelineUID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find pipeline: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, pipeline.UID, enum.PermissionPipelineView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not authorize: %w", err)
|
||||
}
|
||||
|
||||
return c.executionStore.Find(ctx, pipeline.ID, executionNum)
|
||||
}
|
59
internal/api/controller/execution/list.go
Normal file
59
internal/api/controller/execution/list.go
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) List(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
pipelineUID string,
|
||||
pagination types.Pagination,
|
||||
) ([]*types.Execution, int64, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to find parent space: %w", err)
|
||||
}
|
||||
pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, pipelineUID)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to find pipeline: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, pipeline.UID, enum.PermissionPipelineView)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
var count int64
|
||||
var executions []*types.Execution
|
||||
|
||||
err = dbtx.New(c.db).WithTx(ctx, func(ctx context.Context) (err error) {
|
||||
count, err = c.executionStore.Count(ctx, pipeline.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count child executions: %w", err)
|
||||
}
|
||||
|
||||
executions, err = c.executionStore.List(ctx, pipeline.ID, pagination)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list child executions: %w", err)
|
||||
}
|
||||
|
||||
return
|
||||
}, dbtx.TxDefaultReadOnly)
|
||||
if err != nil {
|
||||
return executions, count, fmt.Errorf("failed to fetch list: %w", err)
|
||||
}
|
||||
|
||||
return executions, count, nil
|
||||
}
|
57
internal/api/controller/execution/update.go
Normal file
57
internal/api/controller/execution/update.go
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
type UpdateInput struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (c *Controller) Update(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
pipelineUID string,
|
||||
executionNum int64,
|
||||
in *UpdateInput) (*types.Execution, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, pipelineUID, enum.PermissionPipelineEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check auth: %w", err)
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, pipelineUID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find pipeline: %w", err)
|
||||
}
|
||||
|
||||
execution, err := c.executionStore.Find(ctx, pipeline.ID, executionNum)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find execution: %w", err)
|
||||
}
|
||||
|
||||
return c.executionStore.UpdateOptLock(ctx,
|
||||
execution, func(original *types.Execution) error {
|
||||
// update values only if provided
|
||||
if in.Status != "" {
|
||||
original.Status = in.Status
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
27
internal/api/controller/execution/wire.go
Normal file
27
internal/api/controller/execution/wire.go
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideController,
|
||||
)
|
||||
|
||||
func ProvideController(db *sqlx.DB,
|
||||
authorizer authz.Authorizer,
|
||||
executionStore store.ExecutionStore,
|
||||
pipelineStore store.PipelineStore,
|
||||
spaceStore store.SpaceStore,
|
||||
) *Controller {
|
||||
return NewController(db, authorizer, executionStore, pipelineStore, spaceStore)
|
||||
}
|
44
internal/api/controller/pipeline/controller.go
Normal file
44
internal/api/controller/pipeline/controller.go
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/types/check"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
defaultBranch string
|
||||
db *sqlx.DB
|
||||
uidCheck check.PathUID
|
||||
pathStore store.PathStore
|
||||
repoStore store.RepoStore
|
||||
authorizer authz.Authorizer
|
||||
pipelineStore store.PipelineStore
|
||||
spaceStore store.SpaceStore
|
||||
}
|
||||
|
||||
func NewController(
|
||||
db *sqlx.DB,
|
||||
uidCheck check.PathUID,
|
||||
authorizer authz.Authorizer,
|
||||
pathStore store.PathStore,
|
||||
repoStore store.RepoStore,
|
||||
pipelineStore store.PipelineStore,
|
||||
spaceStore store.SpaceStore,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
db: db,
|
||||
uidCheck: uidCheck,
|
||||
pathStore: pathStore,
|
||||
repoStore: repoStore,
|
||||
authorizer: authorizer,
|
||||
pipelineStore: pipelineStore,
|
||||
spaceStore: spaceStore,
|
||||
}
|
||||
}
|
106
internal/api/controller/pipeline/create.go
Normal file
106
internal/api/controller/pipeline/create.go
Normal file
@ -0,0 +1,106 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/api/usererror"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
var (
|
||||
// errPipelineRequiresParent if the user tries to create a pipeline without a parent space.
|
||||
errPipelineRequiresParent = usererror.BadRequest(
|
||||
"Parent space required - standalone pipelines are not supported.")
|
||||
)
|
||||
|
||||
type CreateInput struct {
|
||||
Description string `json:"description"`
|
||||
SpaceRef string `json:"space_ref"`
|
||||
UID string `json:"uid"`
|
||||
RepoRef string `json:"repo_ref"` // empty if repo_type != gitness
|
||||
RepoType enum.ScmType `json:"repo_type"`
|
||||
DefaultBranch string `json:"default_branch"`
|
||||
ConfigPath string `json:"config_path"`
|
||||
}
|
||||
|
||||
func (c *Controller) Create(ctx context.Context, session *auth.Session, in *CreateInput) (*types.Pipeline, error) {
|
||||
parentSpace, err := c.spaceStore.FindByRef(ctx, in.SpaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find parent by ref: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, parentSpace.Path, in.UID, enum.PermissionPipelineEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var repoID int64
|
||||
|
||||
if in.RepoType == enum.ScmTypeGitness {
|
||||
repo, err := c.repoStore.FindByRef(ctx, in.RepoRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find repo by ref: %w", err)
|
||||
}
|
||||
repoID = repo.ID
|
||||
}
|
||||
|
||||
if err := c.sanitizeCreateInput(in); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
|
||||
var pipeline *types.Pipeline
|
||||
now := time.Now().UnixMilli()
|
||||
pipeline = &types.Pipeline{
|
||||
Description: in.Description,
|
||||
SpaceID: parentSpace.ID,
|
||||
UID: in.UID,
|
||||
Seq: 0,
|
||||
RepoID: repoID,
|
||||
RepoType: in.RepoType,
|
||||
DefaultBranch: in.DefaultBranch,
|
||||
ConfigPath: in.ConfigPath,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
Version: 0,
|
||||
}
|
||||
err = c.pipelineStore.Create(ctx, pipeline)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("pipeline creation failed: %w", err)
|
||||
}
|
||||
|
||||
return pipeline, nil
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeCreateInput(in *CreateInput) error {
|
||||
parentRefAsID, err := strconv.ParseInt(in.SpaceRef, 10, 64)
|
||||
if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(in.SpaceRef)) == 0) {
|
||||
return errPipelineRequiresParent
|
||||
}
|
||||
|
||||
if err := c.uidCheck(in.UID, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
in.Description = strings.TrimSpace(in.Description)
|
||||
if err := check.Description(in.Description); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if in.DefaultBranch == "" {
|
||||
in.DefaultBranch = c.defaultBranch
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
31
internal/api/controller/pipeline/delete.go
Normal file
31
internal/api/controller/pipeline/delete.go
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Delete(ctx context.Context, session *auth.Session, spaceRef string, uid string) error {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find parent space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, uid, enum.PermissionPipelineDelete)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not authorize: %w", err)
|
||||
}
|
||||
err = c.pipelineStore.DeleteByUID(ctx, space.ID, uid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not delete pipeline: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
32
internal/api/controller/pipeline/find.go
Normal file
32
internal/api/controller/pipeline/find.go
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Find(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
uid string,
|
||||
) (*types.Pipeline, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find parent space: %w", err)
|
||||
}
|
||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, uid, enum.PermissionPipelineView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not authorize: %w", err)
|
||||
}
|
||||
return c.pipelineStore.FindByUID(ctx, space.ID, uid)
|
||||
}
|
58
internal/api/controller/pipeline/update.go
Normal file
58
internal/api/controller/pipeline/update.go
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
type UpdateInput struct {
|
||||
Description string `json:"description"`
|
||||
UID string `json:"uid"`
|
||||
ConfigPath string `json:"config_path"`
|
||||
}
|
||||
|
||||
func (c *Controller) Update(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
uid string,
|
||||
in *UpdateInput,
|
||||
) (*types.Pipeline, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find parent space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, space.Path, uid, enum.PermissionPipelineEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not authorize: %w", err)
|
||||
}
|
||||
|
||||
pipeline, err := c.pipelineStore.FindByUID(ctx, space.ID, uid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find pipeline: %w", err)
|
||||
}
|
||||
|
||||
return c.pipelineStore.UpdateOptLock(ctx, pipeline, func(pipeline *types.Pipeline) error {
|
||||
if in.Description != "" {
|
||||
pipeline.Description = in.Description
|
||||
}
|
||||
if in.UID != "" {
|
||||
pipeline.UID = in.UID
|
||||
}
|
||||
if in.ConfigPath != "" {
|
||||
pipeline.ConfigPath = in.ConfigPath
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
30
internal/api/controller/pipeline/wire.go
Normal file
30
internal/api/controller/pipeline/wire.go
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/types/check"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideController,
|
||||
)
|
||||
|
||||
func ProvideController(db *sqlx.DB,
|
||||
uidCheck check.PathUID,
|
||||
pathStore store.PathStore,
|
||||
repoStore store.RepoStore,
|
||||
authorizer authz.Authorizer,
|
||||
pipelineStore store.PipelineStore,
|
||||
spaceStore store.SpaceStore,
|
||||
) *Controller {
|
||||
return NewController(db, uidCheck, authorizer, pathStore, repoStore, pipelineStore, spaceStore)
|
||||
}
|
44
internal/api/controller/secret/controller.go
Normal file
44
internal/api/controller/secret/controller.go
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/encrypt"
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/types/check"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
db *sqlx.DB
|
||||
uidCheck check.PathUID
|
||||
pathStore store.PathStore
|
||||
encrypter encrypt.Encrypter
|
||||
secretStore store.SecretStore
|
||||
authorizer authz.Authorizer
|
||||
spaceStore store.SpaceStore
|
||||
}
|
||||
|
||||
func NewController(
|
||||
db *sqlx.DB,
|
||||
uidCheck check.PathUID,
|
||||
authorizer authz.Authorizer,
|
||||
pathStore store.PathStore,
|
||||
encrypter encrypt.Encrypter,
|
||||
secretStore store.SecretStore,
|
||||
spaceStore store.SpaceStore,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
db: db,
|
||||
uidCheck: uidCheck,
|
||||
pathStore: pathStore,
|
||||
encrypter: encrypter,
|
||||
secretStore: secretStore,
|
||||
authorizer: authorizer,
|
||||
spaceStore: spaceStore,
|
||||
}
|
||||
}
|
122
internal/api/controller/secret/create.go
Normal file
122
internal/api/controller/secret/create.go
Normal file
@ -0,0 +1,122 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/encrypt"
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/api/usererror"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/check"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
var (
|
||||
// errSecretRequiresParent if the user tries to create a secret without a parent space.
|
||||
errSecretRequiresParent = usererror.BadRequest(
|
||||
"Parent space required - standalone secret are not supported.")
|
||||
)
|
||||
|
||||
type CreateInput struct {
|
||||
Description string `json:"description"`
|
||||
SpaceRef string `json:"space_ref"` // Ref of the parent space
|
||||
UID string `json:"uid"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Controller) Create(ctx context.Context, session *auth.Session, in *CreateInput) (*types.Secret, error) {
|
||||
parentSpace, err := c.spaceStore.FindByRef(ctx, in.SpaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find parent by ref: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckSecret(ctx, c.authorizer, session, parentSpace.Path, in.UID, enum.PermissionSecretEdit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.sanitizeCreateInput(in); err != nil {
|
||||
return nil, fmt.Errorf("failed to sanitize input: %w", err)
|
||||
}
|
||||
|
||||
var secret *types.Secret
|
||||
now := time.Now().UnixMilli()
|
||||
secret = &types.Secret{
|
||||
Description: in.Description,
|
||||
Data: in.Data,
|
||||
SpaceID: parentSpace.ID,
|
||||
UID: in.UID,
|
||||
Created: now,
|
||||
Updated: now,
|
||||
Version: 0,
|
||||
}
|
||||
secret, err = enc(c.encrypter, secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not encrypt secret: %w", err)
|
||||
}
|
||||
err = c.secretStore.Create(ctx, secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("secret creation failed: %w", err)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func (c *Controller) sanitizeCreateInput(in *CreateInput) error {
|
||||
parentRefAsID, err := strconv.ParseInt(in.SpaceRef, 10, 64)
|
||||
|
||||
if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(in.SpaceRef)) == 0) {
|
||||
return errSecretRequiresParent
|
||||
}
|
||||
|
||||
if err := c.uidCheck(in.UID, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
in.Description = strings.TrimSpace(in.Description)
|
||||
if err := check.Description(in.Description); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// helper function returns the same secret with encrypted data.
|
||||
func enc(encrypt encrypt.Encrypter, secret *types.Secret) (*types.Secret, error) {
|
||||
if secret == nil {
|
||||
return nil, fmt.Errorf("cannot encrypt a nil secret")
|
||||
}
|
||||
s := *secret
|
||||
ciphertext, err := encrypt.Encrypt(secret.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Data = string(ciphertext)
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
// helper function returns the same secret with decrypted data.
|
||||
func dec(encrypt encrypt.Encrypter, secret *types.Secret) (*types.Secret, error) {
|
||||
if secret == nil {
|
||||
return nil, fmt.Errorf("cannot decrypt a nil secret")
|
||||
}
|
||||
s := *secret
|
||||
plaintext, err := encrypt.Decrypt([]byte(secret.Data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Data = plaintext
|
||||
return &s, nil
|
||||
}
|
31
internal/api/controller/secret/delete.go
Normal file
31
internal/api/controller/secret/delete.go
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Delete(ctx context.Context, session *auth.Session, spaceRef string, uid string) error {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckSecret(ctx, c.authorizer, session, space.Path, uid, enum.PermissionSecretDelete)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
err = c.secretStore.DeleteByUID(ctx, space.ID, uid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not delete secret: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
40
internal/api/controller/secret/find.go
Normal file
40
internal/api/controller/secret/find.go
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
func (c *Controller) Find(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
uid string,
|
||||
) (*types.Secret, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find space: %w", err)
|
||||
}
|
||||
err = apiauth.CheckSecret(ctx, c.authorizer, session, space.Path, uid, enum.PermissionSecretView)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
secret, err := c.secretStore.FindByUID(ctx, space.ID, uid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find secret: %w", err)
|
||||
}
|
||||
secret, err = dec(c.encrypter, secret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not decrypt secret: %w", err)
|
||||
}
|
||||
return secret, nil
|
||||
}
|
63
internal/api/controller/secret/update.go
Normal file
63
internal/api/controller/secret/update.go
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// UpdateInput is used for updating a repo.
|
||||
type UpdateInput struct {
|
||||
Description string `json:"description"`
|
||||
UID string `json:"uid"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Controller) Update(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
uid string,
|
||||
in *UpdateInput,
|
||||
) (*types.Secret, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckSecret(ctx, c.authorizer, session, space.Path, uid, enum.PermissionSecretEdit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to authorize: %w", err)
|
||||
}
|
||||
|
||||
secret, err := c.secretStore.FindByUID(ctx, space.ID, uid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find secret: %w", err)
|
||||
}
|
||||
|
||||
return c.secretStore.UpdateOptLock(ctx, secret, func(original *types.Secret) error {
|
||||
if in.Description != "" {
|
||||
original.Description = in.Description
|
||||
}
|
||||
if in.Data != "" {
|
||||
data, err := c.encrypter.Encrypt(original.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not encrypt secret: %w", err)
|
||||
}
|
||||
original.Data = string(data)
|
||||
}
|
||||
if in.UID != "" {
|
||||
original.UID = in.UID
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
31
internal/api/controller/secret/wire.go
Normal file
31
internal/api/controller/secret/wire.go
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/encrypt"
|
||||
"github.com/harness/gitness/internal/auth/authz"
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/types/check"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideController,
|
||||
)
|
||||
|
||||
func ProvideController(db *sqlx.DB,
|
||||
uidCheck check.PathUID,
|
||||
pathStore store.PathStore,
|
||||
encrypter encrypt.Encrypter,
|
||||
secretStore store.SecretStore,
|
||||
authorizer authz.Authorizer,
|
||||
spaceStore store.SpaceStore,
|
||||
) *Controller {
|
||||
return NewController(db, uidCheck, authorizer, pathStore, encrypter, secretStore, spaceStore)
|
||||
}
|
@ -20,6 +20,8 @@ type Controller struct {
|
||||
uidCheck check.PathUID
|
||||
authorizer authz.Authorizer
|
||||
pathStore store.PathStore
|
||||
pipelineStore store.PipelineStore
|
||||
secretStore store.SecretStore
|
||||
spaceStore store.SpaceStore
|
||||
repoStore store.RepoStore
|
||||
principalStore store.PrincipalStore
|
||||
@ -29,9 +31,9 @@ type Controller struct {
|
||||
|
||||
func NewController(db *sqlx.DB, urlProvider *url.Provider,
|
||||
uidCheck check.PathUID, authorizer authz.Authorizer,
|
||||
pathStore store.PathStore, spaceStore store.SpaceStore,
|
||||
repoStore store.RepoStore, principalStore store.PrincipalStore, repoCtrl *repo.Controller,
|
||||
membershipStore store.MembershipStore,
|
||||
pathStore store.PathStore, pipelineStore store.PipelineStore, secretStore store.SecretStore,
|
||||
spaceStore store.SpaceStore, repoStore store.RepoStore, principalStore store.PrincipalStore,
|
||||
repoCtrl *repo.Controller, membershipStore store.MembershipStore,
|
||||
) *Controller {
|
||||
return &Controller{
|
||||
db: db,
|
||||
@ -39,6 +41,8 @@ func NewController(db *sqlx.DB, urlProvider *url.Provider,
|
||||
uidCheck: uidCheck,
|
||||
authorizer: authorizer,
|
||||
pathStore: pathStore,
|
||||
pipelineStore: pipelineStore,
|
||||
secretStore: secretStore,
|
||||
spaceStore: spaceStore,
|
||||
repoStore: repoStore,
|
||||
principalStore: principalStore,
|
||||
|
54
internal/api/controller/space/list_pipelines.go
Normal file
54
internal/api/controller/space/list_pipelines.go
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
package space
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// ListPipelines lists the pipelines in a space.
|
||||
func (c *Controller) ListPipelines(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
filter types.ListQueryFilter,
|
||||
) ([]*types.Pipeline, int64, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to find parent space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionPipelineView, false)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("could not authorize: %w", err)
|
||||
}
|
||||
|
||||
var count int64
|
||||
var pipelines []*types.Pipeline
|
||||
|
||||
err = dbtx.New(c.db).WithTx(ctx, func(ctx context.Context) (err error) {
|
||||
count, err = c.pipelineStore.Count(ctx, space.ID, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count child executions: %w", err)
|
||||
}
|
||||
|
||||
pipelines, err = c.pipelineStore.List(ctx, space.ID, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count child executions: %w", err)
|
||||
}
|
||||
return
|
||||
}, dbtx.TxDefaultReadOnly)
|
||||
if err != nil {
|
||||
return pipelines, count, fmt.Errorf("failed to list pipelines: %w", err)
|
||||
}
|
||||
|
||||
return pipelines, count, nil
|
||||
}
|
54
internal/api/controller/space/list_secrets.go
Normal file
54
internal/api/controller/space/list_secrets.go
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
package space
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
apiauth "github.com/harness/gitness/internal/api/auth"
|
||||
"github.com/harness/gitness/internal/auth"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// ListSecrets lists the secrets in a space.
|
||||
func (c *Controller) ListSecrets(
|
||||
ctx context.Context,
|
||||
session *auth.Session,
|
||||
spaceRef string,
|
||||
filter types.ListQueryFilter,
|
||||
) ([]*types.Secret, int64, error) {
|
||||
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to find parent space: %w", err)
|
||||
}
|
||||
|
||||
err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSecretView, false)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("could not authorize: %w", err)
|
||||
}
|
||||
|
||||
var count int64
|
||||
var secrets []*types.Secret
|
||||
|
||||
err = dbtx.New(c.db).WithTx(ctx, func(ctx context.Context) (err error) {
|
||||
count, err = c.secretStore.Count(ctx, space.ID, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to count child executions: %w", err)
|
||||
}
|
||||
|
||||
secrets, err = c.secretStore.List(ctx, space.ID, filter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list child executions: %w", err)
|
||||
}
|
||||
return
|
||||
}, dbtx.TxDefaultReadOnly)
|
||||
if err != nil {
|
||||
return secrets, count, fmt.Errorf("failed to list secrets: %w", err)
|
||||
}
|
||||
|
||||
return secrets, count, nil
|
||||
}
|
@ -21,12 +21,11 @@ var WireSet = wire.NewSet(
|
||||
)
|
||||
|
||||
func ProvideController(db *sqlx.DB, urlProvider *url.Provider, uidCheck check.PathUID, authorizer authz.Authorizer,
|
||||
pathStore store.PathStore, spaceStore store.SpaceStore, repoStore store.RepoStore,
|
||||
principalStore store.PrincipalStore, repoCtrl *repo.Controller,
|
||||
membershipStore store.MembershipStore,
|
||||
pathStore store.PathStore, pipelineStore store.PipelineStore, secretStore store.SecretStore,
|
||||
spaceStore store.SpaceStore, repoStore store.RepoStore, principalStore store.PrincipalStore,
|
||||
repoCtrl *repo.Controller, membershipStore store.MembershipStore,
|
||||
) *Controller {
|
||||
return NewController(db, urlProvider, uidCheck, authorizer,
|
||||
pathStore, spaceStore, repoStore,
|
||||
principalStore, repoCtrl,
|
||||
membershipStore)
|
||||
pathStore, pipelineStore, secretStore, spaceStore, repoStore,
|
||||
principalStore, repoCtrl, membershipStore)
|
||||
}
|
||||
|
47
internal/api/handler/execution/create.go
Normal file
47
internal/api/handler/execution/create.go
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleCreate(executionCtrl *execution.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
pipelineRef, err := request.GetPipelineRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, pipelineUID, err := paths.DisectLeaf(pipelineRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
in := new(execution.CreateInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
execution, err := executionCtrl.Create(ctx, session, spaceRef, pipelineUID, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusCreated, execution)
|
||||
}
|
||||
}
|
44
internal/api/handler/execution/delete.go
Normal file
44
internal/api/handler/execution/delete.go
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleDelete(executionCtrl *execution.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
pipelineRef, err := request.GetPipelineRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, pipelineUID, err := paths.DisectLeaf(pipelineRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
n, err := request.GetExecutionNumberFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = executionCtrl.Delete(ctx, session, spaceRef, pipelineUID, n)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.DeleteSuccessful(w)
|
||||
}
|
||||
}
|
44
internal/api/handler/execution/find.go
Normal file
44
internal/api/handler/execution/find.go
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleFind(executionCtrl *execution.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
pipelineRef, err := request.GetPipelineRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
n, err := request.GetExecutionNumberFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, pipelineUID, err := paths.DisectLeaf(pipelineRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
execution, err := executionCtrl.Find(ctx, session, spaceRef, pipelineUID, n)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, execution)
|
||||
}
|
||||
}
|
42
internal/api/handler/execution/list.go
Normal file
42
internal/api/handler/execution/list.go
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleList(executionCtrl *execution.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
pipelineRef, err := request.GetPipelineRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, pipelineUID, err := paths.DisectLeaf(pipelineRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
pagination := request.ParsePaginationFromRequest(r)
|
||||
|
||||
repos, totalCount, err := executionCtrl.List(ctx, session, spaceRef, pipelineUID, pagination)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Pagination(r, w, pagination.Page, pagination.Size, int(totalCount))
|
||||
render.JSON(w, http.StatusOK, repos)
|
||||
}
|
||||
}
|
53
internal/api/handler/execution/update.go
Normal file
53
internal/api/handler/execution/update.go
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package execution
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleUpdate(executionCtrl *execution.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
|
||||
in := new(execution.UpdateInput)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
pipelineRef, err := request.GetPipelineRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, pipelineUID, err := paths.DisectLeaf(pipelineRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
n, err := request.GetExecutionNumberFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
pipeline, err := executionCtrl.Update(ctx, session, spaceRef, pipelineUID, n, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, pipeline)
|
||||
}
|
||||
}
|
36
internal/api/handler/pipeline/create.go
Normal file
36
internal/api/handler/pipeline/create.go
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/pipeline"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
)
|
||||
|
||||
func HandleCreate(pipelineCtrl *pipeline.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
|
||||
in := new(pipeline.CreateInput)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
pipeline, err := pipelineCtrl.Create(ctx, session, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusCreated, pipeline)
|
||||
}
|
||||
}
|
39
internal/api/handler/pipeline/delete.go
Normal file
39
internal/api/handler/pipeline/delete.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/pipeline"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleDelete(pipelineCtrl *pipeline.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
pipelineRef, err := request.GetPipelineRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, pipelineUID, err := paths.DisectLeaf(pipelineRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = pipelineCtrl.Delete(ctx, session, spaceRef, pipelineUID)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.DeleteSuccessful(w)
|
||||
}
|
||||
}
|
39
internal/api/handler/pipeline/find.go
Normal file
39
internal/api/handler/pipeline/find.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/pipeline"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleFind(pipelineCtrl *pipeline.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
pipelineRef, err := request.GetPipelineRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, pipelineUID, err := paths.DisectLeaf(pipelineRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
pipeline, err := pipelineCtrl.Find(ctx, session, spaceRef, pipelineUID)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, pipeline)
|
||||
}
|
||||
}
|
48
internal/api/handler/pipeline/update.go
Normal file
48
internal/api/handler/pipeline/update.go
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package pipeline
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/pipeline"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleUpdate(pipelineCtrl *pipeline.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
|
||||
in := new(pipeline.UpdateInput)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
pipelineRef, err := request.GetPipelineRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, pipelineUID, err := paths.DisectLeaf(pipelineRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
pipeline, err := pipelineCtrl.Update(ctx, session, spaceRef, pipelineUID, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, pipeline)
|
||||
}
|
||||
}
|
37
internal/api/handler/secret/create.go
Normal file
37
internal/api/handler/secret/create.go
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/secret"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
)
|
||||
|
||||
// HandleCreate returns a http.HandlerFunc that creates a new secretsitory.
|
||||
func HandleCreate(secretCtrl *secret.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
|
||||
in := new(secret.CreateInput)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
secret, err := secretCtrl.Create(ctx, session, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusCreated, secret.CopyWithoutData())
|
||||
}
|
||||
}
|
39
internal/api/handler/secret/delete.go
Normal file
39
internal/api/handler/secret/delete.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/secret"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleDelete(secretCtrl *secret.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
secretRef, err := request.GetSecretRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, secretUID, err := paths.DisectLeaf(secretRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = secretCtrl.Delete(ctx, session, spaceRef, secretUID)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.DeleteSuccessful(w)
|
||||
}
|
||||
}
|
39
internal/api/handler/secret/find.go
Normal file
39
internal/api/handler/secret/find.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/secret"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
// HandleFind finds a secret from the database.
|
||||
func HandleFind(secretCtrl *secret.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
secretRef, err := request.GetSecretRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, secretUID, err := paths.DisectLeaf(secretRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
}
|
||||
|
||||
secret, err := secretCtrl.Find(ctx, session, spaceRef, secretUID)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, secret.CopyWithoutData())
|
||||
}
|
||||
}
|
47
internal/api/handler/secret/update.go
Normal file
47
internal/api/handler/secret/update.go
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package secret
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/secret"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/internal/paths"
|
||||
)
|
||||
|
||||
func HandleUpdate(secretCtrl *secret.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
|
||||
in := new(secret.UpdateInput)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(w, "Invalid Request Body: %s.", err)
|
||||
return
|
||||
}
|
||||
|
||||
secretRef, err := request.GetSecretRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
spaceRef, secretUID, err := paths.DisectLeaf(secretRef)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
}
|
||||
|
||||
secret, err := secretCtrl.Update(ctx, session, spaceRef, secretUID, in)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, secret.CopyWithoutData())
|
||||
}
|
||||
}
|
35
internal/api/handler/space/list_pipelines.go
Normal file
35
internal/api/handler/space/list_pipelines.go
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package space
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/space"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
)
|
||||
|
||||
func HandleListPipelines(spaceCtrl *space.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
spaceRef, err := request.GetSpaceRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
filter := request.ParseListQueryFilterFromRequest(r)
|
||||
repos, totalCount, err := spaceCtrl.ListPipelines(ctx, session, spaceRef, filter)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.Pagination(r, w, filter.Page, filter.Size, int(totalCount))
|
||||
render.JSON(w, http.StatusOK, repos)
|
||||
}
|
||||
}
|
42
internal/api/handler/space/list_secrets.go
Normal file
42
internal/api/handler/space/list_secrets.go
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package space
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/space"
|
||||
"github.com/harness/gitness/internal/api/render"
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
func HandleListSecrets(spaceCtrl *space.Controller) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
spaceRef, err := request.GetSpaceRefFromPath(r)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
filter := request.ParseListQueryFilterFromRequest(r)
|
||||
ret, totalCount, err := spaceCtrl.ListSecrets(ctx, session, spaceRef, filter)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Strip out data in the returned value
|
||||
secrets := []types.Secret{}
|
||||
for _, s := range ret {
|
||||
secrets = append(secrets, *s.CopyWithoutData())
|
||||
}
|
||||
|
||||
render.Pagination(r, w, filter.Page, filter.Size, int(totalCount))
|
||||
render.JSON(w, http.StatusOK, secrets)
|
||||
}
|
||||
}
|
@ -41,6 +41,8 @@ func Generate() *openapi3.Spec {
|
||||
buildPrincipals(&reflector)
|
||||
spaceOperations(&reflector)
|
||||
repoOperations(&reflector)
|
||||
pipelineOperations(&reflector)
|
||||
secretOperations(&reflector)
|
||||
resourceOperations(&reflector)
|
||||
pullReqOperations(&reflector)
|
||||
webhookOperations(&reflector)
|
||||
|
162
internal/api/openapi/pipeline.go
Normal file
162
internal/api/openapi/pipeline.go
Normal file
@ -0,0 +1,162 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package openapi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
"github.com/harness/gitness/internal/api/controller/pipeline"
|
||||
"github.com/harness/gitness/internal/api/usererror"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/swaggest/openapi-go/openapi3"
|
||||
)
|
||||
|
||||
type pipelineRequest struct {
|
||||
Ref string `path:"pipeline_ref"`
|
||||
}
|
||||
|
||||
type executionRequest struct {
|
||||
pipelineRequest
|
||||
Number string `path:"execution_number"`
|
||||
}
|
||||
|
||||
type createExecutionRequest struct {
|
||||
pipelineRequest
|
||||
execution.CreateInput
|
||||
}
|
||||
|
||||
type createPipelineRequest struct {
|
||||
pipeline.CreateInput
|
||||
}
|
||||
|
||||
type getExecutionRequest struct {
|
||||
executionRequest
|
||||
}
|
||||
|
||||
type getPipelineRequest struct {
|
||||
pipelineRequest
|
||||
}
|
||||
|
||||
type updateExecutionRequest struct {
|
||||
executionRequest
|
||||
execution.UpdateInput
|
||||
}
|
||||
|
||||
type updatePipelineRequest struct {
|
||||
pipelineRequest
|
||||
pipeline.UpdateInput
|
||||
}
|
||||
|
||||
func pipelineOperations(reflector *openapi3.Reflector) {
|
||||
opCreate := openapi3.Operation{}
|
||||
opCreate.WithTags("pipeline")
|
||||
opCreate.WithMapOfAnything(map[string]interface{}{"operationId": "createPipeline"})
|
||||
_ = reflector.SetRequest(&opCreate, new(createPipelineRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(types.Pipeline), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPost, "/pipelines", opCreate)
|
||||
|
||||
opFind := openapi3.Operation{}
|
||||
opFind.WithTags("pipeline")
|
||||
opFind.WithMapOfAnything(map[string]interface{}{"operationId": "findPipeline"})
|
||||
_ = reflector.SetRequest(&opFind, new(getPipelineRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(types.Pipeline), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/pipelines/{pipeline_ref}", opFind)
|
||||
|
||||
opDelete := openapi3.Operation{}
|
||||
opDelete.WithTags("pipeline")
|
||||
opDelete.WithMapOfAnything(map[string]interface{}{"operationId": "deletePipeline"})
|
||||
_ = reflector.SetRequest(&opDelete, new(getPipelineRequest), http.MethodDelete)
|
||||
_ = reflector.SetJSONResponse(&opDelete, nil, http.StatusNoContent)
|
||||
_ = reflector.SetJSONResponse(&opDelete, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opDelete, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opDelete, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opDelete, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodDelete, "/pipelines/{pipeline_ref}", opDelete)
|
||||
|
||||
opUpdate := openapi3.Operation{}
|
||||
opUpdate.WithTags("pipeline")
|
||||
opUpdate.WithMapOfAnything(map[string]interface{}{"operationId": "updatePipeline"})
|
||||
_ = reflector.SetRequest(&opUpdate, new(updatePipelineRequest), http.MethodPatch)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(types.Pipeline), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPatch,
|
||||
"/pipelines/{pipeline_ref}", opUpdate)
|
||||
|
||||
executionCreate := openapi3.Operation{}
|
||||
executionCreate.WithTags("pipeline")
|
||||
executionCreate.WithMapOfAnything(map[string]interface{}{"operationId": "createExecution"})
|
||||
_ = reflector.SetRequest(&executionCreate, new(createExecutionRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&executionCreate, new(types.Execution), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&executionCreate, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&executionCreate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&executionCreate, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&executionCreate, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPost,
|
||||
"/pipelines/{pipeline_ref}/executions", executionCreate)
|
||||
|
||||
executionFind := openapi3.Operation{}
|
||||
executionFind.WithTags("pipeline")
|
||||
executionFind.WithMapOfAnything(map[string]interface{}{"operationId": "findExecution"})
|
||||
_ = reflector.SetRequest(&executionFind, new(getExecutionRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&executionFind, new(types.Execution), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&executionFind, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&executionFind, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&executionFind, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&executionFind, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet,
|
||||
"/pipelines/{pipeline_ref}/executions/{execution_number}", executionFind)
|
||||
|
||||
executionDelete := openapi3.Operation{}
|
||||
executionDelete.WithTags("pipeline")
|
||||
executionDelete.WithMapOfAnything(map[string]interface{}{"operationId": "deleteExecution"})
|
||||
_ = reflector.SetRequest(&executionDelete, new(getExecutionRequest), http.MethodDelete)
|
||||
_ = reflector.SetJSONResponse(&executionDelete, nil, http.StatusNoContent)
|
||||
_ = reflector.SetJSONResponse(&executionDelete, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&executionDelete, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&executionDelete, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&executionDelete, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodDelete,
|
||||
"/pipelines/{pipeline_ref}/executions/{execution_number}", executionDelete)
|
||||
|
||||
executionUpdate := openapi3.Operation{}
|
||||
executionUpdate.WithTags("pipeline")
|
||||
executionUpdate.WithMapOfAnything(map[string]interface{}{"operationId": "updateExecution"})
|
||||
_ = reflector.SetRequest(&executionUpdate, new(updateExecutionRequest), http.MethodPatch)
|
||||
_ = reflector.SetJSONResponse(&executionUpdate, new(types.Execution), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&executionUpdate, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&executionUpdate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&executionUpdate, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&executionUpdate, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&executionUpdate, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPatch,
|
||||
"/pipelines/{pipeline_ref}/executions/{execution_number}", executionUpdate)
|
||||
|
||||
executionList := openapi3.Operation{}
|
||||
executionList.WithTags("pipeline")
|
||||
executionList.WithMapOfAnything(map[string]interface{}{"operationId": "listExecutions"})
|
||||
executionList.WithParameters(queryParameterPage, queryParameterLimit)
|
||||
_ = reflector.SetRequest(&executionList, new(pipelineRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&executionList, []types.Execution{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&executionList, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&executionList, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&executionList, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&executionList, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet,
|
||||
"/pipelines/{pipeline_ref}/executions", executionList)
|
||||
}
|
79
internal/api/openapi/secret.go
Normal file
79
internal/api/openapi/secret.go
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package openapi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/internal/api/controller/secret"
|
||||
"github.com/harness/gitness/internal/api/usererror"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/swaggest/openapi-go/openapi3"
|
||||
)
|
||||
|
||||
type createSecretRequest struct {
|
||||
secret.CreateInput
|
||||
}
|
||||
|
||||
type secretRequest struct {
|
||||
Ref string `path:"secret_ref"`
|
||||
}
|
||||
|
||||
type getSecretRequest struct {
|
||||
secretRequest
|
||||
}
|
||||
|
||||
type updateSecretRequest struct {
|
||||
secretRequest
|
||||
secret.UpdateInput
|
||||
}
|
||||
|
||||
func secretOperations(reflector *openapi3.Reflector) {
|
||||
opCreate := openapi3.Operation{}
|
||||
opCreate.WithTags("secret")
|
||||
opCreate.WithMapOfAnything(map[string]interface{}{"operationId": "createSecret"})
|
||||
_ = reflector.SetRequest(&opCreate, new(createSecretRequest), http.MethodPost)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(types.Secret), http.StatusCreated)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opCreate, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPost, "/secrets", opCreate)
|
||||
|
||||
opFind := openapi3.Operation{}
|
||||
opFind.WithTags("secret")
|
||||
opFind.WithMapOfAnything(map[string]interface{}{"operationId": "findSecret"})
|
||||
_ = reflector.SetRequest(&opFind, new(getSecretRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(types.Secret), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opFind, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/secrets/{secret_ref}", opFind)
|
||||
|
||||
opDelete := openapi3.Operation{}
|
||||
opDelete.WithTags("secret")
|
||||
opDelete.WithMapOfAnything(map[string]interface{}{"operationId": "deleteSecret"})
|
||||
_ = reflector.SetRequest(&opDelete, new(getSecretRequest), http.MethodDelete)
|
||||
_ = reflector.SetJSONResponse(&opDelete, nil, http.StatusNoContent)
|
||||
_ = reflector.SetJSONResponse(&opDelete, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opDelete, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opDelete, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opDelete, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodDelete, "/secrets/{secret_ref}", opDelete)
|
||||
|
||||
opUpdate := openapi3.Operation{}
|
||||
opUpdate.WithTags("secret")
|
||||
opUpdate.WithMapOfAnything(map[string]interface{}{"operationId": "updateSecret"})
|
||||
_ = reflector.SetRequest(&opUpdate, new(updateSecretRequest), http.MethodPatch)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(types.Secret), http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusBadRequest)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opUpdate, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodPatch, "/secrets/{secret_ref}", opUpdate)
|
||||
}
|
@ -230,6 +230,30 @@ func spaceOperations(reflector *openapi3.Reflector) {
|
||||
_ = reflector.SetJSONResponse(&opRepos, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/spaces/{space_ref}/repos", opRepos)
|
||||
|
||||
opPipelines := openapi3.Operation{}
|
||||
opPipelines.WithTags("space")
|
||||
opPipelines.WithMapOfAnything(map[string]interface{}{"operationId": "listPipelines"})
|
||||
opPipelines.WithParameters(queryParameterQueryRepo, queryParameterPage, queryParameterLimit)
|
||||
_ = reflector.SetRequest(&opPipelines, new(spaceRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opPipelines, []types.Pipeline{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opPipelines, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opPipelines, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opPipelines, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opPipelines, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/spaces/{space_ref}/pipelines", opPipelines)
|
||||
|
||||
opSecrets := openapi3.Operation{}
|
||||
opSecrets.WithTags("space")
|
||||
opSecrets.WithMapOfAnything(map[string]interface{}{"operationId": "listSecrets"})
|
||||
opSecrets.WithParameters(queryParameterQueryRepo, queryParameterPage, queryParameterLimit)
|
||||
_ = reflector.SetRequest(&opSecrets, new(spaceRequest), http.MethodGet)
|
||||
_ = reflector.SetJSONResponse(&opSecrets, []types.Secret{}, http.StatusOK)
|
||||
_ = reflector.SetJSONResponse(&opSecrets, new(usererror.Error), http.StatusInternalServerError)
|
||||
_ = reflector.SetJSONResponse(&opSecrets, new(usererror.Error), http.StatusUnauthorized)
|
||||
_ = reflector.SetJSONResponse(&opSecrets, new(usererror.Error), http.StatusForbidden)
|
||||
_ = reflector.SetJSONResponse(&opSecrets, new(usererror.Error), http.StatusNotFound)
|
||||
_ = reflector.Spec.AddOperation(http.MethodGet, "/spaces/{space_ref}/secrets", opSecrets)
|
||||
|
||||
opServiceAccounts := openapi3.Operation{}
|
||||
opServiceAccounts.WithTags("space")
|
||||
opServiceAccounts.WithMapOfAnything(map[string]interface{}{"operationId": "listServiceAccounts"})
|
||||
|
29
internal/api/request/pipeline.go
Normal file
29
internal/api/request/pipeline.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package request
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
PathParamPipelineRef = "pipeline_ref"
|
||||
PathParamExecutionNumber = "execution_number"
|
||||
)
|
||||
|
||||
func GetPipelineRefFromPath(r *http.Request) (string, error) {
|
||||
rawRef, err := PathParamOrError(r, PathParamPipelineRef)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// paths are unescaped
|
||||
return url.PathUnescape(rawRef)
|
||||
}
|
||||
|
||||
func GetExecutionNumberFromPath(r *http.Request) (int64, error) {
|
||||
return PathParamAsPositiveInt64(r, PathParamExecutionNumber)
|
||||
}
|
24
internal/api/request/secret.go
Normal file
24
internal/api/request/secret.go
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package request
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
PathParamSecretRef = "secret_ref"
|
||||
)
|
||||
|
||||
func GetSecretRefFromPath(r *http.Request) (string, error) {
|
||||
rawRef, err := PathParamOrError(r, PathParamSecretRef)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// paths are unescaped
|
||||
return url.PathUnescape(rawRef)
|
||||
}
|
@ -9,6 +9,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/harness/gitness/internal/api/usererror"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
@ -17,11 +18,10 @@ import (
|
||||
const (
|
||||
PathParamRemainder = "*"
|
||||
|
||||
QueryParamSort = "sort"
|
||||
QueryParamOrder = "order"
|
||||
QueryParamQuery = "query"
|
||||
|
||||
QueryParamCreatedBy = "created_by"
|
||||
QueryParamSort = "sort"
|
||||
QueryParamOrder = "order"
|
||||
QueryParamQuery = "query"
|
||||
|
||||
QueryParamState = "state"
|
||||
QueryParamKind = "kind"
|
||||
@ -204,3 +204,19 @@ func ParseOrder(r *http.Request) enum.Order {
|
||||
func ParseSort(r *http.Request) string {
|
||||
return r.URL.Query().Get(QueryParamSort)
|
||||
}
|
||||
|
||||
// ParsePaginationFromRequest parses pagination related info from the url.
|
||||
func ParsePaginationFromRequest(r *http.Request) types.Pagination {
|
||||
return types.Pagination{
|
||||
Page: ParsePage(r),
|
||||
Size: ParseLimit(r),
|
||||
}
|
||||
}
|
||||
|
||||
// ParseListQueryFilterFromRequest parses pagination and query related info from the url.
|
||||
func ParseListQueryFilterFromRequest(r *http.Request) types.ListQueryFilter {
|
||||
return types.ListQueryFilter{
|
||||
Query: ParseQuery(r),
|
||||
Pagination: ParsePaginationFromRequest(r),
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,12 @@ func (a *MembershipAuthorizer) Check(
|
||||
case enum.ResourceTypeServiceAccount:
|
||||
spaceRef = scope.SpacePath
|
||||
|
||||
case enum.ResourceTypePipeline:
|
||||
spaceRef = scope.SpacePath
|
||||
|
||||
case enum.ResourceTypeSecret:
|
||||
spaceRef = scope.SpacePath
|
||||
|
||||
case enum.ResourceTypeUser:
|
||||
// a user is allowed to view / edit themselves
|
||||
if resource.Name == session.Principal.UID &&
|
||||
|
@ -10,21 +10,27 @@ import (
|
||||
|
||||
"github.com/harness/gitness/githook"
|
||||
"github.com/harness/gitness/internal/api/controller/check"
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
controllergithook "github.com/harness/gitness/internal/api/controller/githook"
|
||||
"github.com/harness/gitness/internal/api/controller/pipeline"
|
||||
"github.com/harness/gitness/internal/api/controller/principal"
|
||||
"github.com/harness/gitness/internal/api/controller/pullreq"
|
||||
"github.com/harness/gitness/internal/api/controller/repo"
|
||||
"github.com/harness/gitness/internal/api/controller/secret"
|
||||
"github.com/harness/gitness/internal/api/controller/serviceaccount"
|
||||
"github.com/harness/gitness/internal/api/controller/space"
|
||||
"github.com/harness/gitness/internal/api/controller/user"
|
||||
"github.com/harness/gitness/internal/api/controller/webhook"
|
||||
"github.com/harness/gitness/internal/api/handler/account"
|
||||
handlercheck "github.com/harness/gitness/internal/api/handler/check"
|
||||
handlerexecution "github.com/harness/gitness/internal/api/handler/execution"
|
||||
handlergithook "github.com/harness/gitness/internal/api/handler/githook"
|
||||
handlerpipeline "github.com/harness/gitness/internal/api/handler/pipeline"
|
||||
handlerprincipal "github.com/harness/gitness/internal/api/handler/principal"
|
||||
handlerpullreq "github.com/harness/gitness/internal/api/handler/pullreq"
|
||||
handlerrepo "github.com/harness/gitness/internal/api/handler/repo"
|
||||
"github.com/harness/gitness/internal/api/handler/resource"
|
||||
handlersecret "github.com/harness/gitness/internal/api/handler/secret"
|
||||
handlerserviceaccount "github.com/harness/gitness/internal/api/handler/serviceaccount"
|
||||
handlerspace "github.com/harness/gitness/internal/api/handler/space"
|
||||
"github.com/harness/gitness/internal/api/handler/system"
|
||||
@ -54,7 +60,7 @@ type APIHandler interface {
|
||||
|
||||
var (
|
||||
// terminatedPathPrefixesAPI is the list of prefixes that will require resolving terminated paths.
|
||||
terminatedPathPrefixesAPI = []string{"/v1/spaces/", "/v1/repos/"}
|
||||
terminatedPathPrefixesAPI = []string{"/v1/spaces/", "/v1/repos/", "/v1/pipelines/", "/v1/secrets/"}
|
||||
)
|
||||
|
||||
// NewAPIHandler returns a new APIHandler.
|
||||
@ -62,7 +68,10 @@ func NewAPIHandler(
|
||||
config *types.Config,
|
||||
authenticator authn.Authenticator,
|
||||
repoCtrl *repo.Controller,
|
||||
executionCtrl *execution.Controller,
|
||||
spaceCtrl *space.Controller,
|
||||
pipelineCtrl *pipeline.Controller,
|
||||
secretCtrl *secret.Controller,
|
||||
pullreqCtrl *pullreq.Controller,
|
||||
webhookCtrl *webhook.Controller,
|
||||
githookCtrl *controllergithook.Controller,
|
||||
@ -92,7 +101,7 @@ func NewAPIHandler(
|
||||
r.Use(middlewareauthn.Attempt(authenticator, authn.SourceRouterAPI))
|
||||
|
||||
r.Route("/v1", func(r chi.Router) {
|
||||
setupRoutesV1(r, repoCtrl, spaceCtrl, pullreqCtrl, webhookCtrl, githookCtrl,
|
||||
setupRoutesV1(r, repoCtrl, executionCtrl, pipelineCtrl, secretCtrl, spaceCtrl, pullreqCtrl, webhookCtrl, githookCtrl,
|
||||
saCtrl, userCtrl, principalCtrl, checkCtrl)
|
||||
})
|
||||
|
||||
@ -115,6 +124,9 @@ func corsHandler(config *types.Config) func(http.Handler) http.Handler {
|
||||
|
||||
func setupRoutesV1(r chi.Router,
|
||||
repoCtrl *repo.Controller,
|
||||
executionCtrl *execution.Controller,
|
||||
pipelineCtrl *pipeline.Controller,
|
||||
secretCtrl *secret.Controller,
|
||||
spaceCtrl *space.Controller,
|
||||
pullreqCtrl *pullreq.Controller,
|
||||
webhookCtrl *webhook.Controller,
|
||||
@ -126,6 +138,8 @@ func setupRoutesV1(r chi.Router,
|
||||
) {
|
||||
setupSpaces(r, spaceCtrl)
|
||||
setupRepos(r, repoCtrl, pullreqCtrl, webhookCtrl, checkCtrl)
|
||||
setupPipelines(r, pipelineCtrl, executionCtrl)
|
||||
setupSecrets(r, secretCtrl)
|
||||
setupUser(r, userCtrl)
|
||||
setupServiceAccounts(r, saCtrl)
|
||||
setupPrincipals(r, principalCtrl)
|
||||
@ -151,6 +165,8 @@ func setupSpaces(r chi.Router, spaceCtrl *space.Controller) {
|
||||
r.Get("/spaces", handlerspace.HandleListSpaces(spaceCtrl))
|
||||
r.Get("/repos", handlerspace.HandleListRepos(spaceCtrl))
|
||||
r.Get("/service-accounts", handlerspace.HandleListServiceAccounts(spaceCtrl))
|
||||
r.Get("/pipelines", handlerspace.HandleListPipelines(spaceCtrl))
|
||||
r.Get("/secrets", handlerspace.HandleListSecrets(spaceCtrl))
|
||||
|
||||
// Child collections
|
||||
r.Route("/paths", func(r chi.Router) {
|
||||
@ -268,6 +284,43 @@ func setupRepos(r chi.Router,
|
||||
})
|
||||
}
|
||||
|
||||
func setupPipelines(r chi.Router, pipelineCtrl *pipeline.Controller, executionCtrl *execution.Controller) {
|
||||
r.Route("/pipelines", func(r chi.Router) {
|
||||
// Create takes path and parentId via body, not uri
|
||||
r.Post("/", handlerpipeline.HandleCreate(pipelineCtrl))
|
||||
r.Route(fmt.Sprintf("/{%s}", request.PathParamPipelineRef), func(r chi.Router) {
|
||||
r.Get("/", handlerpipeline.HandleFind(pipelineCtrl))
|
||||
r.Patch("/", handlerpipeline.HandleUpdate(pipelineCtrl))
|
||||
r.Delete("/", handlerpipeline.HandleDelete(pipelineCtrl))
|
||||
setupExecutions(r, pipelineCtrl, executionCtrl)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func setupSecrets(r chi.Router, secretCtrl *secret.Controller) {
|
||||
r.Route("/secrets", func(r chi.Router) {
|
||||
// Create takes path and parentId via body, not uri
|
||||
r.Post("/", handlersecret.HandleCreate(secretCtrl))
|
||||
r.Route(fmt.Sprintf("/{%s}", request.PathParamSecretRef), func(r chi.Router) {
|
||||
r.Get("/", handlersecret.HandleFind(secretCtrl))
|
||||
r.Patch("/", handlersecret.HandleUpdate(secretCtrl))
|
||||
r.Delete("/", handlersecret.HandleDelete(secretCtrl))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func setupExecutions(r chi.Router, pipelineCtrl *pipeline.Controller, executionCtrl *execution.Controller) {
|
||||
r.Route("/executions", func(r chi.Router) {
|
||||
r.Get("/", handlerexecution.HandleList(executionCtrl))
|
||||
r.Post("/", handlerexecution.HandleCreate(executionCtrl))
|
||||
r.Route(fmt.Sprintf("/{%s}", request.PathParamExecutionNumber), func(r chi.Router) {
|
||||
r.Get("/", handlerexecution.HandleFind(executionCtrl))
|
||||
r.Patch("/", handlerexecution.HandleUpdate(executionCtrl))
|
||||
r.Delete("/", handlerexecution.HandleDelete(executionCtrl))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func setupInternal(r chi.Router, githookCtrl *controllergithook.Controller) {
|
||||
r.Route("/internal", func(r chi.Router) {
|
||||
SetupGitHooks(r, githookCtrl)
|
||||
|
@ -7,10 +7,13 @@ package router
|
||||
import (
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
"github.com/harness/gitness/internal/api/controller/check"
|
||||
"github.com/harness/gitness/internal/api/controller/execution"
|
||||
"github.com/harness/gitness/internal/api/controller/githook"
|
||||
"github.com/harness/gitness/internal/api/controller/pipeline"
|
||||
"github.com/harness/gitness/internal/api/controller/principal"
|
||||
"github.com/harness/gitness/internal/api/controller/pullreq"
|
||||
"github.com/harness/gitness/internal/api/controller/repo"
|
||||
"github.com/harness/gitness/internal/api/controller/secret"
|
||||
"github.com/harness/gitness/internal/api/controller/serviceaccount"
|
||||
"github.com/harness/gitness/internal/api/controller/space"
|
||||
"github.com/harness/gitness/internal/api/controller/user"
|
||||
@ -57,7 +60,10 @@ func ProvideAPIHandler(
|
||||
config *types.Config,
|
||||
authenticator authn.Authenticator,
|
||||
repoCtrl *repo.Controller,
|
||||
executionCtrl *execution.Controller,
|
||||
spaceCtrl *space.Controller,
|
||||
pipelineCtrl *pipeline.Controller,
|
||||
secretCtrl *secret.Controller,
|
||||
pullreqCtrl *pullreq.Controller,
|
||||
webhookCtrl *webhook.Controller,
|
||||
githookCtrl *githook.Controller,
|
||||
@ -66,8 +72,8 @@ func ProvideAPIHandler(
|
||||
principalCtrl principal.Controller,
|
||||
checkCtrl *check.Controller,
|
||||
) APIHandler {
|
||||
return NewAPIHandler(config, authenticator, repoCtrl, spaceCtrl, pullreqCtrl,
|
||||
webhookCtrl, githookCtrl, saCtrl, userCtrl, principalCtrl, checkCtrl)
|
||||
return NewAPIHandler(config, authenticator, repoCtrl, executionCtrl, spaceCtrl, pipelineCtrl, secretCtrl,
|
||||
pullreqCtrl, webhookCtrl, githookCtrl, saCtrl, userCtrl, principalCtrl, checkCtrl)
|
||||
}
|
||||
|
||||
func ProvideWebHandler(config *types.Config) WebHandler {
|
||||
|
@ -439,4 +439,90 @@ type (
|
||||
// Delete removes a required status checks for a repo.
|
||||
Delete(ctx context.Context, repoID, reqCheckID int64) error
|
||||
}
|
||||
PipelineStore interface {
|
||||
// Find returns a pipeline given a pipeline ID from the datastore.
|
||||
Find(ctx context.Context, id int64) (*types.Pipeline, error)
|
||||
|
||||
// FindByUID returns a pipeline with a given UID in a space
|
||||
FindByUID(ctx context.Context, id int64, uid string) (*types.Pipeline, error)
|
||||
|
||||
// Create creates a new pipeline in the datastore.
|
||||
Create(ctx context.Context, pipeline *types.Pipeline) error
|
||||
|
||||
// Update tries to update a pipeline in the datastore
|
||||
Update(ctx context.Context, pipeline *types.Pipeline) error
|
||||
|
||||
// List lists the pipelines present in a parent space ID in the datastore.
|
||||
List(ctx context.Context, spaceID int64, pagination types.ListQueryFilter) ([]*types.Pipeline, error)
|
||||
|
||||
// UpdateOptLock updates the pipeline using the optimistic locking mechanism.
|
||||
UpdateOptLock(ctx context.Context, pipeline *types.Pipeline,
|
||||
mutateFn func(pipeline *types.Pipeline) error) (*types.Pipeline, error)
|
||||
|
||||
// Delete deletes a pipeline ID from the datastore.
|
||||
Delete(ctx context.Context, id int64) error
|
||||
|
||||
// Count the number of pipelines in a space matching the given filter.
|
||||
Count(ctx context.Context, spaceID int64, filter types.ListQueryFilter) (int64, error)
|
||||
|
||||
// DeleteByUID deletes a pipeline with a given UID in a space
|
||||
DeleteByUID(ctx context.Context, spaceID int64, uid string) error
|
||||
|
||||
// IncrementSeqNum increments the sequence number of the pipeline
|
||||
IncrementSeqNum(ctx context.Context, pipeline *types.Pipeline) (*types.Pipeline, error)
|
||||
}
|
||||
|
||||
SecretStore interface {
|
||||
// Find returns a secret given an ID
|
||||
Find(ctx context.Context, id int64) (*types.Secret, error)
|
||||
|
||||
// FindByUID returns a secret given a space ID and a UID
|
||||
FindByUID(ctx context.Context, spaceID int64, uid string) (*types.Secret, error)
|
||||
|
||||
// Create creates a new secret
|
||||
Create(ctx context.Context, secret *types.Secret) error
|
||||
|
||||
// Count the number of secrets in a space matching the given filter.
|
||||
Count(ctx context.Context, spaceID int64, pagination types.ListQueryFilter) (int64, error)
|
||||
|
||||
// UpdateOptLock updates the secret using the optimistic locking mechanism.
|
||||
UpdateOptLock(ctx context.Context, secret *types.Secret,
|
||||
mutateFn func(secret *types.Secret) error) (*types.Secret, error)
|
||||
|
||||
// Update tries to update a secret.
|
||||
Update(ctx context.Context, secret *types.Secret) error
|
||||
|
||||
// Delete deletes a secret given an ID.
|
||||
Delete(ctx context.Context, id int64) error
|
||||
|
||||
// DeleteByUID deletes a secret given a space ID and a uid
|
||||
DeleteByUID(ctx context.Context, spaceID int64, uid string) error
|
||||
|
||||
// List lists the secrets in a given space
|
||||
List(ctx context.Context, spaceID int64, filter types.ListQueryFilter) ([]*types.Secret, error)
|
||||
}
|
||||
|
||||
ExecutionStore interface {
|
||||
// Find returns a execution given a pipeline and an execution number
|
||||
Find(ctx context.Context, pipelineID int64, num int64) (*types.Execution, error)
|
||||
|
||||
// Create creates a new execution in the datastore.
|
||||
Create(ctx context.Context, execution *types.Execution) error
|
||||
|
||||
// Update tries to update an execution.
|
||||
Update(ctx context.Context, execution *types.Execution) error
|
||||
|
||||
// UpdateOptLock updates the execution using the optimistic locking mechanism.
|
||||
UpdateOptLock(ctx context.Context, exectuion *types.Execution,
|
||||
mutateFn func(execution *types.Execution) error) (*types.Execution, error)
|
||||
|
||||
// List lists the executions for a given pipeline ID
|
||||
List(ctx context.Context, pipelineID int64, pagination types.Pagination) ([]*types.Execution, error)
|
||||
|
||||
// Delete deletes an execution given a pipeline ID and an execution number
|
||||
Delete(ctx context.Context, pipelineID int64, num int64) error
|
||||
|
||||
// Count the number of executions in a space
|
||||
Count(ctx context.Context, parentID int64) (int64, error)
|
||||
}
|
||||
)
|
||||
|
315
internal/store/database/execution.go
Normal file
315
internal/store/database/execution.go
Normal file
@ -0,0 +1,315 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/internal/store"
|
||||
gitness_store "github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/store/database"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var _ store.ExecutionStore = (*executionStore)(nil)
|
||||
|
||||
// NewExecutionStore returns a new ExecutionStore.
|
||||
func NewExecutionStore(db *sqlx.DB) *executionStore {
|
||||
return &executionStore{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
type executionStore struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
const (
|
||||
executionColumns = `
|
||||
execution_id
|
||||
,execution_pipeline_id
|
||||
,execution_repo_id
|
||||
,execution_trigger
|
||||
,execution_number
|
||||
,execution_parent
|
||||
,execution_status
|
||||
,execution_error
|
||||
,execution_event
|
||||
,execution_action
|
||||
,execution_link
|
||||
,execution_timestamp
|
||||
,execution_title
|
||||
,execution_message
|
||||
,execution_before
|
||||
,execution_after
|
||||
,execution_ref
|
||||
,execution_source_repo
|
||||
,execution_source
|
||||
,execution_target
|
||||
,execution_author
|
||||
,execution_author_name
|
||||
,execution_author_email
|
||||
,execution_author_avatar
|
||||
,execution_sender
|
||||
,execution_params
|
||||
,execution_cron
|
||||
,execution_deploy
|
||||
,execution_deploy_id
|
||||
,execution_debug
|
||||
,execution_started
|
||||
,execution_finished
|
||||
,execution_created
|
||||
,execution_updated
|
||||
,execution_version
|
||||
`
|
||||
)
|
||||
|
||||
// Find returns an execution given a pipeline ID and an execution number.
|
||||
func (s *executionStore) Find(ctx context.Context, pipelineID int64, executionNum int64) (*types.Execution, error) {
|
||||
const findQueryStmt = `
|
||||
SELECT` + executionColumns + `
|
||||
FROM executions
|
||||
WHERE execution_pipeline_id = $1 AND execution_number = $2`
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
dst := new(types.Execution)
|
||||
if err := db.GetContext(ctx, dst, findQueryStmt, pipelineID, executionNum); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(err, "Failed to find execution")
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// Create creates a new execution in the datastore.
|
||||
func (s *executionStore) Create(ctx context.Context, execution *types.Execution) error {
|
||||
const executionInsertStmt = `
|
||||
INSERT INTO executions (
|
||||
execution_pipeline_id
|
||||
,execution_repo_id
|
||||
,execution_trigger
|
||||
,execution_number
|
||||
,execution_parent
|
||||
,execution_status
|
||||
,execution_error
|
||||
,execution_event
|
||||
,execution_action
|
||||
,execution_link
|
||||
,execution_timestamp
|
||||
,execution_title
|
||||
,execution_message
|
||||
,execution_before
|
||||
,execution_after
|
||||
,execution_ref
|
||||
,execution_source_repo
|
||||
,execution_source
|
||||
,execution_target
|
||||
,execution_author
|
||||
,execution_author_name
|
||||
,execution_author_email
|
||||
,execution_author_avatar
|
||||
,execution_sender
|
||||
,execution_params
|
||||
,execution_cron
|
||||
,execution_deploy
|
||||
,execution_deploy_id
|
||||
,execution_debug
|
||||
,execution_started
|
||||
,execution_finished
|
||||
,execution_created
|
||||
,execution_updated
|
||||
,execution_version
|
||||
) VALUES (
|
||||
:execution_pipeline_id
|
||||
,:execution_repo_id
|
||||
,:execution_trigger
|
||||
,:execution_number
|
||||
,:execution_parent
|
||||
,:execution_status
|
||||
,:execution_error
|
||||
,:execution_event
|
||||
,:execution_action
|
||||
,:execution_link
|
||||
,:execution_timestamp
|
||||
,:execution_title
|
||||
,:execution_message
|
||||
,:execution_before
|
||||
,:execution_after
|
||||
,:execution_ref
|
||||
,:execution_source_repo
|
||||
,:execution_source
|
||||
,:execution_target
|
||||
,:execution_author
|
||||
,:execution_author_name
|
||||
,:execution_author_email
|
||||
,:execution_author_avatar
|
||||
,:execution_sender
|
||||
,:execution_params
|
||||
,:execution_cron
|
||||
,:execution_deploy
|
||||
,:execution_deploy_id
|
||||
,:execution_debug
|
||||
,:execution_started
|
||||
,:execution_finished
|
||||
,:execution_created
|
||||
,:execution_updated
|
||||
,:execution_version
|
||||
) RETURNING execution_id`
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
query, arg, err := db.BindNamed(executionInsertStmt, execution)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to bind execution object")
|
||||
}
|
||||
|
||||
if err = db.QueryRowContext(ctx, query, arg...).Scan(&execution.ID); err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Execution query failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update tries to update an execution in the datastore with optimistic locking.
|
||||
func (s *executionStore) Update(ctx context.Context, e *types.Execution) error {
|
||||
const executionUpdateStmt = `
|
||||
UPDATE executions
|
||||
SET
|
||||
,execution_status = :execution_status
|
||||
,execution_error = :execution_error
|
||||
,execution_event = :execution_event
|
||||
,execution_started = :execution_started
|
||||
,execution_finished = :execution_finished
|
||||
,execution_updated = :execution_updated
|
||||
,execution_version = :execution_version
|
||||
WHERE execution_id = :execution_id AND execution_version = :execution_version - 1`
|
||||
updatedAt := time.Now()
|
||||
|
||||
execution := *e
|
||||
|
||||
execution.Version++
|
||||
execution.Updated = updatedAt.UnixMilli()
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
query, arg, err := db.BindNamed(executionUpdateStmt, execution)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to bind execution object")
|
||||
}
|
||||
|
||||
result, err := db.ExecContext(ctx, query, arg...)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to update execution")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to get number of updated rows")
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return gitness_store.ErrVersionConflict
|
||||
}
|
||||
|
||||
e.Version = execution.Version
|
||||
e.Updated = execution.Updated
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateOptLock updates the pipeline using the optimistic locking mechanism.
|
||||
func (s *executionStore) UpdateOptLock(ctx context.Context,
|
||||
execution *types.Execution,
|
||||
mutateFn func(execution *types.Execution) error) (*types.Execution, error) {
|
||||
for {
|
||||
dup := *execution
|
||||
|
||||
err := mutateFn(&dup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.Update(ctx, &dup)
|
||||
if err == nil {
|
||||
return &dup, nil
|
||||
}
|
||||
if !errors.Is(err, gitness_store.ErrVersionConflict) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
execution, err = s.Find(ctx, execution.PipelineID, execution.Number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// List lists the executions for a given pipeline ID.
|
||||
func (s *executionStore) List(
|
||||
ctx context.Context,
|
||||
pipelineID int64,
|
||||
pagination types.Pagination,
|
||||
) ([]*types.Execution, error) {
|
||||
stmt := database.Builder.
|
||||
Select(executionColumns).
|
||||
From("executions").
|
||||
Where("execution_pipeline_id = ?", fmt.Sprint(pipelineID))
|
||||
|
||||
stmt = stmt.Limit(database.Limit(pagination.Size))
|
||||
stmt = stmt.Offset(database.Offset(pagination.Page, pagination.Size))
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
dst := []*types.Execution{}
|
||||
if err = db.SelectContext(ctx, &dst, sql, args...); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(err, "Failed executing custom list query")
|
||||
}
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// Count of executions in a space.
|
||||
func (s *executionStore) Count(ctx context.Context, pipelineID int64) (int64, error) {
|
||||
stmt := database.Builder.
|
||||
Select("count(*)").
|
||||
From("executions").
|
||||
Where("execution_pipeline_id = ?", pipelineID)
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "Failed to convert query to sql")
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
var count int64
|
||||
err = db.QueryRowContext(ctx, sql, args...).Scan(&count)
|
||||
if err != nil {
|
||||
return 0, database.ProcessSQLErrorf(err, "Failed executing count query")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// Delete deletes an execution given a pipeline ID and an execution number.
|
||||
func (s *executionStore) Delete(ctx context.Context, pipelineID int64, executionNum int64) error {
|
||||
const executionDeleteStmt = `
|
||||
DELETE FROM executions
|
||||
WHERE execution_pipeline_id = $1 AND execution_number = $2`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
if _, err := db.ExecContext(ctx, executionDeleteStmt, pipelineID, executionNum); err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Could not delete execution")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
103
internal/store/database/migrate/ci/ci_migrations.sql
Normal file
103
internal/store/database/migrate/ci/ci_migrations.sql
Normal file
@ -0,0 +1,103 @@
|
||||
CREATE TABLE IF NOT EXISTS pipelines (
|
||||
pipeline_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,pipeline_description TEXT NOT NULL
|
||||
,pipeline_space_id INTEGER NOT NULL
|
||||
,pipeline_uid TEXT NOT NULL
|
||||
,pipeline_seq INTEGER NOT NULL DEFAULT 0
|
||||
,pipeline_repo_id INTEGER
|
||||
,pipeline_repo_type TEXT NOT NULL
|
||||
,pipeline_repo_name TEXT
|
||||
,pipeline_default_branch TEXT
|
||||
,pipeline_config_path TEXT NOT NULL
|
||||
,pipeline_created INTEGER NOT NULL
|
||||
,pipeline_updated INTEGER NOT NULL
|
||||
,pipeline_version INTEGER NOT NULL
|
||||
|
||||
-- Ensure unique combination of UID and ParentID
|
||||
,UNIQUE (pipeline_space_id, pipeline_uid)
|
||||
|
||||
-- Foreign key to spaces table
|
||||
,CONSTRAINT fk_pipeline_space_id FOREIGN KEY (pipeline_space_id)
|
||||
REFERENCES spaces (space_id) MATCH SIMPLE
|
||||
ON UPDATE NO ACTION
|
||||
ON DELETE CASCADE
|
||||
|
||||
-- Foreign key to repositories table
|
||||
,CONSTRAINT fk_pipelines_repo_id FOREIGN KEY (pipeline_repo_id)
|
||||
REFERENCES repositories (repo_id) MATCH SIMPLE
|
||||
ON UPDATE NO ACTION
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS executions (
|
||||
execution_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,execution_pipeline_id INTEGER NOT NULL
|
||||
,execution_repo_id INTEGER
|
||||
,execution_trigger TEXT
|
||||
,execution_number INTEGER NOT NULL
|
||||
,execution_parent INTEGER
|
||||
,execution_status TEXT
|
||||
,execution_error TEXT
|
||||
,execution_event TEXT
|
||||
,execution_action TEXT
|
||||
,execution_link TEXT
|
||||
,execution_timestamp INTEGER
|
||||
,execution_title TEXT
|
||||
,execution_message TEXT
|
||||
,execution_before TEXT
|
||||
,execution_after TEXT
|
||||
,execution_ref TEXT
|
||||
,execution_source_repo TEXT
|
||||
,execution_source TEXT
|
||||
,execution_target TEXT
|
||||
,execution_author TEXT
|
||||
,execution_author_name TEXT
|
||||
,execution_author_email TEXT
|
||||
,execution_author_avatar TEXT
|
||||
,execution_sender TEXT
|
||||
,execution_params TEXT
|
||||
,execution_cron TEXT
|
||||
,execution_deploy TEXT
|
||||
,execution_deploy_id INTEGER
|
||||
,execution_debug BOOLEAN NOT NULL DEFAULT 0
|
||||
,execution_started INTEGER
|
||||
,execution_finished INTEGER
|
||||
,execution_created INTEGER NOT NULL
|
||||
,execution_updated INTEGER NOT NULL
|
||||
,execution_version INTEGER NOT NULL
|
||||
|
||||
-- Ensure unique combination of pipeline ID and number
|
||||
,UNIQUE (execution_pipeline_id, execution_number)
|
||||
|
||||
-- Foreign key to pipelines table
|
||||
,CONSTRAINT fk_executions_pipeline_id FOREIGN KEY (execution_pipeline_id)
|
||||
REFERENCES pipelines (pipeline_id) MATCH SIMPLE
|
||||
ON UPDATE NO ACTION
|
||||
ON DELETE CASCADE
|
||||
|
||||
-- Foreign key to repositories table
|
||||
,CONSTRAINT fk_executions_repo_id FOREIGN KEY (execution_repo_id)
|
||||
REFERENCES repositories (repo_id) MATCH SIMPLE
|
||||
ON UPDATE NO ACTION
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS secrets (
|
||||
secret_id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
,secret_uid TEXT NOT NULL
|
||||
,secret_space_id INTEGER NOT NULL
|
||||
,secret_description TEXT NOT NULL
|
||||
,secret_data BLOB NOT NULL
|
||||
,secret_created INTEGER NOT NULL
|
||||
,secret_updated INTEGER NOT NULL
|
||||
,secret_version INTEGER NOT NULL
|
||||
|
||||
-- Ensure unique combination of space ID and UID
|
||||
,UNIQUE (secret_space_id, secret_uid)
|
||||
|
||||
-- Foreign key to spaces table
|
||||
,CONSTRAINT fk_secrets_space_id FOREIGN KEY (secret_space_id)
|
||||
REFERENCES spaces (space_id) MATCH SIMPLE
|
||||
ON UPDATE NO ACTION
|
||||
ON DELETE CASCADE
|
||||
);
|
307
internal/store/database/pipeline.go
Normal file
307
internal/store/database/pipeline.go
Normal file
@ -0,0 +1,307 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/internal/store"
|
||||
gitness_store "github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/store/database"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var _ store.PipelineStore = (*pipelineStore)(nil)
|
||||
|
||||
const (
|
||||
pipelineQueryBase = `
|
||||
SELECT` +
|
||||
pipelineColumns + `
|
||||
FROM pipelines`
|
||||
|
||||
pipelineColumns = `
|
||||
pipeline_id
|
||||
,pipeline_description
|
||||
,pipeline_space_id
|
||||
,pipeline_uid
|
||||
,pipeline_seq
|
||||
,pipeline_repo_id
|
||||
,pipeline_repo_type
|
||||
,pipeline_repo_name
|
||||
,pipeline_default_branch
|
||||
,pipeline_config_path
|
||||
,pipeline_created
|
||||
,pipeline_updated
|
||||
,pipeline_version
|
||||
`
|
||||
)
|
||||
|
||||
// NewPipelineStore returns a new PipelineStore.
|
||||
func NewPipelineStore(db *sqlx.DB) *pipelineStore {
|
||||
return &pipelineStore{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
type pipelineStore struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
// Find returns a pipeline given a pipeline ID.
|
||||
func (s *pipelineStore) Find(ctx context.Context, id int64) (*types.Pipeline, error) {
|
||||
const findQueryStmt = pipelineQueryBase + `
|
||||
WHERE pipeline_id = $1`
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
dst := new(types.Pipeline)
|
||||
if err := db.GetContext(ctx, dst, findQueryStmt, id); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(err, "Failed to find pipeline")
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// FindByUID returns a pipeline in a given space with a given UID.
|
||||
func (s *pipelineStore) FindByUID(ctx context.Context, spaceID int64, uid string) (*types.Pipeline, error) {
|
||||
const findQueryStmt = pipelineQueryBase + `
|
||||
WHERE pipeline_space_id = $1 AND pipeline_uid = $2`
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
dst := new(types.Pipeline)
|
||||
if err := db.GetContext(ctx, dst, findQueryStmt, spaceID, uid); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(err, "Failed to find pipeline")
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// Create creates a pipeline.
|
||||
func (s *pipelineStore) Create(ctx context.Context, pipeline *types.Pipeline) error {
|
||||
const pipelineInsertStmt = `
|
||||
INSERT INTO pipelines (
|
||||
pipeline_description
|
||||
,pipeline_space_id
|
||||
,pipeline_uid
|
||||
,pipeline_seq
|
||||
,pipeline_repo_id
|
||||
,pipeline_repo_type
|
||||
,pipeline_repo_name
|
||||
,pipeline_default_branch
|
||||
,pipeline_config_path
|
||||
,pipeline_created
|
||||
,pipeline_updated
|
||||
,pipeline_version
|
||||
) VALUES (
|
||||
:pipeline_description,
|
||||
:pipeline_space_id,
|
||||
:pipeline_uid,
|
||||
:pipeline_seq,
|
||||
:pipeline_repo_id,
|
||||
:pipeline_repo_type,
|
||||
:pipeline_repo_name,
|
||||
:pipeline_default_branch,
|
||||
:pipeline_config_path,
|
||||
:pipeline_created,
|
||||
:pipeline_updated,
|
||||
:pipeline_version
|
||||
) RETURNING pipeline_id`
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
query, arg, err := db.BindNamed(pipelineInsertStmt, pipeline)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to bind pipeline object")
|
||||
}
|
||||
|
||||
if err = db.QueryRowContext(ctx, query, arg...).Scan(&pipeline.ID); err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Pipeline query failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update updates a pipeline.
|
||||
func (s *pipelineStore) Update(ctx context.Context, p *types.Pipeline) error {
|
||||
const pipelineUpdateStmt = `
|
||||
UPDATE pipelines
|
||||
SET
|
||||
pipeline_description = :pipeline_description,
|
||||
pipeline_uid = :pipeline_uid,
|
||||
pipeline_seq = :pipeline_seq,
|
||||
pipeline_default_branch = :pipeline_default_branch,
|
||||
pipeline_config_path = :pipeline_config_path,
|
||||
pipeline_updated = :pipeline_updated,
|
||||
pipeline_version = :pipeline_version
|
||||
WHERE pipeline_id = :pipeline_id AND pipeline_version = :pipeline_version - 1`
|
||||
updatedAt := time.Now()
|
||||
pipeline := *p
|
||||
|
||||
pipeline.Version++
|
||||
pipeline.Updated = updatedAt.UnixMilli()
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
query, arg, err := db.BindNamed(pipelineUpdateStmt, pipeline)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to bind pipeline object")
|
||||
}
|
||||
|
||||
result, err := db.ExecContext(ctx, query, arg...)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to update pipeline")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to get number of updated rows")
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return gitness_store.ErrVersionConflict
|
||||
}
|
||||
|
||||
p.Updated = pipeline.Updated
|
||||
p.Version = pipeline.Version
|
||||
return nil
|
||||
}
|
||||
|
||||
// List lists all the pipelines present in a space.
|
||||
func (s *pipelineStore) List(
|
||||
ctx context.Context,
|
||||
parentID int64,
|
||||
filter types.ListQueryFilter,
|
||||
) ([]*types.Pipeline, error) {
|
||||
stmt := database.Builder.
|
||||
Select(pipelineColumns).
|
||||
From("pipelines").
|
||||
Where("pipeline_space_id = ?", fmt.Sprint(parentID))
|
||||
|
||||
if filter.Query != "" {
|
||||
stmt = stmt.Where("LOWER(pipeline_uid) LIKE ?", fmt.Sprintf("%%%s%%", strings.ToLower(filter.Query)))
|
||||
}
|
||||
|
||||
stmt = stmt.Limit(database.Limit(filter.Size))
|
||||
stmt = stmt.Offset(database.Offset(filter.Page, filter.Size))
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
dst := []*types.Pipeline{}
|
||||
if err = db.SelectContext(ctx, &dst, sql, args...); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(err, "Failed executing custom list query")
|
||||
}
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// UpdateOptLock updates the pipeline using the optimistic locking mechanism.
|
||||
func (s *pipelineStore) UpdateOptLock(ctx context.Context,
|
||||
pipeline *types.Pipeline,
|
||||
mutateFn func(pipeline *types.Pipeline) error) (*types.Pipeline, error) {
|
||||
for {
|
||||
dup := *pipeline
|
||||
|
||||
err := mutateFn(&dup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.Update(ctx, &dup)
|
||||
if err == nil {
|
||||
return &dup, nil
|
||||
}
|
||||
if !errors.Is(err, gitness_store.ErrVersionConflict) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pipeline, err = s.Find(ctx, pipeline.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Count of pipelines in a space.
|
||||
func (s *pipelineStore) Count(ctx context.Context, parentID int64, filter types.ListQueryFilter) (int64, error) {
|
||||
stmt := database.Builder.
|
||||
Select("count(*)").
|
||||
From("pipelines").
|
||||
Where("pipeline_space_id = ?", parentID)
|
||||
|
||||
if filter.Query != "" {
|
||||
stmt = stmt.Where("pipeline_uid LIKE ?", fmt.Sprintf("%%%s%%", filter.Query))
|
||||
}
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "Failed to convert query to sql")
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
var count int64
|
||||
err = db.QueryRowContext(ctx, sql, args...).Scan(&count)
|
||||
if err != nil {
|
||||
return 0, database.ProcessSQLErrorf(err, "Failed executing count query")
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// Delete deletes a pipeline given a pipeline ID.
|
||||
func (s *pipelineStore) Delete(ctx context.Context, id int64) error {
|
||||
const pipelineDeleteStmt = `
|
||||
DELETE FROM pipelines
|
||||
WHERE pipeline_id = $1`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
if _, err := db.ExecContext(ctx, pipelineDeleteStmt, id); err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Could not delete pipeline")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteByUID deletes a pipeline with a given UID in a space.
|
||||
func (s *pipelineStore) DeleteByUID(ctx context.Context, spaceID int64, uid string) error {
|
||||
const pipelineDeleteStmt = `
|
||||
DELETE FROM pipelines
|
||||
WHERE pipeline_space_id = $1 AND pipeline_uid = $2`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
if _, err := db.ExecContext(ctx, pipelineDeleteStmt, spaceID, uid); err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Could not delete pipeline")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Increment increments the pipeline sequence number. It will keep retrying in case
|
||||
// of optimistic lock errors.
|
||||
func (s *pipelineStore) IncrementSeqNum(ctx context.Context, pipeline *types.Pipeline) (*types.Pipeline, error) {
|
||||
for {
|
||||
var err error
|
||||
pipeline.Seq++
|
||||
err = s.Update(ctx, pipeline)
|
||||
if err == nil {
|
||||
return pipeline, nil
|
||||
} else if !errors.Is(err, gitness_store.ErrVersionConflict) {
|
||||
return pipeline, errors.Wrap(err, "could not increment pipeline sequence number")
|
||||
}
|
||||
pipeline, err = s.Find(ctx, pipeline.ID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not increment pipeline sequence number")
|
||||
}
|
||||
}
|
||||
}
|
266
internal/store/database/secret.go
Normal file
266
internal/store/database/secret.go
Normal file
@ -0,0 +1,266 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/internal/store"
|
||||
gitness_store "github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/store/database"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var _ store.SecretStore = (*secretStore)(nil)
|
||||
|
||||
const (
|
||||
secretQueryBase = `
|
||||
SELECT` + secretColumns + `
|
||||
FROM secrets`
|
||||
|
||||
secretColumns = `
|
||||
secret_id,
|
||||
secret_description,
|
||||
secret_space_id,
|
||||
secret_uid,
|
||||
secret_data,
|
||||
secret_created,
|
||||
secret_updated,
|
||||
secret_version
|
||||
`
|
||||
)
|
||||
|
||||
// NewSecretStore returns a new SecretStore.
|
||||
func NewSecretStore(db *sqlx.DB) *secretStore {
|
||||
return &secretStore{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
type secretStore struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
// Find returns a secret given a secret ID.
|
||||
func (s *secretStore) Find(ctx context.Context, id int64) (*types.Secret, error) {
|
||||
const findQueryStmt = secretQueryBase + `
|
||||
WHERE secret_id = $1`
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
dst := new(types.Secret)
|
||||
if err := db.GetContext(ctx, dst, findQueryStmt, id); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(err, "Failed to find secret")
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// FindByUID returns a secret in a given space with a given UID.
|
||||
func (s *secretStore) FindByUID(ctx context.Context, spaceID int64, uid string) (*types.Secret, error) {
|
||||
const findQueryStmt = secretQueryBase + `
|
||||
WHERE secret_space_id = $1 AND secret_uid = $2`
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
dst := new(types.Secret)
|
||||
if err := db.GetContext(ctx, dst, findQueryStmt, spaceID, uid); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(err, "Failed to find secret")
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// Create creates a secret.
|
||||
func (s *secretStore) Create(ctx context.Context, secret *types.Secret) error {
|
||||
const secretInsertStmt = `
|
||||
INSERT INTO secrets (
|
||||
secret_description,
|
||||
secret_space_id,
|
||||
secret_uid,
|
||||
secret_data,
|
||||
secret_created,
|
||||
secret_updated,
|
||||
secret_version
|
||||
) VALUES (
|
||||
:secret_description,
|
||||
:secret_space_id,
|
||||
:secret_uid,
|
||||
:secret_data,
|
||||
:secret_created,
|
||||
:secret_updated,
|
||||
:secret_version
|
||||
) RETURNING secret_id`
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
query, arg, err := db.BindNamed(secretInsertStmt, secret)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to bind secret object")
|
||||
}
|
||||
|
||||
if err = db.QueryRowContext(ctx, query, arg...).Scan(&secret.ID); err != nil {
|
||||
return database.ProcessSQLErrorf(err, "secret query failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *secretStore) Update(ctx context.Context, p *types.Secret) error {
|
||||
const secretUpdateStmt = `
|
||||
UPDATE secrets
|
||||
SET
|
||||
secret_description = :secret_description,
|
||||
secret_uid = :secret_uid,
|
||||
secret_data = :secret_data,
|
||||
secret_updated = :secret_updated,
|
||||
secret_version = :secret_version
|
||||
WHERE secret_id = :secret_id AND secret_version = :secret_version - 1`
|
||||
updatedAt := time.Now()
|
||||
secret := *p
|
||||
|
||||
secret.Version++
|
||||
secret.Updated = updatedAt.UnixMilli()
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
query, arg, err := db.BindNamed(secretUpdateStmt, secret)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to bind secret object")
|
||||
}
|
||||
|
||||
result, err := db.ExecContext(ctx, query, arg...)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to update secret")
|
||||
}
|
||||
|
||||
count, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Failed to get number of updated rows")
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return gitness_store.ErrVersionConflict
|
||||
}
|
||||
|
||||
p.Version = secret.Version
|
||||
p.Updated = secret.Updated
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateOptLock updates the pipeline using the optimistic locking mechanism.
|
||||
func (s *secretStore) UpdateOptLock(ctx context.Context,
|
||||
secret *types.Secret,
|
||||
mutateFn func(secret *types.Secret) error,
|
||||
) (*types.Secret, error) {
|
||||
for {
|
||||
dup := *secret
|
||||
|
||||
err := mutateFn(&dup)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.Update(ctx, &dup)
|
||||
if err == nil {
|
||||
return &dup, nil
|
||||
}
|
||||
if !errors.Is(err, gitness_store.ErrVersionConflict) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secret, err = s.Find(ctx, secret.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// List lists all the secrets present in a space.
|
||||
func (s *secretStore) List(ctx context.Context, parentID int64, filter types.ListQueryFilter) ([]*types.Secret, error) {
|
||||
stmt := database.Builder.
|
||||
Select(secretColumns).
|
||||
From("secrets").
|
||||
Where("secret_space_id = ?", fmt.Sprint(parentID))
|
||||
|
||||
if filter.Query != "" {
|
||||
stmt = stmt.Where("LOWER(secret_uid) LIKE ?", fmt.Sprintf("%%%s%%", strings.ToLower(filter.Query)))
|
||||
}
|
||||
|
||||
stmt = stmt.Limit(database.Limit(filter.Size))
|
||||
stmt = stmt.Offset(database.Offset(filter.Page, filter.Size))
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
dst := []*types.Secret{}
|
||||
if err = db.SelectContext(ctx, &dst, sql, args...); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(err, "Failed executing custom list query")
|
||||
}
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// Delete deletes a secret given a secret ID.
|
||||
func (s *secretStore) Delete(ctx context.Context, id int64) error {
|
||||
const secretDeleteStmt = `
|
||||
DELETE FROM secrets
|
||||
WHERE secret_id = $1`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
if _, err := db.ExecContext(ctx, secretDeleteStmt, id); err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Could not delete secret")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteByUID deletes a secret with a given UID in a space.
|
||||
func (s *secretStore) DeleteByUID(ctx context.Context, spaceID int64, uid string) error {
|
||||
const secretDeleteStmt = `
|
||||
DELETE FROM secrets
|
||||
WHERE secret_space_id = $1 AND secret_uid = $2`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
if _, err := db.ExecContext(ctx, secretDeleteStmt, spaceID, uid); err != nil {
|
||||
return database.ProcessSQLErrorf(err, "Could not delete secret")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Count of secrets in a space.
|
||||
func (s *secretStore) Count(ctx context.Context, parentID int64, filter types.ListQueryFilter) (int64, error) {
|
||||
stmt := database.Builder.
|
||||
Select("count(*)").
|
||||
From("secrets").
|
||||
Where("secret_space_id = ?", parentID)
|
||||
|
||||
if filter.Query != "" {
|
||||
stmt = stmt.Where("secret_uid LIKE ?", fmt.Sprintf("%%%s%%", filter.Query))
|
||||
}
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "Failed to convert query to sql")
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, s.db)
|
||||
|
||||
var count int64
|
||||
err = db.QueryRowContext(ctx, sql, args...).Scan(&count)
|
||||
if err != nil {
|
||||
return 0, database.ProcessSQLErrorf(err, "Failed executing count query")
|
||||
}
|
||||
return count, nil
|
||||
}
|
@ -23,6 +23,9 @@ var WireSet = wire.NewSet(
|
||||
ProvidePathStore,
|
||||
ProvideSpaceStore,
|
||||
ProvideRepoStore,
|
||||
ProvideExecutionStore,
|
||||
ProvidePipelineStore,
|
||||
ProvideSecretStore,
|
||||
ProvideRepoGitInfoView,
|
||||
ProvideMembershipStore,
|
||||
ProvideTokenStore,
|
||||
@ -78,6 +81,21 @@ func ProvideRepoStore(db *sqlx.DB, pathCache store.PathCache) store.RepoStore {
|
||||
return NewRepoStore(db, pathCache)
|
||||
}
|
||||
|
||||
// ProvidePipelineStore provides a pipeline store.
|
||||
func ProvidePipelineStore(db *sqlx.DB) store.PipelineStore {
|
||||
return NewPipelineStore(db)
|
||||
}
|
||||
|
||||
// ProvideSecretStore provides a secret store.
|
||||
func ProvideSecretStore(db *sqlx.DB) store.SecretStore {
|
||||
return NewSecretStore(db)
|
||||
}
|
||||
|
||||
// ProvideExecutionStore provides an execution store.
|
||||
func ProvideExecutionStore(db *sqlx.DB) store.ExecutionStore {
|
||||
return NewExecutionStore(db)
|
||||
}
|
||||
|
||||
// ProvideRepoGitInfoView provides a repo git UID view.
|
||||
func ProvideRepoGitInfoView(db *sqlx.DB) store.RepoGitInfoView {
|
||||
return NewRepoGitInfoView(db)
|
||||
|
@ -8,9 +8,10 @@ import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
user "github.com/harness/gitness/internal/api/controller/user"
|
||||
types "github.com/harness/gitness/types"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockClient is a mock of Client interface.
|
||||
|
@ -8,9 +8,10 @@ import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
types "github.com/harness/gitness/types"
|
||||
enum "github.com/harness/gitness/types/enum"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockPrincipalStore is a mock of PrincipalStore interface.
|
||||
|
@ -52,6 +52,12 @@ type Config struct {
|
||||
DefaultBranch string `envconfig:"GITNESS_GIT_DEFAULTBRANCH" default:"main"`
|
||||
}
|
||||
|
||||
// Encrypter defines the parameters for the encrypter
|
||||
Encrypter struct {
|
||||
Secret string `envconfig:"GITNESS_ENCRYPTER_SECRET"` // key used for encryption
|
||||
MixedContent bool `envconfig:"GITNESS_ENCRYPTER_MIXED_CONTENT"`
|
||||
}
|
||||
|
||||
// Server defines the server configuration parameters.
|
||||
Server struct {
|
||||
// HTTP defines the http configuration parameters
|
||||
|
@ -24,10 +24,14 @@ var membershipRoleReaderPermissions = slices.Clip(slices.Insert([]Permission{},
|
||||
PermissionRepoView,
|
||||
PermissionSpaceView,
|
||||
PermissionServiceAccountView,
|
||||
PermissionPipelineView,
|
||||
PermissionSecretView,
|
||||
))
|
||||
|
||||
var membershipRoleExecutorPermissions = slices.Clip(slices.Insert(membershipRoleReaderPermissions, 0,
|
||||
PermissionCommitCheckReport,
|
||||
PermissionPipelineExecute,
|
||||
PermissionSecretAccess,
|
||||
))
|
||||
|
||||
var membershipRoleContributorPermissions = slices.Clip(slices.Insert(membershipRoleReaderPermissions, 0,
|
||||
@ -47,6 +51,16 @@ var membershipRoleSpaceOwnerPermissions = slices.Clip(slices.Insert(membershipRo
|
||||
PermissionServiceAccountCreate,
|
||||
PermissionServiceAccountEdit,
|
||||
PermissionServiceAccountDelete,
|
||||
|
||||
PermissionPipelineEdit,
|
||||
PermissionPipelineExecute,
|
||||
PermissionPipelineDelete,
|
||||
PermissionPipelineView,
|
||||
|
||||
PermissionSecretAccess,
|
||||
PermissionSecretDelete,
|
||||
PermissionSecretEdit,
|
||||
PermissionSecretView,
|
||||
))
|
||||
|
||||
func init() {
|
||||
|
@ -13,6 +13,8 @@ const (
|
||||
ResourceTypeUser ResourceType = "USER"
|
||||
ResourceTypeServiceAccount ResourceType = "SERVICEACCOUNT"
|
||||
ResourceTypeService ResourceType = "SERVICE"
|
||||
ResourceTypePipeline ResourceType = "PIPELINE"
|
||||
ResourceTypeSecret ResourceType = "SECRET"
|
||||
// ResourceType_Branch ResourceType = "BRANCH"
|
||||
)
|
||||
|
||||
@ -71,6 +73,26 @@ const (
|
||||
PermissionServiceEditAdmin Permission = "service_editAdmin"
|
||||
)
|
||||
|
||||
const (
|
||||
/*
|
||||
----- PIPELINE -----
|
||||
*/
|
||||
PermissionPipelineView Permission = "pipeline_view"
|
||||
PermissionPipelineEdit Permission = "pipeline_edit"
|
||||
PermissionPipelineDelete Permission = "pipeline_delete"
|
||||
PermissionPipelineExecute Permission = "pipeline_execute"
|
||||
)
|
||||
|
||||
const (
|
||||
/*
|
||||
----- SECRET -----
|
||||
*/
|
||||
PermissionSecretView Permission = "secret_view"
|
||||
PermissionSecretEdit Permission = "secret_edit"
|
||||
PermissionSecretDelete Permission = "secret_delete"
|
||||
PermissionSecretAccess Permission = "secret_access"
|
||||
)
|
||||
|
||||
const (
|
||||
/*
|
||||
----- COMMIT CHECK -----
|
||||
|
24
types/enum/scm.go
Normal file
24
types/enum/scm.go
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package enum
|
||||
|
||||
// ScmType defines the different SCM types supported for CI.
|
||||
type ScmType string
|
||||
|
||||
func (ScmType) Enum() []interface{} { return toInterfaceSlice(scmTypes) }
|
||||
|
||||
var scmTypes = ([]ScmType{
|
||||
ScmTypeGitness,
|
||||
ScmTypeGithub,
|
||||
ScmTypeGitlab,
|
||||
ScmTypeUnknown,
|
||||
})
|
||||
|
||||
const (
|
||||
ScmTypeUnknown ScmType = "UNKNOWN"
|
||||
ScmTypeGitness ScmType = "GITNESS"
|
||||
ScmTypeGithub ScmType = "GITHUB"
|
||||
ScmTypeGitlab ScmType = "GITLAB"
|
||||
)
|
46
types/execution.go
Normal file
46
types/execution.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package types
|
||||
|
||||
// Execution represents an instance of a pipeline execution.
|
||||
type Execution struct {
|
||||
ID int64 `db:"execution_id" json:"id"`
|
||||
PipelineID int64 `db:"execution_pipeline_id" json:"pipeline_id"`
|
||||
RepoID int64 `db:"execution_repo_id" json:"repo_id"`
|
||||
Trigger string `db:"execution_trigger" json:"trigger"`
|
||||
Number int64 `db:"execution_number" json:"number"`
|
||||
Parent int64 `db:"execution_parent" json:"parent,omitempty"`
|
||||
Status string `db:"execution_status" json:"status"`
|
||||
Error string `db:"execution_error" json:"error,omitempty"`
|
||||
Event string `db:"execution_event" json:"event"`
|
||||
Action string `db:"execution_action" json:"action"`
|
||||
Link string `db:"execution_link" json:"link"`
|
||||
Timestamp int64 `db:"execution_timestamp" json:"timestamp"`
|
||||
Title string `db:"execution_title" json:"title,omitempty"`
|
||||
Message string `db:"execution_message" json:"message"`
|
||||
Before string `db:"execution_before" json:"before"`
|
||||
After string `db:"execution_after" json:"after"`
|
||||
Ref string `db:"execution_ref" json:"ref"`
|
||||
Fork string `db:"execution_source_repo" json:"source_repo"`
|
||||
Source string `db:"execution_source" json:"source"`
|
||||
Target string `db:"execution_target" json:"target"`
|
||||
Author string `db:"execution_author" json:"author_login"`
|
||||
AuthorName string `db:"execution_author_name" json:"author_name"`
|
||||
AuthorEmail string `db:"execution_author_email" json:"author_email"`
|
||||
AuthorAvatar string `db:"execution_author_avatar" json:"author_avatar"`
|
||||
Sender string `db:"execution_sender" json:"sender"`
|
||||
Params string `db:"execution_params" json:"params,omitempty"`
|
||||
Cron string `db:"execution_cron" json:"cron,omitempty"`
|
||||
Deploy string `db:"execution_deploy" json:"deploy_to,omitempty"`
|
||||
DeployID int64 `db:"execution_deploy_id" json:"deploy_id,omitempty"`
|
||||
Debug bool `db:"execution_debug" json:"debug,omitempty"`
|
||||
Started int64 `db:"execution_started" json:"started"`
|
||||
Finished int64 `db:"execution_finished" json:"finished"`
|
||||
Created int64 `db:"execution_created" json:"created"`
|
||||
Updated int64 `db:"execution_updated" json:"updated"`
|
||||
Version int64 `db:"execution_version" json:"version"`
|
||||
// TODO: (Vistaar) Add stages
|
||||
// Stages []*Stage `db:"-" json:"stages,omitempty"`
|
||||
}
|
7
types/list_filters.go
Normal file
7
types/list_filters.go
Normal file
@ -0,0 +1,7 @@
|
||||
package types
|
||||
|
||||
// ListQueryFilter has pagination related info and a query param
|
||||
type ListQueryFilter struct {
|
||||
Pagination
|
||||
Query string `json:"query"`
|
||||
}
|
7
types/pagination.go
Normal file
7
types/pagination.go
Normal file
@ -0,0 +1,7 @@
|
||||
package types
|
||||
|
||||
// Pagination stores pagination related params
|
||||
type Pagination struct {
|
||||
Page int `json:"page"`
|
||||
Size int `json:"size"`
|
||||
}
|
23
types/pipeline.go
Normal file
23
types/pipeline.go
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2022 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package types
|
||||
|
||||
import "github.com/harness/gitness/types/enum"
|
||||
|
||||
type Pipeline struct {
|
||||
ID int64 `db:"pipeline_id" json:"id"`
|
||||
Description string `db:"pipeline_description" json:"description"`
|
||||
SpaceID int64 `db:"pipeline_space_id" json:"space_id"`
|
||||
UID string `db:"pipeline_uid" json:"uid"`
|
||||
Seq int64 `db:"pipeline_seq" json:"seq"` // last execution number for this pipeline
|
||||
RepoID int64 `db:"pipeline_repo_id" json:"repo_id"` // null if repo_type != gitness
|
||||
RepoType enum.ScmType `db:"pipeline_repo_type" json:"repo_type"`
|
||||
RepoName string `db:"pipeline_repo_name" json:"repo_name"`
|
||||
DefaultBranch string `db:"pipeline_default_branch" json:"default_branch"`
|
||||
ConfigPath string `db:"pipeline_config_path" json:"config_path"`
|
||||
Created int64 `db:"pipeline_created" json:"created"`
|
||||
Updated int64 `db:"pipeline_updated" json:"updated"`
|
||||
Version int64 `db:"pipeline_version" json:"version"`
|
||||
}
|
29
types/secret.go
Normal file
29
types/secret.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2023 Harness Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Polyform Free Trial License
|
||||
// that can be found in the LICENSE.md file for this repository.
|
||||
|
||||
package types
|
||||
|
||||
type Secret struct {
|
||||
ID int64 `db:"secret_id" json:"id"`
|
||||
Description string `db:"secret_description" json:"description"`
|
||||
SpaceID int64 `db:"secret_space_id" json:"space_id"`
|
||||
UID string `db:"secret_uid" json:"uid"`
|
||||
Data string `db:"secret_data" json:"-"`
|
||||
Created int64 `db:"secret_created" json:"created"`
|
||||
Updated int64 `db:"secret_updated" json:"updated"`
|
||||
Version int64 `db:"secret_version" json:"version"`
|
||||
}
|
||||
|
||||
// Copy makes a copy of the secret without the value.
|
||||
func (s *Secret) CopyWithoutData() *Secret {
|
||||
return &Secret{
|
||||
ID: s.ID,
|
||||
Description: s.Description,
|
||||
UID: s.UID,
|
||||
SpaceID: s.SpaceID,
|
||||
Created: s.Created,
|
||||
Updated: s.Updated,
|
||||
Version: s.Version,
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user