Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 117 additions & 32 deletions artifactory/commands/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/jfrog/gofrog/version"
"github.com/jfrog/jfrog-client-go/utils/log"
"strconv"
"strings"

Expand All @@ -19,7 +21,8 @@ import (
const (
// The actual field in the repository configuration is an array (plural) but in practice only one environment is allowed.
// This is why the question differs from the repository configuration.
environmentsKey = "environments"
environmentsKey = "environments"
singleRepoCreateEntity = 1
)

type RepoCommand struct {
Expand All @@ -36,51 +39,133 @@ func (rc *RepoCommand) TemplatePath() string {
return rc.templatePath
}

type repoCreateHandler interface {
Execute(repoConfigMaps []map[string]interface{}, servicesManager artifactory.ArtifactoryServicesManager, isUpdate bool) error
}

type (
MultipleRepositoryHandler struct{}
SingleRepositoryHandler struct{}
)

func (rc *RepoCommand) PerformRepoCmd(isUpdate bool) (err error) {
repoConfigMap, err := utils.ConvertTemplateToMap(rc)
repoConfigMaps, err := utils.ConvertTemplateToMaps(rc)
if err != nil {
return err
}

var missingKeys []string
for _, config := range repoConfigMaps {
if key, ok := config["key"]; !ok || key == "" {
missingKeys = append(missingKeys, fmt.Sprintf("%v\n", config))
}
}

if len(missingKeys) > 0 {
return fmt.Errorf("'key' is missing in the following configs\n: %v", missingKeys)
}

servicesManager, err := rtUtils.CreateServiceManager(rc.serverDetails, -1, 0, false)
if err != nil {
return err
}

var strategy repoCreateHandler
if len(repoConfigMaps) > singleRepoCreateEntity {
strategy = &MultipleRepositoryHandler{}
} else {
strategy = &SingleRepositoryHandler{}
}

err = strategy.Execute(repoConfigMaps, servicesManager, isUpdate)
if err != nil {
return err
}

return nil
}

func (m *MultipleRepositoryHandler) Execute(repoConfigMaps []map[string]interface{}, servicesManager artifactory.ArtifactoryServicesManager, isUpdate bool) error {
content, err := json.Marshal(repoConfigMaps)
if err != nil {
return err
}
// All the values in the template are strings
return multipleRepoHandler(servicesManager, content, isUpdate)
}

func (s *SingleRepositoryHandler) Execute(repoConfigMaps []map[string]interface{}, servicesManager artifactory.ArtifactoryServicesManager, isUpdate bool) error {
// Go over the confMap and write the values with the correct type using the writersMap
for key, value := range repoConfigMap {
if err = utils.ValidateMapEntry(key, value, writersMap); err != nil {
return
for _, repoConfigMap := range repoConfigMaps {
for key, value := range repoConfigMap {
if err := utils.ValidateMapEntry(key, value, writersMap); err != nil {
return err
}
if err := writersMap[key](&repoConfigMap, key, fmt.Sprint(value)); err != nil {
return err
}
}
if err = writersMap[key](&repoConfigMap, key, fmt.Sprint(value)); err != nil {
return

content, err := json.Marshal(repoConfigMap)
if err != nil {
return err
}

// Rclass and packageType are mandatory keys in our templates
// Using their values we'll pick the suitable handler from one of the handler maps to create/update a repository
var handlerFunc func(servicesManager artifactory.ArtifactoryServicesManager, jsonConfig []byte, isUpdate bool) error
packageType := fmt.Sprint(repoConfigMap[PackageType])
switch repoConfigMap[Rclass] {
case Local:
handlerFunc = localRepoHandlers[packageType]
case Remote:
handlerFunc = remoteRepoHandlers[packageType]
case Virtual:
handlerFunc = virtualRepoHandlers[packageType]
case Federated:
handlerFunc = federatedRepoHandlers[packageType]
default:
return errorutils.CheckErrorf("unsupported rclass: %s", repoConfigMap[Rclass])
}
if handlerFunc == nil {
return errors.New("unsupported package type: " + packageType)
}

if err := handlerFunc(servicesManager, content, isUpdate); err != nil {
return err
}
}
// Write a JSON with the correct values
content, err := json.Marshal(repoConfigMap)
return nil
}

func multipleRepoHandler(servicesManager artifactory.ArtifactoryServicesManager, jsonConfig []byte, isUpdate bool) (err error) {
artifactoryVersion, err := servicesManager.GetVersion()
if err != nil {
return err
return errorutils.CheckErrorf("failed to get Artifactory rtVersion: %v", err)
}
rtVersion := version.NewVersion(artifactoryVersion)
if isUpdate {
if !rtVersion.AtLeast("7.104.2") {
return errorutils.CheckErrorf("bulk repository updation is supported from Artifactory rtVersion 7.104.2, current rtVersion: %v", artifactoryVersion)
}
} else {
if !rtVersion.AtLeast("7.84.3") {
return errorutils.CheckErrorf("bulk repository creation is supported from Artifactory rtVersion 7.84.3, current rtVersion: %v", artifactoryVersion)
}
}

servicesManager, err := rtUtils.CreateServiceManager(rc.serverDetails, -1, 0, false)
log.Info("creating/updating repositories in batch...")

err = servicesManager.CreateUpdateRepositoriesInBatch(jsonConfig, isUpdate)
if err != nil {
return err
}
// Rclass and packageType are mandatory keys in our templates
// Using their values we'll pick the suitable handler from one of the handler maps to create/update a repository
var handlerFunc func(servicesManager artifactory.ArtifactoryServicesManager, jsonConfig []byte, isUpdate bool) error
packageType := fmt.Sprint(repoConfigMap[PackageType])
switch repoConfigMap[Rclass] {
case Local:
handlerFunc = localRepoHandlers[packageType]
case Remote:
handlerFunc = remoteRepoHandlers[packageType]
case Virtual:
handlerFunc = virtualRepoHandlers[packageType]
case Federated:
handlerFunc = federatedRepoHandlers[packageType]
default:
return errorutils.CheckErrorf("unsupported rclass: %s", repoConfigMap[Rclass])
}
if handlerFunc == nil {
return errors.New("unsupported package type: " + packageType)
}
return handlerFunc(servicesManager, content, isUpdate)

if isUpdate {
log.Info("Successfully updated the repositories")
} else {
log.Info("Successfully created the repositories")
}
return nil
}

var writersMap = map[string]ioutils.AnswerWriter{
Expand Down
Loading
Loading