From 1f2db83d1694768ece52ffa43520c2273b6c790e Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Mon, 14 Aug 2023 23:16:38 +0200 Subject: [PATCH 01/14] feat: values service basic structure --- momentum-core/main.go | 4 +- momentum-core/models/keyvalue.go | 57 +++++++++++-- momentum-core/routers/application-router.go | 4 +- momentum-core/routers/value-router.go | 40 ++++++++- momentum-core/services/keyvalue-service.go | 10 --- momentum-core/services/tree-service.go | 18 ++++ momentum-core/services/value-service.go | 92 +++++++++++++++++++++ momentum-core/tree/momentum-tree.go | 46 +++++++++++ 8 files changed, 247 insertions(+), 24 deletions(-) delete mode 100644 momentum-core/services/keyvalue-service.go create mode 100644 momentum-core/services/value-service.go diff --git a/momentum-core/main.go b/momentum-core/main.go index 8d976ec..4c31b0c 100644 --- a/momentum-core/main.go +++ b/momentum-core/main.go @@ -38,10 +38,10 @@ func main() { applicationService := services.NewApplicationService(config, treeService, templateService) stageService := services.NewStageService(config, treeService, templateService) deploymentService := services.NewDeploymentService(config, stageService, templateService, treeService) - // valueService := services.NewValueService() + valueService := services.NewValueService(treeService) templateRouter := routers.NewTemplateRouter() - valueRouter := routers.NewValueRouter() + valueRouter := routers.NewValueRouter(valueService) deploymentRouter := routers.NewDeploymentRouter(deploymentService) stageRouter := routers.NewStageRouter(stageService) applicationRouter := routers.NewApplicationRouter(applicationService) diff --git a/momentum-core/models/keyvalue.go b/momentum-core/models/keyvalue.go index 0c9e8fa..fbdfa34 100644 --- a/momentum-core/models/keyvalue.go +++ b/momentum-core/models/keyvalue.go @@ -1,6 +1,7 @@ package models import ( + "errors" "momentum-core/clients" "momentum-core/tree" "momentum-core/utils" @@ -8,6 +9,15 @@ import ( "github.com/gin-gonic/gin" ) +type ValueType int + +const ( + REPOSITORY ValueType = iota + APPLICATION + STAGE + DEPLOYMENT +) + type KeyValueCreateRequest struct { Key string `json:"key"` Value string `json:"value"` @@ -17,7 +27,7 @@ type KeyValueCreateRequest struct { ParentKeyValueId string `json:"parentKeyValueId"` } -type KeyValue struct { +type Value struct { Id string `json:"id"` Key string `json:"key"` Value string `json:"value"` @@ -27,17 +37,48 @@ type KeyValue struct { ParentDeploymentId string `json:"parentDeploymentId"` } +type ValueWrapper struct { + FileId string `json:"parentFileId"` + FileName string `json:"parentFileName"` + ValueType ValueType `json:"valueType"` + Values []*Value `json:"values"` +} + func ExtractKeyValueCreateRequest(c *gin.Context) (*KeyValueCreateRequest, error) { return utils.Extract[KeyValueCreateRequest](c) } -func ExtractKeyValue(c *gin.Context) (*KeyValue, error) { - return utils.Extract[KeyValue](c) +func ExtractKeyValue(c *gin.Context) (*Value, error) { + return utils.Extract[Value](c) +} + +func ToValueWrapperFromNode(n *tree.Node, valType ValueType) (*ValueWrapper, error) { + + if n.Kind != tree.File { + return nil, errors.New("only files can be converted to a value wrapper") + } + + valueWrapper := new(ValueWrapper) + + valueWrapper.FileId = n.Id + valueWrapper.FileName = n.NormalizedPath() + mappedValues := make([]*Value, 0) + for _, v := range n.Values() { + value, err := ToValueFromNode(v) + if err != nil { + return nil, errors.New("unable to map value from node") + } + mappedValues = append(mappedValues, value) + } + valueWrapper.Values = mappedValues + valueWrapper.ValueType = valType + + return valueWrapper, nil } -func ToKeyValueFromNode(n *tree.Node) (*KeyValue, error) { +func ToValueFromNode(n *tree.Node) (*Value, error) { - keyValue := new(KeyValue) + keyValue := new(Value) keyValue.Id = n.Id keyValue.Key = n.FullPath() @@ -57,16 +98,16 @@ func ToKeyValueFromNode(n *tree.Node) (*KeyValue, error) { return keyValue, nil } -func ToKeyValue(data []byte) (*KeyValue, error) { +func ToKeyValue(data []byte) (*Value, error) { - keyValue, err := clients.UnmarshallJson[KeyValue](data) + keyValue, err := clients.UnmarshallJson[Value](data) if err != nil { return nil, err } return keyValue, nil } -func (kv *KeyValue) ToJson() ([]byte, error) { +func (kv *Value) ToJson() ([]byte, error) { data, err := clients.MarshallJson(kv) if err != nil { diff --git a/momentum-core/routers/application-router.go b/momentum-core/routers/application-router.go index f2f2541..5aaf197 100644 --- a/momentum-core/routers/application-router.go +++ b/momentum-core/routers/application-router.go @@ -31,7 +31,7 @@ func (a *ApplicationRouter) RegisterApplicationRoutes(server *gin.Engine) { server.POST(ROUTING_PATH_APPLICATION, a.addApplication) } -// GetApplication godoc +// getApplication godoc // // @Summary get an application of a repository by id // @Tags applications @@ -77,7 +77,7 @@ func (a *ApplicationRouter) getApplication(c *gin.Context) { c.JSON(http.StatusOK, result) } -// AddApplication godoc +// addApplication godoc // // @Summary add an application // @Tags applications diff --git a/momentum-core/routers/value-router.go b/momentum-core/routers/value-router.go index 4c444ca..c941c2f 100644 --- a/momentum-core/routers/value-router.go +++ b/momentum-core/routers/value-router.go @@ -1,7 +1,43 @@ package routers -type ValueRouter struct{} +import ( + "momentum-core/config" + "momentum-core/models" + "momentum-core/services" + "net/http" -func NewValueRouter() *ValueRouter { + "github.com/gin-gonic/gin" +) + +const ROUTING_PATH_VALUE_BY_ID = VERSION + "/repository/:repositoryName/:valueId" +const ROUTING_PATH_VALUE = VERSION + "/value" + +type ValueRouter struct { + valueService *services.ValueService +} + +func NewValueRouter(valueService *services.ValueService) *ValueRouter { return new(ValueRouter) } + +func (vr *ValueRouter) RegisterValueRoutes(server *gin.Engine) { + + server.GET(ROUTING_PATH_VALUE_BY_ID, vr.valueById) +} + +func (vr *ValueRouter) valueById(c *gin.Context) { + + traceId := config.LOGGER.TraceId() + + repoName := c.Param("repositoryName") + valueId := c.Param("valueId") + + result, err := vr.valueService.ValueById(repoName, valueId, traceId) + if err != nil { + c.JSON(http.StatusNotFound, models.NewApiError(err, http.StatusNotFound, c, traceId)) + config.LOGGER.LogError(err.Error(), err, traceId) + return + } + + c.JSON(http.StatusOK, result) +} diff --git a/momentum-core/services/keyvalue-service.go b/momentum-core/services/keyvalue-service.go deleted file mode 100644 index 2d3b435..0000000 --- a/momentum-core/services/keyvalue-service.go +++ /dev/null @@ -1,10 +0,0 @@ -package services - -type ValueService struct{} - -func NewValueService() *ValueService { - - valueService := new(ValueService) - - return valueService -} diff --git a/momentum-core/services/tree-service.go b/momentum-core/services/tree-service.go index ad8caf4..be8a0f2 100644 --- a/momentum-core/services/tree-service.go +++ b/momentum-core/services/tree-service.go @@ -79,6 +79,24 @@ func (ts *TreeService) deployment(repositoryName string, deploymentId string, tr return nil, errors.New("no deployment with id " + deploymentId) } +func (ts *TreeService) value(repositoryName string, valueId string, traceId string) (*tree.Node, error) { + + repo, err := ts.repository(repositoryName, traceId) + if err != nil { + return nil, err + } + + // TODO -> AllValues / ValueById etc. on Momentum-Tree abstraction. + + values := repo.AllDeployments() + for _, value := range values { + if value.Id == valueId { + return value, nil + } + } + return nil, errors.New("no value with id " + valueId) +} + func (ts *TreeService) find(traceId string, repositoryName string, terms ...string) (*tree.Node, error) { repo, err := ts.repository(repositoryName, traceId) diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go new file mode 100644 index 0000000..c54f236 --- /dev/null +++ b/momentum-core/services/value-service.go @@ -0,0 +1,92 @@ +package services + +import ( + "errors" + "momentum-core/config" + "momentum-core/models" +) + +type ValueService struct { + treeService *TreeService +} + +func NewValueService(treeService *TreeService) *ValueService { + + valueService := new(ValueService) + + valueService.treeService = treeService + + return valueService +} + +func (vs *ValueService) ValueById(repositoryName string, valueId string, traceId string) (*models.Value, error) { + + value, err := vs.treeService.value(repositoryName, valueId, traceId) + if err != nil { + config.LOGGER.LogWarning("unable to find value "+valueId, err, traceId) + return nil, err + } + if value == nil { + return nil, errors.New("no value with id " + valueId) + } + + return models.ToValueFromNode(value) +} + +func (vs *ValueService) ValuesByRepository(repositoryName string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil +} + +func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil +} + +func (vs *ValueService) ValuesByStage(repositoryName string, stageId string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil +} + +func (vs *ValueService) ValuesByDeployment(repositoryName string, deploymentId string, traceId string) ([]*models.ValueWrapper, error) { + + deployment, err := vs.treeService.deployment(repositoryName, deploymentId, traceId) + if err != nil { + return nil, err + } + + wrappers := make([]*models.ValueWrapper, 0) + + wrappedDeploymentFile, err := models.ToValueWrapperFromNode(deployment, models.DEPLOYMENT) + if err != nil { + return nil, err + } + wrappers = append(wrappers, wrappedDeploymentFile) + + for _, f := range deployment.DeploymentFolderFiles() { + wrappedFile, err := models.ToValueWrapperFromNode(f, models.DEPLOYMENT) + if err != nil { + return nil, err + } + wrappers = append(wrappers, wrappedFile) + } + + return wrappers, nil +} + +// This method removes all parents which shall not be read in certain types. +// For example, when reading values of a stage, we do not want to read the +// value of each deployment. +func (vs *ValueService) cleanParents(parents []string, reading models.ValueType) []string { + + switch reading { + + case models.REPOSITORY: + + case models.APPLICATION: + + case models.STAGE: + + case models.DEPLOYMENT: + + } + + return make([]string, 0) +} diff --git a/momentum-core/tree/momentum-tree.go b/momentum-core/tree/momentum-tree.go index b5bbba1..3979e6e 100644 --- a/momentum-core/tree/momentum-tree.go +++ b/momentum-core/tree/momentum-tree.go @@ -102,6 +102,40 @@ func (n *Node) Deployment(deploymentId string) *Node { return nil } +func (n *Node) DeploymentFolderFiles() []*Node { + + deploymentFolders := childrenWithName(n.Parent, "_deploy") + for _, depl := range deploymentFolders { + + if strings.EqualFold(n.PathWithoutEnding(), depl.PathWithoutEnding()) { + return depl.Files() + } + } + + return make([]*Node, 0) +} + +func (n *Node) Values() []*Node { + + if n == nil || n.Kind != File { + return make([]*Node, 0) + } + + return n.flat(make([]*Node, 0)) +} + +func (n *Node) flat(result []*Node) []*Node { + + if len(n.Children) > 0 { + result = append(result, n.Children...) + for _, child := range n.Children { + result = append(result, child.flat(result)...) + } + } + + return result +} + func deployments(stage *Node) []*Node { files := stage.Files() @@ -142,3 +176,15 @@ func deployments(stage *Node) []*Node { return depls } + +func childrenWithName(n *Node, name string) []*Node { + + matches := make([]*Node, 0) + for _, child := range n.Children { + if strings.EqualFold(child.Path, name) { + matches = append(matches, child) + } + } + + return matches +} From f2c55afcfdcedbc6adb58d04bc626c39a995a276 Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Tue, 15 Aug 2023 21:19:21 +0200 Subject: [PATCH 02/14] feat: basic values service --- momentum-core/dev-setup.sh | 9 +++ momentum-core/services/value-service.go | 76 +++++++++++++++++-------- 2 files changed, 60 insertions(+), 25 deletions(-) create mode 100755 momentum-core/dev-setup.sh diff --git a/momentum-core/dev-setup.sh b/momentum-core/dev-setup.sh new file mode 100755 index 0000000..553ddff --- /dev/null +++ b/momentum-core/dev-setup.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +export MOMENTUM_GIT_USER=Joel-Haeberli +export MOMENTUM_GIT_EMAIL=joel.haeberli@hotmail.com +export MOMENTUM_GIT_TOKEN=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 + +echo "user: $MOMENTUM_GIT_USER" +echo "mail: $MOMENTUM_GIT_EMAIL" +echo "token: $MOMENTUM_GIT_TOKEN" \ No newline at end of file diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go index c54f236..ef5d19d 100644 --- a/momentum-core/services/value-service.go +++ b/momentum-core/services/value-service.go @@ -4,6 +4,7 @@ import ( "errors" "momentum-core/config" "momentum-core/models" + "strings" ) type ValueService struct { @@ -33,15 +34,60 @@ func (vs *ValueService) ValueById(repositoryName string, valueId string, traceId return models.ToValueFromNode(value) } -func (vs *ValueService) ValuesByRepository(repositoryName string, traceId string) ([]*models.ValueWrapper, error) { - return make([]*models.ValueWrapper, 0), nil -} - func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { - return make([]*models.ValueWrapper, 0), nil + + application, err := vs.treeService.application(repositoryName, applicationId, traceId) + if err != nil { + return nil, err + } + + wrappedValues := make([]*models.ValueWrapper, 0) + files := application.Files() + for _, f := range files { + if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { + wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedKustomization) + } + if strings.EqualFold(f.PathWithoutEnding(), "ns") { + wrappedNamespace, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedNamespace) + } + if strings.EqualFold(f.PathWithoutEnding(), "repository") { + wrappedRepository, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedRepository) + } + } + + return wrappedValues, nil } func (vs *ValueService) ValuesByStage(repositoryName string, stageId string, traceId string) ([]*models.ValueWrapper, error) { + + stage, err := vs.treeService.stage(repositoryName, stageId, traceId) + if err != nil { + return nil, err + } + + files := stage.Files() + for _, f := range files { + if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { + wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.STAGE) + if err != nil { + return nil, err + } + return []*models.ValueWrapper{wrappedKustomization}, nil + } + } + return make([]*models.ValueWrapper, 0), nil } @@ -70,23 +116,3 @@ func (vs *ValueService) ValuesByDeployment(repositoryName string, deploymentId s return wrappers, nil } - -// This method removes all parents which shall not be read in certain types. -// For example, when reading values of a stage, we do not want to read the -// value of each deployment. -func (vs *ValueService) cleanParents(parents []string, reading models.ValueType) []string { - - switch reading { - - case models.REPOSITORY: - - case models.APPLICATION: - - case models.STAGE: - - case models.DEPLOYMENT: - - } - - return make([]string, 0) -} From 04f9cc44d847e7fed4bad2a698d6f7b813375acb Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Tue, 15 Aug 2023 21:20:08 +0200 Subject: [PATCH 03/14] Revert "feat: basic values service" This reverts commit f2c55afcfdcedbc6adb58d04bc626c39a995a276. --- momentum-core/dev-setup.sh | 9 --- momentum-core/services/value-service.go | 76 ++++++++----------------- 2 files changed, 25 insertions(+), 60 deletions(-) delete mode 100755 momentum-core/dev-setup.sh diff --git a/momentum-core/dev-setup.sh b/momentum-core/dev-setup.sh deleted file mode 100755 index 553ddff..0000000 --- a/momentum-core/dev-setup.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -export MOMENTUM_GIT_USER=Joel-Haeberli -export MOMENTUM_GIT_EMAIL=joel.haeberli@hotmail.com -export MOMENTUM_GIT_TOKEN=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 - -echo "user: $MOMENTUM_GIT_USER" -echo "mail: $MOMENTUM_GIT_EMAIL" -echo "token: $MOMENTUM_GIT_TOKEN" \ No newline at end of file diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go index ef5d19d..c54f236 100644 --- a/momentum-core/services/value-service.go +++ b/momentum-core/services/value-service.go @@ -4,7 +4,6 @@ import ( "errors" "momentum-core/config" "momentum-core/models" - "strings" ) type ValueService struct { @@ -34,60 +33,15 @@ func (vs *ValueService) ValueById(repositoryName string, valueId string, traceId return models.ToValueFromNode(value) } -func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { - - application, err := vs.treeService.application(repositoryName, applicationId, traceId) - if err != nil { - return nil, err - } - - wrappedValues := make([]*models.ValueWrapper, 0) - files := application.Files() - for _, f := range files { - if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { - wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.APPLICATION) - if err != nil { - return nil, err - } - wrappedValues = append(wrappedValues, wrappedKustomization) - } - if strings.EqualFold(f.PathWithoutEnding(), "ns") { - wrappedNamespace, err := models.ToValueWrapperFromNode(f, models.APPLICATION) - if err != nil { - return nil, err - } - wrappedValues = append(wrappedValues, wrappedNamespace) - } - if strings.EqualFold(f.PathWithoutEnding(), "repository") { - wrappedRepository, err := models.ToValueWrapperFromNode(f, models.APPLICATION) - if err != nil { - return nil, err - } - wrappedValues = append(wrappedValues, wrappedRepository) - } - } +func (vs *ValueService) ValuesByRepository(repositoryName string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil +} - return wrappedValues, nil +func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil } func (vs *ValueService) ValuesByStage(repositoryName string, stageId string, traceId string) ([]*models.ValueWrapper, error) { - - stage, err := vs.treeService.stage(repositoryName, stageId, traceId) - if err != nil { - return nil, err - } - - files := stage.Files() - for _, f := range files { - if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { - wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.STAGE) - if err != nil { - return nil, err - } - return []*models.ValueWrapper{wrappedKustomization}, nil - } - } - return make([]*models.ValueWrapper, 0), nil } @@ -116,3 +70,23 @@ func (vs *ValueService) ValuesByDeployment(repositoryName string, deploymentId s return wrappers, nil } + +// This method removes all parents which shall not be read in certain types. +// For example, when reading values of a stage, we do not want to read the +// value of each deployment. +func (vs *ValueService) cleanParents(parents []string, reading models.ValueType) []string { + + switch reading { + + case models.REPOSITORY: + + case models.APPLICATION: + + case models.STAGE: + + case models.DEPLOYMENT: + + } + + return make([]string, 0) +} From 065cbf365aeb3f54ce28c867c38e78da88b48c75 Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Tue, 15 Aug 2023 21:24:30 +0200 Subject: [PATCH 04/14] feat: basic value service --- momentum-core/services/value-service.go | 76 +++++++++++++++++-------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go index c54f236..ef5d19d 100644 --- a/momentum-core/services/value-service.go +++ b/momentum-core/services/value-service.go @@ -4,6 +4,7 @@ import ( "errors" "momentum-core/config" "momentum-core/models" + "strings" ) type ValueService struct { @@ -33,15 +34,60 @@ func (vs *ValueService) ValueById(repositoryName string, valueId string, traceId return models.ToValueFromNode(value) } -func (vs *ValueService) ValuesByRepository(repositoryName string, traceId string) ([]*models.ValueWrapper, error) { - return make([]*models.ValueWrapper, 0), nil -} - func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { - return make([]*models.ValueWrapper, 0), nil + + application, err := vs.treeService.application(repositoryName, applicationId, traceId) + if err != nil { + return nil, err + } + + wrappedValues := make([]*models.ValueWrapper, 0) + files := application.Files() + for _, f := range files { + if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { + wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedKustomization) + } + if strings.EqualFold(f.PathWithoutEnding(), "ns") { + wrappedNamespace, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedNamespace) + } + if strings.EqualFold(f.PathWithoutEnding(), "repository") { + wrappedRepository, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedRepository) + } + } + + return wrappedValues, nil } func (vs *ValueService) ValuesByStage(repositoryName string, stageId string, traceId string) ([]*models.ValueWrapper, error) { + + stage, err := vs.treeService.stage(repositoryName, stageId, traceId) + if err != nil { + return nil, err + } + + files := stage.Files() + for _, f := range files { + if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { + wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.STAGE) + if err != nil { + return nil, err + } + return []*models.ValueWrapper{wrappedKustomization}, nil + } + } + return make([]*models.ValueWrapper, 0), nil } @@ -70,23 +116,3 @@ func (vs *ValueService) ValuesByDeployment(repositoryName string, deploymentId s return wrappers, nil } - -// This method removes all parents which shall not be read in certain types. -// For example, when reading values of a stage, we do not want to read the -// value of each deployment. -func (vs *ValueService) cleanParents(parents []string, reading models.ValueType) []string { - - switch reading { - - case models.REPOSITORY: - - case models.APPLICATION: - - case models.STAGE: - - case models.DEPLOYMENT: - - } - - return make([]string, 0) -} From 5b868c4ed19662296f7df21a9ad9373e8583a0c4 Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Mon, 14 Aug 2023 23:16:38 +0200 Subject: [PATCH 05/14] feat: values service basic structure --- momentum-core/main.go | 4 +- momentum-core/models/keyvalue.go | 57 +++++++++++-- momentum-core/routers/application-router.go | 4 +- momentum-core/routers/value-router.go | 40 ++++++++- momentum-core/services/keyvalue-service.go | 10 --- momentum-core/services/tree-service.go | 18 ++++ momentum-core/services/value-service.go | 92 +++++++++++++++++++++ momentum-core/tree/momentum-tree.go | 46 +++++++++++ 8 files changed, 247 insertions(+), 24 deletions(-) delete mode 100644 momentum-core/services/keyvalue-service.go create mode 100644 momentum-core/services/value-service.go diff --git a/momentum-core/main.go b/momentum-core/main.go index 3fa959c..28ca829 100644 --- a/momentum-core/main.go +++ b/momentum-core/main.go @@ -38,10 +38,10 @@ func main() { applicationService := services.NewApplicationService(config, treeService, templateService) stageService := services.NewStageService(config, treeService, templateService) deploymentService := services.NewDeploymentService(config, stageService, templateService, treeService) - // valueService := services.NewValueService() + valueService := services.NewValueService(treeService) templateRouter := routers.NewTemplateRouter() - valueRouter := routers.NewValueRouter() + valueRouter := routers.NewValueRouter(valueService) deploymentRouter := routers.NewDeploymentRouter(deploymentService, repositoryService, config) stageRouter := routers.NewStageRouter(stageService, repositoryService, config) applicationRouter := routers.NewApplicationRouter(applicationService, repositoryService, config) diff --git a/momentum-core/models/keyvalue.go b/momentum-core/models/keyvalue.go index 0c9e8fa..fbdfa34 100644 --- a/momentum-core/models/keyvalue.go +++ b/momentum-core/models/keyvalue.go @@ -1,6 +1,7 @@ package models import ( + "errors" "momentum-core/clients" "momentum-core/tree" "momentum-core/utils" @@ -8,6 +9,15 @@ import ( "github.com/gin-gonic/gin" ) +type ValueType int + +const ( + REPOSITORY ValueType = iota + APPLICATION + STAGE + DEPLOYMENT +) + type KeyValueCreateRequest struct { Key string `json:"key"` Value string `json:"value"` @@ -17,7 +27,7 @@ type KeyValueCreateRequest struct { ParentKeyValueId string `json:"parentKeyValueId"` } -type KeyValue struct { +type Value struct { Id string `json:"id"` Key string `json:"key"` Value string `json:"value"` @@ -27,17 +37,48 @@ type KeyValue struct { ParentDeploymentId string `json:"parentDeploymentId"` } +type ValueWrapper struct { + FileId string `json:"parentFileId"` + FileName string `json:"parentFileName"` + ValueType ValueType `json:"valueType"` + Values []*Value `json:"values"` +} + func ExtractKeyValueCreateRequest(c *gin.Context) (*KeyValueCreateRequest, error) { return utils.Extract[KeyValueCreateRequest](c) } -func ExtractKeyValue(c *gin.Context) (*KeyValue, error) { - return utils.Extract[KeyValue](c) +func ExtractKeyValue(c *gin.Context) (*Value, error) { + return utils.Extract[Value](c) +} + +func ToValueWrapperFromNode(n *tree.Node, valType ValueType) (*ValueWrapper, error) { + + if n.Kind != tree.File { + return nil, errors.New("only files can be converted to a value wrapper") + } + + valueWrapper := new(ValueWrapper) + + valueWrapper.FileId = n.Id + valueWrapper.FileName = n.NormalizedPath() + mappedValues := make([]*Value, 0) + for _, v := range n.Values() { + value, err := ToValueFromNode(v) + if err != nil { + return nil, errors.New("unable to map value from node") + } + mappedValues = append(mappedValues, value) + } + valueWrapper.Values = mappedValues + valueWrapper.ValueType = valType + + return valueWrapper, nil } -func ToKeyValueFromNode(n *tree.Node) (*KeyValue, error) { +func ToValueFromNode(n *tree.Node) (*Value, error) { - keyValue := new(KeyValue) + keyValue := new(Value) keyValue.Id = n.Id keyValue.Key = n.FullPath() @@ -57,16 +98,16 @@ func ToKeyValueFromNode(n *tree.Node) (*KeyValue, error) { return keyValue, nil } -func ToKeyValue(data []byte) (*KeyValue, error) { +func ToKeyValue(data []byte) (*Value, error) { - keyValue, err := clients.UnmarshallJson[KeyValue](data) + keyValue, err := clients.UnmarshallJson[Value](data) if err != nil { return nil, err } return keyValue, nil } -func (kv *KeyValue) ToJson() ([]byte, error) { +func (kv *Value) ToJson() ([]byte, error) { data, err := clients.MarshallJson(kv) if err != nil { diff --git a/momentum-core/routers/application-router.go b/momentum-core/routers/application-router.go index 1dc2847..bb5d37b 100644 --- a/momentum-core/routers/application-router.go +++ b/momentum-core/routers/application-router.go @@ -39,7 +39,7 @@ func (a *ApplicationRouter) RegisterApplicationRoutes(server *gin.Engine) { server.POST(ROUTING_PATH_APPLICATION, a.addApplication) } -// GetApplication godoc +// getApplication godoc // // @Summary get an application of a repository by id // @Tags applications @@ -85,7 +85,7 @@ func (a *ApplicationRouter) getApplication(c *gin.Context) { c.JSON(http.StatusOK, result) } -// AddApplication godoc +// addApplication godoc // // @Summary add an application // @Tags applications diff --git a/momentum-core/routers/value-router.go b/momentum-core/routers/value-router.go index 4c444ca..c941c2f 100644 --- a/momentum-core/routers/value-router.go +++ b/momentum-core/routers/value-router.go @@ -1,7 +1,43 @@ package routers -type ValueRouter struct{} +import ( + "momentum-core/config" + "momentum-core/models" + "momentum-core/services" + "net/http" -func NewValueRouter() *ValueRouter { + "github.com/gin-gonic/gin" +) + +const ROUTING_PATH_VALUE_BY_ID = VERSION + "/repository/:repositoryName/:valueId" +const ROUTING_PATH_VALUE = VERSION + "/value" + +type ValueRouter struct { + valueService *services.ValueService +} + +func NewValueRouter(valueService *services.ValueService) *ValueRouter { return new(ValueRouter) } + +func (vr *ValueRouter) RegisterValueRoutes(server *gin.Engine) { + + server.GET(ROUTING_PATH_VALUE_BY_ID, vr.valueById) +} + +func (vr *ValueRouter) valueById(c *gin.Context) { + + traceId := config.LOGGER.TraceId() + + repoName := c.Param("repositoryName") + valueId := c.Param("valueId") + + result, err := vr.valueService.ValueById(repoName, valueId, traceId) + if err != nil { + c.JSON(http.StatusNotFound, models.NewApiError(err, http.StatusNotFound, c, traceId)) + config.LOGGER.LogError(err.Error(), err, traceId) + return + } + + c.JSON(http.StatusOK, result) +} diff --git a/momentum-core/services/keyvalue-service.go b/momentum-core/services/keyvalue-service.go deleted file mode 100644 index 2d3b435..0000000 --- a/momentum-core/services/keyvalue-service.go +++ /dev/null @@ -1,10 +0,0 @@ -package services - -type ValueService struct{} - -func NewValueService() *ValueService { - - valueService := new(ValueService) - - return valueService -} diff --git a/momentum-core/services/tree-service.go b/momentum-core/services/tree-service.go index ad8caf4..be8a0f2 100644 --- a/momentum-core/services/tree-service.go +++ b/momentum-core/services/tree-service.go @@ -79,6 +79,24 @@ func (ts *TreeService) deployment(repositoryName string, deploymentId string, tr return nil, errors.New("no deployment with id " + deploymentId) } +func (ts *TreeService) value(repositoryName string, valueId string, traceId string) (*tree.Node, error) { + + repo, err := ts.repository(repositoryName, traceId) + if err != nil { + return nil, err + } + + // TODO -> AllValues / ValueById etc. on Momentum-Tree abstraction. + + values := repo.AllDeployments() + for _, value := range values { + if value.Id == valueId { + return value, nil + } + } + return nil, errors.New("no value with id " + valueId) +} + func (ts *TreeService) find(traceId string, repositoryName string, terms ...string) (*tree.Node, error) { repo, err := ts.repository(repositoryName, traceId) diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go new file mode 100644 index 0000000..c54f236 --- /dev/null +++ b/momentum-core/services/value-service.go @@ -0,0 +1,92 @@ +package services + +import ( + "errors" + "momentum-core/config" + "momentum-core/models" +) + +type ValueService struct { + treeService *TreeService +} + +func NewValueService(treeService *TreeService) *ValueService { + + valueService := new(ValueService) + + valueService.treeService = treeService + + return valueService +} + +func (vs *ValueService) ValueById(repositoryName string, valueId string, traceId string) (*models.Value, error) { + + value, err := vs.treeService.value(repositoryName, valueId, traceId) + if err != nil { + config.LOGGER.LogWarning("unable to find value "+valueId, err, traceId) + return nil, err + } + if value == nil { + return nil, errors.New("no value with id " + valueId) + } + + return models.ToValueFromNode(value) +} + +func (vs *ValueService) ValuesByRepository(repositoryName string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil +} + +func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil +} + +func (vs *ValueService) ValuesByStage(repositoryName string, stageId string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil +} + +func (vs *ValueService) ValuesByDeployment(repositoryName string, deploymentId string, traceId string) ([]*models.ValueWrapper, error) { + + deployment, err := vs.treeService.deployment(repositoryName, deploymentId, traceId) + if err != nil { + return nil, err + } + + wrappers := make([]*models.ValueWrapper, 0) + + wrappedDeploymentFile, err := models.ToValueWrapperFromNode(deployment, models.DEPLOYMENT) + if err != nil { + return nil, err + } + wrappers = append(wrappers, wrappedDeploymentFile) + + for _, f := range deployment.DeploymentFolderFiles() { + wrappedFile, err := models.ToValueWrapperFromNode(f, models.DEPLOYMENT) + if err != nil { + return nil, err + } + wrappers = append(wrappers, wrappedFile) + } + + return wrappers, nil +} + +// This method removes all parents which shall not be read in certain types. +// For example, when reading values of a stage, we do not want to read the +// value of each deployment. +func (vs *ValueService) cleanParents(parents []string, reading models.ValueType) []string { + + switch reading { + + case models.REPOSITORY: + + case models.APPLICATION: + + case models.STAGE: + + case models.DEPLOYMENT: + + } + + return make([]string, 0) +} diff --git a/momentum-core/tree/momentum-tree.go b/momentum-core/tree/momentum-tree.go index b5bbba1..3979e6e 100644 --- a/momentum-core/tree/momentum-tree.go +++ b/momentum-core/tree/momentum-tree.go @@ -102,6 +102,40 @@ func (n *Node) Deployment(deploymentId string) *Node { return nil } +func (n *Node) DeploymentFolderFiles() []*Node { + + deploymentFolders := childrenWithName(n.Parent, "_deploy") + for _, depl := range deploymentFolders { + + if strings.EqualFold(n.PathWithoutEnding(), depl.PathWithoutEnding()) { + return depl.Files() + } + } + + return make([]*Node, 0) +} + +func (n *Node) Values() []*Node { + + if n == nil || n.Kind != File { + return make([]*Node, 0) + } + + return n.flat(make([]*Node, 0)) +} + +func (n *Node) flat(result []*Node) []*Node { + + if len(n.Children) > 0 { + result = append(result, n.Children...) + for _, child := range n.Children { + result = append(result, child.flat(result)...) + } + } + + return result +} + func deployments(stage *Node) []*Node { files := stage.Files() @@ -142,3 +176,15 @@ func deployments(stage *Node) []*Node { return depls } + +func childrenWithName(n *Node, name string) []*Node { + + matches := make([]*Node, 0) + for _, child := range n.Children { + if strings.EqualFold(child.Path, name) { + matches = append(matches, child) + } + } + + return matches +} From 4420bcefbcdc16fd85c1bf3a6b2420b20057ffa1 Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Tue, 15 Aug 2023 21:19:21 +0200 Subject: [PATCH 06/14] feat: basic values service --- momentum-core/dev-setup.sh | 9 +++ momentum-core/services/value-service.go | 76 +++++++++++++++++-------- 2 files changed, 60 insertions(+), 25 deletions(-) create mode 100755 momentum-core/dev-setup.sh diff --git a/momentum-core/dev-setup.sh b/momentum-core/dev-setup.sh new file mode 100755 index 0000000..553ddff --- /dev/null +++ b/momentum-core/dev-setup.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +export MOMENTUM_GIT_USER=Joel-Haeberli +export MOMENTUM_GIT_EMAIL=joel.haeberli@hotmail.com +export MOMENTUM_GIT_TOKEN=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 + +echo "user: $MOMENTUM_GIT_USER" +echo "mail: $MOMENTUM_GIT_EMAIL" +echo "token: $MOMENTUM_GIT_TOKEN" \ No newline at end of file diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go index c54f236..ef5d19d 100644 --- a/momentum-core/services/value-service.go +++ b/momentum-core/services/value-service.go @@ -4,6 +4,7 @@ import ( "errors" "momentum-core/config" "momentum-core/models" + "strings" ) type ValueService struct { @@ -33,15 +34,60 @@ func (vs *ValueService) ValueById(repositoryName string, valueId string, traceId return models.ToValueFromNode(value) } -func (vs *ValueService) ValuesByRepository(repositoryName string, traceId string) ([]*models.ValueWrapper, error) { - return make([]*models.ValueWrapper, 0), nil -} - func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { - return make([]*models.ValueWrapper, 0), nil + + application, err := vs.treeService.application(repositoryName, applicationId, traceId) + if err != nil { + return nil, err + } + + wrappedValues := make([]*models.ValueWrapper, 0) + files := application.Files() + for _, f := range files { + if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { + wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedKustomization) + } + if strings.EqualFold(f.PathWithoutEnding(), "ns") { + wrappedNamespace, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedNamespace) + } + if strings.EqualFold(f.PathWithoutEnding(), "repository") { + wrappedRepository, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedRepository) + } + } + + return wrappedValues, nil } func (vs *ValueService) ValuesByStage(repositoryName string, stageId string, traceId string) ([]*models.ValueWrapper, error) { + + stage, err := vs.treeService.stage(repositoryName, stageId, traceId) + if err != nil { + return nil, err + } + + files := stage.Files() + for _, f := range files { + if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { + wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.STAGE) + if err != nil { + return nil, err + } + return []*models.ValueWrapper{wrappedKustomization}, nil + } + } + return make([]*models.ValueWrapper, 0), nil } @@ -70,23 +116,3 @@ func (vs *ValueService) ValuesByDeployment(repositoryName string, deploymentId s return wrappers, nil } - -// This method removes all parents which shall not be read in certain types. -// For example, when reading values of a stage, we do not want to read the -// value of each deployment. -func (vs *ValueService) cleanParents(parents []string, reading models.ValueType) []string { - - switch reading { - - case models.REPOSITORY: - - case models.APPLICATION: - - case models.STAGE: - - case models.DEPLOYMENT: - - } - - return make([]string, 0) -} From 0d190511039e8568af0c0b0a4cd0b5da72733c7b Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Tue, 15 Aug 2023 21:20:08 +0200 Subject: [PATCH 07/14] Revert "feat: basic values service" This reverts commit f2c55afcfdcedbc6adb58d04bc626c39a995a276. --- momentum-core/dev-setup.sh | 9 --- momentum-core/services/value-service.go | 76 ++++++++----------------- 2 files changed, 25 insertions(+), 60 deletions(-) delete mode 100755 momentum-core/dev-setup.sh diff --git a/momentum-core/dev-setup.sh b/momentum-core/dev-setup.sh deleted file mode 100755 index 553ddff..0000000 --- a/momentum-core/dev-setup.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -export MOMENTUM_GIT_USER=Joel-Haeberli -export MOMENTUM_GIT_EMAIL=joel.haeberli@hotmail.com -export MOMENTUM_GIT_TOKEN=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 - -echo "user: $MOMENTUM_GIT_USER" -echo "mail: $MOMENTUM_GIT_EMAIL" -echo "token: $MOMENTUM_GIT_TOKEN" \ No newline at end of file diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go index ef5d19d..c54f236 100644 --- a/momentum-core/services/value-service.go +++ b/momentum-core/services/value-service.go @@ -4,7 +4,6 @@ import ( "errors" "momentum-core/config" "momentum-core/models" - "strings" ) type ValueService struct { @@ -34,60 +33,15 @@ func (vs *ValueService) ValueById(repositoryName string, valueId string, traceId return models.ToValueFromNode(value) } -func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { - - application, err := vs.treeService.application(repositoryName, applicationId, traceId) - if err != nil { - return nil, err - } - - wrappedValues := make([]*models.ValueWrapper, 0) - files := application.Files() - for _, f := range files { - if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { - wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.APPLICATION) - if err != nil { - return nil, err - } - wrappedValues = append(wrappedValues, wrappedKustomization) - } - if strings.EqualFold(f.PathWithoutEnding(), "ns") { - wrappedNamespace, err := models.ToValueWrapperFromNode(f, models.APPLICATION) - if err != nil { - return nil, err - } - wrappedValues = append(wrappedValues, wrappedNamespace) - } - if strings.EqualFold(f.PathWithoutEnding(), "repository") { - wrappedRepository, err := models.ToValueWrapperFromNode(f, models.APPLICATION) - if err != nil { - return nil, err - } - wrappedValues = append(wrappedValues, wrappedRepository) - } - } +func (vs *ValueService) ValuesByRepository(repositoryName string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil +} - return wrappedValues, nil +func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { + return make([]*models.ValueWrapper, 0), nil } func (vs *ValueService) ValuesByStage(repositoryName string, stageId string, traceId string) ([]*models.ValueWrapper, error) { - - stage, err := vs.treeService.stage(repositoryName, stageId, traceId) - if err != nil { - return nil, err - } - - files := stage.Files() - for _, f := range files { - if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { - wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.STAGE) - if err != nil { - return nil, err - } - return []*models.ValueWrapper{wrappedKustomization}, nil - } - } - return make([]*models.ValueWrapper, 0), nil } @@ -116,3 +70,23 @@ func (vs *ValueService) ValuesByDeployment(repositoryName string, deploymentId s return wrappers, nil } + +// This method removes all parents which shall not be read in certain types. +// For example, when reading values of a stage, we do not want to read the +// value of each deployment. +func (vs *ValueService) cleanParents(parents []string, reading models.ValueType) []string { + + switch reading { + + case models.REPOSITORY: + + case models.APPLICATION: + + case models.STAGE: + + case models.DEPLOYMENT: + + } + + return make([]string, 0) +} From 41a8c7b256869f70412a743cca185e538421d254 Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Tue, 15 Aug 2023 21:24:30 +0200 Subject: [PATCH 08/14] feat: basic value service --- momentum-core/services/value-service.go | 76 +++++++++++++++++-------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go index c54f236..ef5d19d 100644 --- a/momentum-core/services/value-service.go +++ b/momentum-core/services/value-service.go @@ -4,6 +4,7 @@ import ( "errors" "momentum-core/config" "momentum-core/models" + "strings" ) type ValueService struct { @@ -33,15 +34,60 @@ func (vs *ValueService) ValueById(repositoryName string, valueId string, traceId return models.ToValueFromNode(value) } -func (vs *ValueService) ValuesByRepository(repositoryName string, traceId string) ([]*models.ValueWrapper, error) { - return make([]*models.ValueWrapper, 0), nil -} - func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId string, traceId string) ([]*models.ValueWrapper, error) { - return make([]*models.ValueWrapper, 0), nil + + application, err := vs.treeService.application(repositoryName, applicationId, traceId) + if err != nil { + return nil, err + } + + wrappedValues := make([]*models.ValueWrapper, 0) + files := application.Files() + for _, f := range files { + if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { + wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedKustomization) + } + if strings.EqualFold(f.PathWithoutEnding(), "ns") { + wrappedNamespace, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedNamespace) + } + if strings.EqualFold(f.PathWithoutEnding(), "repository") { + wrappedRepository, err := models.ToValueWrapperFromNode(f, models.APPLICATION) + if err != nil { + return nil, err + } + wrappedValues = append(wrappedValues, wrappedRepository) + } + } + + return wrappedValues, nil } func (vs *ValueService) ValuesByStage(repositoryName string, stageId string, traceId string) ([]*models.ValueWrapper, error) { + + stage, err := vs.treeService.stage(repositoryName, stageId, traceId) + if err != nil { + return nil, err + } + + files := stage.Files() + for _, f := range files { + if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { + wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.STAGE) + if err != nil { + return nil, err + } + return []*models.ValueWrapper{wrappedKustomization}, nil + } + } + return make([]*models.ValueWrapper, 0), nil } @@ -70,23 +116,3 @@ func (vs *ValueService) ValuesByDeployment(repositoryName string, deploymentId s return wrappers, nil } - -// This method removes all parents which shall not be read in certain types. -// For example, when reading values of a stage, we do not want to read the -// value of each deployment. -func (vs *ValueService) cleanParents(parents []string, reading models.ValueType) []string { - - switch reading { - - case models.REPOSITORY: - - case models.APPLICATION: - - case models.STAGE: - - case models.DEPLOYMENT: - - } - - return make([]string, 0) -} From 1693f266739f74b7bf52e26ded5c83c2b5ee138c Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Wed, 16 Aug 2023 21:38:20 +0200 Subject: [PATCH 09/14] feat: add value routes --- momentum-core/config/config.go | 4 ++ momentum-core/dispatcher.go | 1 + momentum-core/routers/value-router.go | 59 ++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/momentum-core/config/config.go b/momentum-core/config/config.go index ecd528b..bef810d 100644 --- a/momentum-core/config/config.go +++ b/momentum-core/config/config.go @@ -99,6 +99,10 @@ func (m *MomentumConfig) checkMandatoryTemplates() error { func (m *MomentumConfig) initializeGitAccessToken() error { + if TRANSACTION_MODE == gittransaction.DEBUG { + return nil + } + m.transactionToken = new(gittransaction.Token) m.transactionToken.Username = os.Getenv(MOMENTUM_GIT_USER) diff --git a/momentum-core/dispatcher.go b/momentum-core/dispatcher.go index dd5e9be..dbe2771 100644 --- a/momentum-core/dispatcher.go +++ b/momentum-core/dispatcher.go @@ -47,6 +47,7 @@ func NewDispatcher(config *config.MomentumConfig, dispatcher.applicationRouter.RegisterApplicationRoutes(dispatcher.server) dispatcher.stageRouter.RegisterStageRoutes(dispatcher.server) dispatcher.deploymentRouter.RegisterDeploymentRoutes(dispatcher.server) + dispatcher.valueRouter.RegisterValueRoutes(dispatcher.server) dispatcher.server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) diff --git a/momentum-core/routers/value-router.go b/momentum-core/routers/value-router.go index c941c2f..c4465b8 100644 --- a/momentum-core/routers/value-router.go +++ b/momentum-core/routers/value-router.go @@ -9,8 +9,11 @@ import ( "github.com/gin-gonic/gin" ) -const ROUTING_PATH_VALUE_BY_ID = VERSION + "/repository/:repositoryName/:valueId" +const ROUTING_PATH_VALUE_BY_ID = VERSION + "/repository/:repositoryName/value/:valueId" const ROUTING_PATH_VALUE = VERSION + "/value" +const ROUTING_PATH_VALUE_BY_APPLICATION = VERSION + "/:repositoryName/application/values/:applicationId" +const ROUTING_PATH_VALUE_BY_STAGE = VERSION + "/:repositoryName/stage/values/:stageId" +const ROUTING_PATH_VALUE_BY_DEPLOYMENT = VERSION + "/:repositoryName/deployment/values/:deploymentId" type ValueRouter struct { valueService *services.ValueService @@ -23,6 +26,9 @@ func NewValueRouter(valueService *services.ValueService) *ValueRouter { func (vr *ValueRouter) RegisterValueRoutes(server *gin.Engine) { server.GET(ROUTING_PATH_VALUE_BY_ID, vr.valueById) + server.GET(ROUTING_PATH_VALUE_BY_APPLICATION, vr.valuesByApplication) + server.GET(ROUTING_PATH_VALUE_BY_STAGE, vr.valuesByStage) + server.GET(ROUTING_PATH_VALUE_BY_DEPLOYMENT, vr.valuesByDeployment) } func (vr *ValueRouter) valueById(c *gin.Context) { @@ -41,3 +47,54 @@ func (vr *ValueRouter) valueById(c *gin.Context) { c.JSON(http.StatusOK, result) } + +func (vr *ValueRouter) valuesByApplication(c *gin.Context) { + + traceId := config.LOGGER.TraceId() + + repoName := c.Param("repositoryName") + applicationId := c.Param("applicationId") + + result, err := vr.valueService.ValueById(repoName, applicationId, traceId) + if err != nil { + c.JSON(http.StatusNotFound, models.NewApiError(err, http.StatusNotFound, c, traceId)) + config.LOGGER.LogError(err.Error(), err, traceId) + return + } + + c.JSON(http.StatusOK, result) +} + +func (vr *ValueRouter) valuesByStage(c *gin.Context) { + + traceId := config.LOGGER.TraceId() + + repoName := c.Param("repositoryName") + stageId := c.Param("stageId") + + result, err := vr.valueService.ValuesByStage(repoName, stageId, traceId) + if err != nil { + c.JSON(http.StatusNotFound, models.NewApiError(err, http.StatusNotFound, c, traceId)) + config.LOGGER.LogError(err.Error(), err, traceId) + return + } + + c.JSON(http.StatusOK, result) +} + +func (vr *ValueRouter) valuesByDeployment(c *gin.Context) { + + traceId := config.LOGGER.TraceId() + + repoName := c.Param("repositoryName") + deploymentId := c.Param("deploymentId") + + result, err := vr.valueService.ValuesByDeployment(repoName, deploymentId, traceId) + if err != nil { + c.JSON(http.StatusNotFound, models.NewApiError(err, http.StatusNotFound, c, traceId)) + config.LOGGER.LogError(err.Error(), err, traceId) + return + } + + c.JSON(http.StatusOK, result) +} From 6bd1c617f32b3eb9e030d512983750c072e4d9dd Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Wed, 16 Aug 2023 21:56:40 +0200 Subject: [PATCH 10/14] feat: add swagger doc for value endpoints --- momentum-core/docs/docs.go | 279 ++++++++++++++++++++++++++ momentum-core/docs/swagger.json | 279 ++++++++++++++++++++++++++ momentum-core/docs/swagger.yaml | 186 +++++++++++++++++ momentum-core/routers/value-router.go | 48 +++++ 4 files changed, 792 insertions(+) diff --git a/momentum-core/docs/docs.go b/momentum-core/docs/docs.go index 5f98176..4e66efb 100644 --- a/momentum-core/docs/docs.go +++ b/momentum-core/docs/docs.go @@ -367,6 +367,62 @@ const docTemplate = `{ } } }, + "/repository/{repositoryName}/application/values/{applicationId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "values" + ], + "summary": "get all values of an application by the applications id", + "parameters": [ + { + "type": "string", + "description": "Repository Name", + "name": "repositoryName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Application ID", + "name": "applicationId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ValueWrapper" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + } + } + } + }, "/repository/{repositoryName}/applications": { "get": { "consumes": [ @@ -419,6 +475,62 @@ const docTemplate = `{ } } }, + "/repository/{repositoryName}/deployment/values/{deploymentId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "values" + ], + "summary": "get all values of a deployment by the deployments id", + "parameters": [ + { + "type": "string", + "description": "Repository Name", + "name": "repositoryName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Deployment ID", + "name": "deploymentId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ValueWrapper" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + } + } + } + }, "/repository/{repositoryName}/deployments": { "get": { "produces": [ @@ -468,6 +580,62 @@ const docTemplate = `{ } } }, + "/repository/{repositoryName}/stage/values/{stageId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "values" + ], + "summary": "get all values of an stage by the stages id", + "parameters": [ + { + "type": "string", + "description": "Repository Name", + "name": "repositoryName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage ID", + "name": "stageId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ValueWrapper" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + } + } + } + }, "/repository/{repositoryName}/stages": { "get": { "produces": [ @@ -517,6 +685,59 @@ const docTemplate = `{ } } }, + "/repository/{repositoryName}/value/{valueId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "values" + ], + "summary": "get a value of a repository by id", + "parameters": [ + { + "type": "string", + "description": "Repository Name", + "name": "repositoryName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Value ID", + "name": "valueId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Value" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + } + } + } + }, "/repository/{repositoryName}/{applicationId}": { "get": { "produces": [ @@ -776,6 +997,64 @@ const docTemplate = `{ "type": "string" } } + }, + "models.Value": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "key": { + "type": "string" + }, + "parentDeploymentId": { + "type": "string" + }, + "parentStageId": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "models.ValueType": { + "type": "integer", + "enum": [ + 0, + 1, + 2, + 3 + ], + "x-enum-varnames": [ + "REPOSITORY", + "APPLICATION", + "STAGE", + "DEPLOYMENT" + ] + }, + "models.ValueWrapper": { + "type": "object", + "properties": { + "parentFileId": { + "type": "string" + }, + "parentFileName": { + "type": "string" + }, + "valueType": { + "$ref": "#/definitions/models.ValueType" + }, + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Value" + } + } + } } } }` diff --git a/momentum-core/docs/swagger.json b/momentum-core/docs/swagger.json index ca07c93..7836826 100644 --- a/momentum-core/docs/swagger.json +++ b/momentum-core/docs/swagger.json @@ -364,6 +364,62 @@ } } }, + "/repository/{repositoryName}/application/values/{applicationId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "values" + ], + "summary": "get all values of an application by the applications id", + "parameters": [ + { + "type": "string", + "description": "Repository Name", + "name": "repositoryName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Application ID", + "name": "applicationId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ValueWrapper" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + } + } + } + }, "/repository/{repositoryName}/applications": { "get": { "consumes": [ @@ -416,6 +472,62 @@ } } }, + "/repository/{repositoryName}/deployment/values/{deploymentId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "values" + ], + "summary": "get all values of a deployment by the deployments id", + "parameters": [ + { + "type": "string", + "description": "Repository Name", + "name": "repositoryName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Deployment ID", + "name": "deploymentId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ValueWrapper" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + } + } + } + }, "/repository/{repositoryName}/deployments": { "get": { "produces": [ @@ -465,6 +577,62 @@ } } }, + "/repository/{repositoryName}/stage/values/{stageId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "values" + ], + "summary": "get all values of an stage by the stages id", + "parameters": [ + { + "type": "string", + "description": "Repository Name", + "name": "repositoryName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage ID", + "name": "stageId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ValueWrapper" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + } + } + } + }, "/repository/{repositoryName}/stages": { "get": { "produces": [ @@ -514,6 +682,59 @@ } } }, + "/repository/{repositoryName}/value/{valueId}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "values" + ], + "summary": "get a value of a repository by id", + "parameters": [ + { + "type": "string", + "description": "Repository Name", + "name": "repositoryName", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Value ID", + "name": "valueId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.Value" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/models.ApiError" + } + } + } + } + }, "/repository/{repositoryName}/{applicationId}": { "get": { "produces": [ @@ -773,6 +994,64 @@ "type": "string" } } + }, + "models.Value": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "id": { + "type": "string" + }, + "key": { + "type": "string" + }, + "parentDeploymentId": { + "type": "string" + }, + "parentStageId": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "models.ValueType": { + "type": "integer", + "enum": [ + 0, + 1, + 2, + 3 + ], + "x-enum-varnames": [ + "REPOSITORY", + "APPLICATION", + "STAGE", + "DEPLOYMENT" + ] + }, + "models.ValueWrapper": { + "type": "object", + "properties": { + "parentFileId": { + "type": "string" + }, + "parentFileName": { + "type": "string" + }, + "valueType": { + "$ref": "#/definitions/models.ValueType" + }, + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Value" + } + } + } } } } \ No newline at end of file diff --git a/momentum-core/docs/swagger.yaml b/momentum-core/docs/swagger.yaml index 64b93ae..04d9d25 100644 --- a/momentum-core/docs/swagger.yaml +++ b/momentum-core/docs/swagger.yaml @@ -100,6 +100,46 @@ definitions: repositoryName: type: string type: object + models.Value: + properties: + displayName: + type: string + id: + type: string + key: + type: string + parentDeploymentId: + type: string + parentStageId: + type: string + value: + type: string + type: object + models.ValueType: + enum: + - 0 + - 1 + - 2 + - 3 + type: integer + x-enum-varnames: + - REPOSITORY + - APPLICATION + - STAGE + - DEPLOYMENT + models.ValueWrapper: + properties: + parentFileId: + type: string + parentFileName: + type: string + valueType: + $ref: '#/definitions/models.ValueType' + values: + items: + $ref: '#/definitions/models.Value' + type: array + type: object host: localhost:8080 info: contact: {} @@ -372,6 +412,43 @@ paths: summary: get a deployment of a repository by id tags: - deployments + /repository/{repositoryName}/application/values/{applicationId}: + get: + parameters: + - description: Repository Name + in: path + name: repositoryName + required: true + type: string + - description: Application ID + in: path + name: applicationId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.ValueWrapper' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.ApiError' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.ApiError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.ApiError' + summary: get all values of an application by the applications id + tags: + - values /repository/{repositoryName}/applications: get: consumes: @@ -406,6 +483,43 @@ paths: summary: get all applications of a repository tags: - applications + /repository/{repositoryName}/deployment/values/{deploymentId}: + get: + parameters: + - description: Repository Name + in: path + name: repositoryName + required: true + type: string + - description: Deployment ID + in: path + name: deploymentId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.ValueWrapper' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.ApiError' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.ApiError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.ApiError' + summary: get all values of a deployment by the deployments id + tags: + - values /repository/{repositoryName}/deployments: get: parameters: @@ -438,6 +552,43 @@ paths: summary: get deployments tags: - deployments + /repository/{repositoryName}/stage/values/{stageId}: + get: + parameters: + - description: Repository Name + in: path + name: repositoryName + required: true + type: string + - description: Stage ID + in: path + name: stageId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.ValueWrapper' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.ApiError' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.ApiError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.ApiError' + summary: get all values of an stage by the stages id + tags: + - values /repository/{repositoryName}/stages: get: parameters: @@ -470,6 +621,41 @@ paths: summary: get stages tags: - stages + /repository/{repositoryName}/value/{valueId}: + get: + parameters: + - description: Repository Name + in: path + name: repositoryName + required: true + type: string + - description: Value ID + in: path + name: valueId + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.Value' + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.ApiError' + "404": + description: Not Found + schema: + $ref: '#/definitions/models.ApiError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.ApiError' + summary: get a value of a repository by id + tags: + - values /stage: post: consumes: diff --git a/momentum-core/routers/value-router.go b/momentum-core/routers/value-router.go index c4465b8..3605f72 100644 --- a/momentum-core/routers/value-router.go +++ b/momentum-core/routers/value-router.go @@ -31,6 +31,18 @@ func (vr *ValueRouter) RegisterValueRoutes(server *gin.Engine) { server.GET(ROUTING_PATH_VALUE_BY_DEPLOYMENT, vr.valuesByDeployment) } +// valueById godoc +// +// @Summary get a value of a repository by id +// @Tags values +// @Produce json +// @Param repositoryName path string true "Repository Name" +// @Param valueId path string true "Value ID" +// @Success 200 {object} models.Value +// @Failure 400 {object} models.ApiError +// @Failure 404 {object} models.ApiError +// @Failure 500 {object} models.ApiError +// @Router /repository/{repositoryName}/value/{valueId} [get] func (vr *ValueRouter) valueById(c *gin.Context) { traceId := config.LOGGER.TraceId() @@ -48,6 +60,18 @@ func (vr *ValueRouter) valueById(c *gin.Context) { c.JSON(http.StatusOK, result) } +// valuesByApplication godoc +// +// @Summary get all values of an application by the applications id +// @Tags values +// @Produce json +// @Param repositoryName path string true "Repository Name" +// @Param applicationId path string true "Application ID" +// @Success 200 {array} models.ValueWrapper +// @Failure 400 {object} models.ApiError +// @Failure 404 {object} models.ApiError +// @Failure 500 {object} models.ApiError +// @Router /repository/{repositoryName}/application/values/{applicationId} [get] func (vr *ValueRouter) valuesByApplication(c *gin.Context) { traceId := config.LOGGER.TraceId() @@ -65,6 +89,18 @@ func (vr *ValueRouter) valuesByApplication(c *gin.Context) { c.JSON(http.StatusOK, result) } +// valuesByStage godoc +// +// @Summary get all values of an stage by the stages id +// @Tags values +// @Produce json +// @Param repositoryName path string true "Repository Name" +// @Param stageId path string true "Stage ID" +// @Success 200 {array} models.ValueWrapper +// @Failure 400 {object} models.ApiError +// @Failure 404 {object} models.ApiError +// @Failure 500 {object} models.ApiError +// @Router /repository/{repositoryName}/stage/values/{stageId} [get] func (vr *ValueRouter) valuesByStage(c *gin.Context) { traceId := config.LOGGER.TraceId() @@ -82,6 +118,18 @@ func (vr *ValueRouter) valuesByStage(c *gin.Context) { c.JSON(http.StatusOK, result) } +// valuesByDeployment godoc +// +// @Summary get all values of a deployment by the deployments id +// @Tags values +// @Produce json +// @Param repositoryName path string true "Repository Name" +// @Param deploymentId path string true "Deployment ID" +// @Success 200 {array} models.ValueWrapper +// @Failure 400 {object} models.ApiError +// @Failure 404 {object} models.ApiError +// @Failure 500 {object} models.ApiError +// @Router /repository/{repositoryName}/deployment/values/{deploymentId} [get] func (vr *ValueRouter) valuesByDeployment(c *gin.Context) { traceId := config.LOGGER.TraceId() From f9da2575412cc70691294ff585c085c2f11f1d17 Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Tue, 5 Sep 2023 22:08:52 +0200 Subject: [PATCH 11/14] feat: read values of application --- momentum-core/dev-setup.sh | 9 +++++++++ momentum-core/main.go | 2 +- momentum-core/models/keyvalue.go | 7 ++++++- momentum-core/routers/value-router.go | 15 ++++++++++----- momentum-core/services/value-service.go | 4 ++++ momentum-core/tree/momentum-tree.go | 4 ++++ 6 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 momentum-core/dev-setup.sh diff --git a/momentum-core/dev-setup.sh b/momentum-core/dev-setup.sh new file mode 100644 index 0000000..c237fea --- /dev/null +++ b/momentum-core/dev-setup.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +export MOMENTUM_GIT_USER=Joel-Haeberli +export MOMENTUM_GIT_EMAIL=joel.haeberli@hotmail.com +export MOMENTUM_GIT_TOKEN=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 + +echo "user: $MOMENTUM_GIT_USER" +echo "mail: $MOMENTUM_GIT_EMAIL" +echo "token: $MOMENTUM_GIT_TOKEN" diff --git a/momentum-core/main.go b/momentum-core/main.go index 28ca829..e85d9b5 100644 --- a/momentum-core/main.go +++ b/momentum-core/main.go @@ -17,7 +17,7 @@ import ( // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // -// @schemes http, https +// @schemes http // @host localhost:8080 // @BasePath / func main() { diff --git a/momentum-core/models/keyvalue.go b/momentum-core/models/keyvalue.go index fbdfa34..1f5a011 100644 --- a/momentum-core/models/keyvalue.go +++ b/momentum-core/models/keyvalue.go @@ -78,6 +78,10 @@ func ToValueWrapperFromNode(n *tree.Node, valType ValueType) (*ValueWrapper, err func ToValueFromNode(n *tree.Node) (*Value, error) { + if n == nil { + return nil, errors.New("expected a tree node but was nil") + } + keyValue := new(Value) keyValue.Id = n.Id @@ -85,7 +89,8 @@ func ToValueFromNode(n *tree.Node) (*Value, error) { keyValue.Value = n.Value parentStage := n - for !parentStage.IsStage() { + + for !parentStage.IsStage() && parentStage.Parent != nil { if parentStage.Kind == tree.File { keyValue.ParentDeploymentId = parentStage.Id } diff --git a/momentum-core/routers/value-router.go b/momentum-core/routers/value-router.go index 3605f72..9fd8446 100644 --- a/momentum-core/routers/value-router.go +++ b/momentum-core/routers/value-router.go @@ -11,16 +11,21 @@ import ( const ROUTING_PATH_VALUE_BY_ID = VERSION + "/repository/:repositoryName/value/:valueId" const ROUTING_PATH_VALUE = VERSION + "/value" -const ROUTING_PATH_VALUE_BY_APPLICATION = VERSION + "/:repositoryName/application/values/:applicationId" -const ROUTING_PATH_VALUE_BY_STAGE = VERSION + "/:repositoryName/stage/values/:stageId" -const ROUTING_PATH_VALUE_BY_DEPLOYMENT = VERSION + "/:repositoryName/deployment/values/:deploymentId" +const ROUTING_PATH_VALUE_BY_APPLICATION = VERSION + "/repository/:repositoryName/application/values/:applicationId" +const ROUTING_PATH_VALUE_BY_STAGE = VERSION + "/repository/:repositoryName/stage/values/:stageId" +const ROUTING_PATH_VALUE_BY_DEPLOYMENT = VERSION + "/repository/:repositoryName/deployment/values/:deploymentId" type ValueRouter struct { valueService *services.ValueService } func NewValueRouter(valueService *services.ValueService) *ValueRouter { - return new(ValueRouter) + + vs := new(ValueRouter) + + vs.valueService = valueService + + return vs } func (vr *ValueRouter) RegisterValueRoutes(server *gin.Engine) { @@ -79,7 +84,7 @@ func (vr *ValueRouter) valuesByApplication(c *gin.Context) { repoName := c.Param("repositoryName") applicationId := c.Param("applicationId") - result, err := vr.valueService.ValueById(repoName, applicationId, traceId) + result, err := vr.valueService.ValuesByApplication(repoName, applicationId, traceId) if err != nil { c.JSON(http.StatusNotFound, models.NewApiError(err, http.StatusNotFound, c, traceId)) config.LOGGER.LogError(err.Error(), err, traceId) diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go index ef5d19d..be06ae6 100644 --- a/momentum-core/services/value-service.go +++ b/momentum-core/services/value-service.go @@ -2,6 +2,7 @@ package services import ( "errors" + "fmt" "momentum-core/config" "momentum-core/models" "strings" @@ -41,9 +42,12 @@ func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId return nil, err } + fmt.Println(application) + wrappedValues := make([]*models.ValueWrapper, 0) files := application.Files() for _, f := range files { + fmt.Println("File:", f.NormalizedPath()) if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.APPLICATION) if err != nil { diff --git a/momentum-core/tree/momentum-tree.go b/momentum-core/tree/momentum-tree.go index 3979e6e..5af53a2 100644 --- a/momentum-core/tree/momentum-tree.go +++ b/momentum-core/tree/momentum-tree.go @@ -21,6 +21,10 @@ func (n *Node) MomentumRoot() *Node { func (n *Node) Apps() []*Node { + if n == nil { + return make([]*Node, 0) + } + root := n.MomentumRoot() apps := make([]*Node, 0) for _, app := range root.Directories() { From 8f4307640690c87937ed837140c999a80dc83b17 Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Tue, 5 Sep 2023 22:09:29 +0200 Subject: [PATCH 12/14] Revert "feat: read values of application" This reverts commit f9da2575412cc70691294ff585c085c2f11f1d17. --- momentum-core/dev-setup.sh | 9 --------- momentum-core/main.go | 2 +- momentum-core/models/keyvalue.go | 7 +------ momentum-core/routers/value-router.go | 15 +++++---------- momentum-core/services/value-service.go | 4 ---- momentum-core/tree/momentum-tree.go | 4 ---- 6 files changed, 7 insertions(+), 34 deletions(-) delete mode 100644 momentum-core/dev-setup.sh diff --git a/momentum-core/dev-setup.sh b/momentum-core/dev-setup.sh deleted file mode 100644 index c237fea..0000000 --- a/momentum-core/dev-setup.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -export MOMENTUM_GIT_USER=Joel-Haeberli -export MOMENTUM_GIT_EMAIL=joel.haeberli@hotmail.com -export MOMENTUM_GIT_TOKEN=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 - -echo "user: $MOMENTUM_GIT_USER" -echo "mail: $MOMENTUM_GIT_EMAIL" -echo "token: $MOMENTUM_GIT_TOKEN" diff --git a/momentum-core/main.go b/momentum-core/main.go index e85d9b5..28ca829 100644 --- a/momentum-core/main.go +++ b/momentum-core/main.go @@ -17,7 +17,7 @@ import ( // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // -// @schemes http +// @schemes http, https // @host localhost:8080 // @BasePath / func main() { diff --git a/momentum-core/models/keyvalue.go b/momentum-core/models/keyvalue.go index 1f5a011..fbdfa34 100644 --- a/momentum-core/models/keyvalue.go +++ b/momentum-core/models/keyvalue.go @@ -78,10 +78,6 @@ func ToValueWrapperFromNode(n *tree.Node, valType ValueType) (*ValueWrapper, err func ToValueFromNode(n *tree.Node) (*Value, error) { - if n == nil { - return nil, errors.New("expected a tree node but was nil") - } - keyValue := new(Value) keyValue.Id = n.Id @@ -89,8 +85,7 @@ func ToValueFromNode(n *tree.Node) (*Value, error) { keyValue.Value = n.Value parentStage := n - - for !parentStage.IsStage() && parentStage.Parent != nil { + for !parentStage.IsStage() { if parentStage.Kind == tree.File { keyValue.ParentDeploymentId = parentStage.Id } diff --git a/momentum-core/routers/value-router.go b/momentum-core/routers/value-router.go index 9fd8446..3605f72 100644 --- a/momentum-core/routers/value-router.go +++ b/momentum-core/routers/value-router.go @@ -11,21 +11,16 @@ import ( const ROUTING_PATH_VALUE_BY_ID = VERSION + "/repository/:repositoryName/value/:valueId" const ROUTING_PATH_VALUE = VERSION + "/value" -const ROUTING_PATH_VALUE_BY_APPLICATION = VERSION + "/repository/:repositoryName/application/values/:applicationId" -const ROUTING_PATH_VALUE_BY_STAGE = VERSION + "/repository/:repositoryName/stage/values/:stageId" -const ROUTING_PATH_VALUE_BY_DEPLOYMENT = VERSION + "/repository/:repositoryName/deployment/values/:deploymentId" +const ROUTING_PATH_VALUE_BY_APPLICATION = VERSION + "/:repositoryName/application/values/:applicationId" +const ROUTING_PATH_VALUE_BY_STAGE = VERSION + "/:repositoryName/stage/values/:stageId" +const ROUTING_PATH_VALUE_BY_DEPLOYMENT = VERSION + "/:repositoryName/deployment/values/:deploymentId" type ValueRouter struct { valueService *services.ValueService } func NewValueRouter(valueService *services.ValueService) *ValueRouter { - - vs := new(ValueRouter) - - vs.valueService = valueService - - return vs + return new(ValueRouter) } func (vr *ValueRouter) RegisterValueRoutes(server *gin.Engine) { @@ -84,7 +79,7 @@ func (vr *ValueRouter) valuesByApplication(c *gin.Context) { repoName := c.Param("repositoryName") applicationId := c.Param("applicationId") - result, err := vr.valueService.ValuesByApplication(repoName, applicationId, traceId) + result, err := vr.valueService.ValueById(repoName, applicationId, traceId) if err != nil { c.JSON(http.StatusNotFound, models.NewApiError(err, http.StatusNotFound, c, traceId)) config.LOGGER.LogError(err.Error(), err, traceId) diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go index be06ae6..ef5d19d 100644 --- a/momentum-core/services/value-service.go +++ b/momentum-core/services/value-service.go @@ -2,7 +2,6 @@ package services import ( "errors" - "fmt" "momentum-core/config" "momentum-core/models" "strings" @@ -42,12 +41,9 @@ func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId return nil, err } - fmt.Println(application) - wrappedValues := make([]*models.ValueWrapper, 0) files := application.Files() for _, f := range files { - fmt.Println("File:", f.NormalizedPath()) if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.APPLICATION) if err != nil { diff --git a/momentum-core/tree/momentum-tree.go b/momentum-core/tree/momentum-tree.go index 5af53a2..3979e6e 100644 --- a/momentum-core/tree/momentum-tree.go +++ b/momentum-core/tree/momentum-tree.go @@ -21,10 +21,6 @@ func (n *Node) MomentumRoot() *Node { func (n *Node) Apps() []*Node { - if n == nil { - return make([]*Node, 0) - } - root := n.MomentumRoot() apps := make([]*Node, 0) for _, app := range root.Directories() { From cca3669c70f265896d5eb91be319951b9e7a01ea Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Tue, 5 Sep 2023 22:12:55 +0200 Subject: [PATCH 13/14] feat: read values of application --- momentum-core/models/keyvalue.go | 7 ++++++- momentum-core/routers/value-router.go | 15 ++++++++++----- momentum-core/services/value-service.go | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/momentum-core/models/keyvalue.go b/momentum-core/models/keyvalue.go index fbdfa34..1f5a011 100644 --- a/momentum-core/models/keyvalue.go +++ b/momentum-core/models/keyvalue.go @@ -78,6 +78,10 @@ func ToValueWrapperFromNode(n *tree.Node, valType ValueType) (*ValueWrapper, err func ToValueFromNode(n *tree.Node) (*Value, error) { + if n == nil { + return nil, errors.New("expected a tree node but was nil") + } + keyValue := new(Value) keyValue.Id = n.Id @@ -85,7 +89,8 @@ func ToValueFromNode(n *tree.Node) (*Value, error) { keyValue.Value = n.Value parentStage := n - for !parentStage.IsStage() { + + for !parentStage.IsStage() && parentStage.Parent != nil { if parentStage.Kind == tree.File { keyValue.ParentDeploymentId = parentStage.Id } diff --git a/momentum-core/routers/value-router.go b/momentum-core/routers/value-router.go index 3605f72..9fd8446 100644 --- a/momentum-core/routers/value-router.go +++ b/momentum-core/routers/value-router.go @@ -11,16 +11,21 @@ import ( const ROUTING_PATH_VALUE_BY_ID = VERSION + "/repository/:repositoryName/value/:valueId" const ROUTING_PATH_VALUE = VERSION + "/value" -const ROUTING_PATH_VALUE_BY_APPLICATION = VERSION + "/:repositoryName/application/values/:applicationId" -const ROUTING_PATH_VALUE_BY_STAGE = VERSION + "/:repositoryName/stage/values/:stageId" -const ROUTING_PATH_VALUE_BY_DEPLOYMENT = VERSION + "/:repositoryName/deployment/values/:deploymentId" +const ROUTING_PATH_VALUE_BY_APPLICATION = VERSION + "/repository/:repositoryName/application/values/:applicationId" +const ROUTING_PATH_VALUE_BY_STAGE = VERSION + "/repository/:repositoryName/stage/values/:stageId" +const ROUTING_PATH_VALUE_BY_DEPLOYMENT = VERSION + "/repository/:repositoryName/deployment/values/:deploymentId" type ValueRouter struct { valueService *services.ValueService } func NewValueRouter(valueService *services.ValueService) *ValueRouter { - return new(ValueRouter) + + vs := new(ValueRouter) + + vs.valueService = valueService + + return vs } func (vr *ValueRouter) RegisterValueRoutes(server *gin.Engine) { @@ -79,7 +84,7 @@ func (vr *ValueRouter) valuesByApplication(c *gin.Context) { repoName := c.Param("repositoryName") applicationId := c.Param("applicationId") - result, err := vr.valueService.ValueById(repoName, applicationId, traceId) + result, err := vr.valueService.ValuesByApplication(repoName, applicationId, traceId) if err != nil { c.JSON(http.StatusNotFound, models.NewApiError(err, http.StatusNotFound, c, traceId)) config.LOGGER.LogError(err.Error(), err, traceId) diff --git a/momentum-core/services/value-service.go b/momentum-core/services/value-service.go index ef5d19d..b7ed484 100644 --- a/momentum-core/services/value-service.go +++ b/momentum-core/services/value-service.go @@ -2,6 +2,7 @@ package services import ( "errors" + "fmt" "momentum-core/config" "momentum-core/models" "strings" @@ -44,6 +45,7 @@ func (vs *ValueService) ValuesByApplication(repositoryName string, applicationId wrappedValues := make([]*models.ValueWrapper, 0) files := application.Files() for _, f := range files { + fmt.Println("File:", f.NormalizedPath()) if strings.EqualFold(f.NormalizedPath(), KUSTOMIZATION_FILE_NAME) { wrappedKustomization, err := models.ToValueWrapperFromNode(f, models.APPLICATION) if err != nil { From 5d1185698be5a60f17a2fc92757d35b18c8fbd2a Mon Sep 17 00:00:00 2001 From: Joel-Haeberli Date: Wed, 13 Sep 2023 18:52:22 +0200 Subject: [PATCH 14/14] fix: flat tree preorder --- momentum-core/tree/momentum-tree.go | 13 +++++--- momentum-core/tree/tree.go | 3 ++ momentum-core/tree/yaml-node-factory.go | 41 +++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/momentum-core/tree/momentum-tree.go b/momentum-core/tree/momentum-tree.go index 3979e6e..630b17e 100644 --- a/momentum-core/tree/momentum-tree.go +++ b/momentum-core/tree/momentum-tree.go @@ -121,15 +121,20 @@ func (n *Node) Values() []*Node { return make([]*Node, 0) } - return n.flat(make([]*Node, 0)) + return n.flatPreorder(make([]*Node, 0)) } -func (n *Node) flat(result []*Node) []*Node { +func (n *Node) flatPreorder(result []*Node) []*Node { + + if n == nil { + return result + } + + result = append(result, n) if len(n.Children) > 0 { - result = append(result, n.Children...) for _, child := range n.Children { - result = append(result, child.flat(result)...) + result = child.flatPreorder(result) } } diff --git a/momentum-core/tree/tree.go b/momentum-core/tree/tree.go index 5b16b90..f58a2b3 100644 --- a/momentum-core/tree/tree.go +++ b/momentum-core/tree/tree.go @@ -80,6 +80,9 @@ func (n *Node) Remove() { } } n.Parent.Children = newChilds + + n.Parent.RemoveYamlChild(n.Path) + n.Parent = nil } diff --git a/momentum-core/tree/yaml-node-factory.go b/momentum-core/tree/yaml-node-factory.go index cd9ed12..6521830 100644 --- a/momentum-core/tree/yaml-node-factory.go +++ b/momentum-core/tree/yaml-node-factory.go @@ -2,6 +2,7 @@ package tree import ( "errors" + "momentum-core/utils" "momentum-core/yaml" ) @@ -19,6 +20,46 @@ const ( mergeTag = "!!merge" ) +func (n *Node) RemoveYamlChildren() error { + + errs := make([]error, 0) + for _, chld := range n.Children { + errs = append(errs, chld.RemoveYamlChild(chld.Path)) + } + + return errors.Join(errs...) +} + +func (n *Node) RemoveYamlChild(path string) error { + + updated := make([]*Node, 0) + for _, child := range n.Children { + if child.Path != path { + updated = append(updated, child) + } + + updatedYaml := make([]*yaml.Node, 0) + if child.Path == path { + if child.Parent != nil && child.Parent.YamlNode != nil { + if child.Parent.YamlNode != nil { + for _, yamlChild := range child.Parent.YamlNode.Content { + if yamlChild.Value != utils.LastPartOfPath(path) { + updatedYaml = append(updatedYaml, yamlChild) + } + } + child.Parent.YamlNode.Content = updatedYaml + } + } + } + + return nil + } + + n.Children = updated + + return nil +} + func (n *Node) AddYamlSequence(key string, values []string, style yaml.Style) error { if len(values) < 1 {