Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions cmd/promote/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"fmt"

"github.com/openshift/osdctl/cmd/promote/dynatrace"
"github.com/openshift/osdctl/cmd/promote/pko"
"github.com/openshift/osdctl/cmd/promote/managedscripts"
"github.com/openshift/osdctl/cmd/promote/saas"
"github.com/spf13/cobra"
)
Expand All @@ -19,8 +19,8 @@ func NewCmdPromote() *cobra.Command {
}

promoteCmd.AddCommand(saas.NewCmdSaas())
promoteCmd.AddCommand(pko.NewCmdPKO())
promoteCmd.AddCommand(dynatrace.NewCmdDynatrace())
promoteCmd.AddCommand(managedscripts.NewCmdManagedScripts())

return promoteCmd
}
Expand Down
213 changes: 41 additions & 172 deletions cmd/promote/dynatrace/dt_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import (
"sort"
"strings"

"github.com/openshift/osdctl/cmd/promote/git"
"github.com/openshift/osdctl/cmd/promote/iexec"
"gopkg.in/yaml.v3"
"github.com/openshift/osdctl/cmd/promote/utils"

kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
)

const (
Expand All @@ -22,203 +23,73 @@ const (
)

var (
ServicesSlice []string
ServicesFilesMap = map[string]string{}
ModulesSlice []string
ModulesFilesMap = map[string]string{}
ModulesSlice []string
ModulesFilesMap = map[string]string{}
)

func listServiceNames(appInterface git.AppInterface) error {
_, err := GetServiceNames(appInterface, saasDynatraceDir)
if err != nil {
return err
}

sort.Strings(ServicesSlice)
fmt.Println("### Available Dynatrace components ###")
fmt.Println()

// Find the longest service name for alignment
maxLen := 0
for _, service := range ServicesSlice {
if len(service) > maxLen {
maxLen = len(service)
}
}

for _, service := range ServicesSlice {
// Read the service YAML file to extract the path
saasDir, err := GetSaasDir(service)
if err != nil {
fmt.Printf("%-*s (unable to read config)\n", maxLen, service)
continue
}

serviceData, err := os.ReadFile(saasDir)
if err != nil {
fmt.Printf("%-*s (unable to read config)\n", maxLen, service)
continue
}

// Extract the path by parsing the YAML directly
serviceFullPath := extractPathFromServiceYAML(serviceData)

// Display service name with its path
if serviceFullPath != "" {
fmt.Printf("%-*s → %s\n", maxLen, service, serviceFullPath)
} else {
fmt.Printf("%-*s (no specific path)\n", maxLen, service)
}
func validateDynatraceServiceFilePath(filePath string) string {
if !strings.HasSuffix(filePath, ".yaml") {
return ""
}

return nil
return filePath
}

// extractPathFromServiceYAML extracts all unique path fields from resourceTemplates
func extractPathFromServiceYAML(yamlData []byte) string {
var service struct {
ResourceTemplates []struct {
PATH string `yaml:"path"`
} `yaml:"resourceTemplates"`
}

err := yaml.Unmarshal(yamlData, &service)
func getResourceTemplatesPaths(serviceRegistry *utils.ServicesRegistry, serviceId string) string {
service, err := serviceRegistry.GetService(serviceId)
if err != nil {
return ""
}

pathSet := make(map[string]bool)
for _, rt := range service.ResourceTemplates {
if rt.PATH != "" {
pathSet[rt.PATH] = true
}
}

var paths []string
for path := range pathSet {
paths = append(paths, path)
}
sort.Strings(paths)

return strings.Join(paths, ", ")
}

func servicePromotion(appInterface git.AppInterface, component, gitHash string) error {

_, err := GetServiceNames(appInterface, saasDynatraceDir)
if err != nil {
return err
}

component, err = ValidateServiceName(ServicesSlice, component)
if err != nil {
return err
}

saasDir, err := GetSaasDir(component)
if err != nil {
return err
}
fmt.Printf("SAAS Directory: %v\n", saasDir)

serviceData, err := os.ReadFile(saasDir)
if err != nil {
return fmt.Errorf("failed to read SAAS file: %v", err)
}

currentGitHash, serviceRepo, serviceFullPath, err := git.GetCurrentGitHashAndPathFromAppInterface(serviceData, component, "")
if err != nil {
return fmt.Errorf("failed to get current git hash or service repo: %v", err)
}

fmt.Printf("Current Git Hash: %v\nGit Repo: %v\nComponent path: %v\n", currentGitHash, serviceRepo, serviceFullPath)

promotionGitHash, commitLog, err := git.CheckoutAndCompareGitHash(appInterface.GitExecutor, serviceRepo, gitHash, currentGitHash, strings.TrimPrefix(serviceFullPath, "/"))
if err != nil {
return fmt.Errorf("failed to checkout and compare git hash: %v", err)
} else if promotionGitHash == "" {
fmt.Printf("Unable to find a git hash to promote. Exiting.\n")
os.Exit(6)
}

fmt.Printf("Service: %s will be promoted to %s\n", component, promotionGitHash)
fmt.Printf("commitLog: %v\n", commitLog)

branchName := fmt.Sprintf("promote-%s-%s", component, promotionGitHash)

err = appInterface.UpdateAppInterface(component, saasDir, currentGitHash, promotionGitHash, branchName, false)
if err != nil {
fmt.Printf("FAILURE: %v\n", err)
}

commitMessage := fmt.Sprintf("Promote %s to %s\n\nSee %s/compare/%s...%s for contents of the promotion.\n clog:%s", component, promotionGitHash, serviceRepo, currentGitHash, promotionGitHash, commitLog)

fmt.Printf("commitMessage: %s\n", commitMessage)
err = service.GetResourceTemplatesSequenceNode().VisitElements(func(resourceTemplateNode *kyaml.RNode) error {
path, err := resourceTemplateNode.GetString("path")
if err != nil || path == "" {
return nil
}

err = appInterface.CommitSaasFile(saasDir, commitMessage)
paths = append(paths, path)
return nil
})
if err != nil {
return fmt.Errorf("failed to commit changes to app-interface; manual commit may still succeed: %w", err)
return ""
}

fmt.Printf("The branch %s is ready to be pushed\n", branchName)
fmt.Println("")
fmt.Println("DT service:", component)
fmt.Println("from:", currentGitHash)
fmt.Println("to:", promotionGitHash)
fmt.Println("READY TO PUSH,", component, "promotion commit is ready locally")
return nil
return strings.Join(paths, ", ")
}

func GetServiceNames(appInterface git.AppInterface, saaDirs ...string) ([]string, error) {
baseDir := appInterface.GitDirectory
func listServiceIds(serviceRegistry *utils.ServicesRegistry) error {
serviceIds := serviceRegistry.GetServicesIds()

for _, dir := range saaDirs {
dirGlob := filepath.Join(baseDir, dir)
filepaths, err := filepath.Glob(dirGlob + "/*.yaml")
if err != nil {
return nil, err
}
fmt.Println("### Available Dynatrace components ###")

for _, filepath := range filepaths {
filename := strings.TrimPrefix(filepath, baseDir+"/"+dir+"/")
filename = strings.TrimSuffix(filename, ".yaml")
ServicesSlice = append(ServicesSlice, filename)
ServicesFilesMap[filename] = filepath
// Find the longest service name for alignment
maxLen := 0
for _, serviceId := range serviceIds {
if len(serviceId) > maxLen {
maxLen = len(serviceId)
}
}

return ServicesSlice, nil
}
for _, serviceId := range serviceIds {
// Extract the path by parsing the YAML directly
resourcesTemplatesPaths := getResourceTemplatesPaths(serviceRegistry, serviceId)

func ValidateServiceName(serviceSlice []string, serviceName string) (string, error) {
fmt.Printf("### Checking if service %s exists ###\n", serviceName)
for _, service := range serviceSlice {
if service == serviceName {
fmt.Printf("Service %s found\n", serviceName)
return serviceName, nil
}
if service == "dynatrace-"+serviceName {
fmt.Printf("Service %s found\n", serviceName)
return "dynatrace-" + serviceName, nil
// Display service name with its path
if resourcesTemplatesPaths != "" {
fmt.Printf("%-*s → %s\n", maxLen, serviceId, resourcesTemplatesPaths)
} else {
fmt.Printf("%-*s (no specific path)\n", maxLen, serviceId)
}
}

return serviceName, fmt.Errorf("service %s not found", serviceName)
}

func GetSaasDir(component string) (string, error) {
if saasDir, ok := ServicesFilesMap[component]; ok {
if strings.Contains(saasDir, ".yaml") {
return saasDir, nil
}
}
return "", fmt.Errorf("saas directory for service %s not found", component)
return nil
}

func listDynatraceModuleNames(dynatraceConfig DynatraceConfig) error {

baseDir := dynatraceConfig.GitDirectory
_, err := GeModulesNames(baseDir, moduleDir)
_, err := GetModulesNames(baseDir, moduleDir)
if err != nil {
return err
}
Expand All @@ -232,8 +103,7 @@ func listDynatraceModuleNames(dynatraceConfig DynatraceConfig) error {
return nil
}

func GeModulesNames(baseDir, dir string) ([]string, error) {

func GetModulesNames(baseDir, dir string) ([]string, error) {
dirGlob := filepath.Join(baseDir, dir)
filepaths, err := os.ReadDir(dirGlob)

Expand Down Expand Up @@ -337,10 +207,9 @@ func getLatestGitHash(basedir, module string) (string, error) {
}

func modulePromotion(dynatraceConfig DynatraceConfig, module string) error {

baseDir := dynatraceConfig.GitDirectory

_, err := GeModulesNames(baseDir, moduleDir)
_, err := GetModulesNames(baseDir, moduleDir)
if err != nil {
return err
}
Expand Down
Loading