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
8 changes: 7 additions & 1 deletion cmd/promote/git/app_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"

"github.com/openshift/osdctl/cmd/promote/iexec"
"github.com/openshift/osdctl/cmd/promote/pathutil"
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"

"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -330,7 +331,12 @@ func (a *AppInterface) CommitSaasAndAppYmlFile(saasFile, serviceName, commitMess
}

componentName := strings.TrimPrefix(serviceName, "saas-")
appYmlPath := filepath.Join(a.GitDirectory, "data", "services", componentName, "app.yml")

appYmlPath, err := pathutil.DeriveAppYmlPath(a.GitDirectory, saasFile, componentName)
if err != nil {
return fmt.Errorf("failed to derive app.yml path: %v", err)
}

if err := a.GitExecutor.Run(a.GitDirectory, "git", "add", appYmlPath); err != nil {
return fmt.Errorf("failed to add file %s: %v", appYmlPath, err)
}
Expand Down
23 changes: 22 additions & 1 deletion cmd/promote/git/app_interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,19 @@ func TestCommitSaasAndAppYmlFile(t *testing.T) {
commitMsg: "test hotfix commit",
wantErr: false,
},
{
name: "commits_osd_operator_saas_and_app_yml_successfully",
setupMock: func(m *MockExec, dir, saasFile, serviceName, commitMsg string) {
//osd-operators have the app.yml under osd-operators/<name>/app.yml
appYmlPath := filepath.Join(dir, "data", "services", "osd-operators", "managed-cluster-config", "app.yml")
m.On("Run", dir, "git", []string{"add", saasFile}).Return(nil)
m.On("Run", dir, "git", []string{"add", appYmlPath}).Return(nil)
m.On("Run", dir, "git", []string{"commit", "-m", commitMsg}).Return(nil)
},
serviceName: "saas-managed-cluster-config",
commitMsg: "test hotfix commit for OSD operator",
wantErr: false,
},
{
name: "fails_when_saas_file_add_fails",
setupMock: func(m *MockExec, dir, saasFile, serviceName, commitMsg string) {
Expand Down Expand Up @@ -671,7 +684,15 @@ func TestCommitSaasAndAppYmlFile(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
tmpDir := t.TempDir()
saasFile := filepath.Join(tmpDir, "saas.yaml")
var saasFile string
if tc.serviceName == "saas-managed-cluster-config" {
// osd-operator path structure
saasFile = filepath.Join(tmpDir, "data", "services", "osd-operators", "cicd", "saas", "saas-managed-cluster-config.yaml")
} else {
// Regular path structure
saasFile = filepath.Join(tmpDir, "data", "services", "test-service", "cicd", "saas", "saas-test-service.yaml")
}
_ = os.MkdirAll(filepath.Dir(saasFile), 0o755)
_ = os.WriteFile(saasFile, []byte("dummy content"), 0o600)

mockExec := new(MockExec)
Expand Down
88 changes: 88 additions & 0 deletions cmd/promote/pathutil/pathutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package pathutil

import (
"fmt"
"os"
"path/filepath"
"strings"
)

// DeriveAppYmlPath determines the location of app.yml for a given service.
func DeriveAppYmlPath(gitDirectory, saasFile, componentName string) (string, error) {
derivedPath, err := deriveFromSaasPath(gitDirectory, saasFile, componentName)
if err == nil {
if _, statErr := os.Stat(derivedPath); statErr == nil {
return derivedPath, nil
}
}

// as fallback, searches filesystem for likely loccations
searchedPath, searchErr := searchFilesystem(gitDirectory, componentName)
if searchErr == nil {
return searchedPath, nil
}

if err == nil {
return derivedPath, nil
}

return "", fmt.Errorf("could not determine app.yml path for %s: derive error: %v, search error: %v",
componentName, err, searchErr)
}

// deriveFromSaasPath derives the app.yml path by parsing the saasFile path structure.
func deriveFromSaasPath(gitDirectory, saasFile, componentName string) (string, error) {
// absolute saasFile path into relative path
relPath, err := filepath.Rel(gitDirectory, saasFile)
if err != nil {
return "", fmt.Errorf("failed to get relative path from %s to %s: %v", gitDirectory, saasFile, err)
}

pathParts := strings.Split(relPath, string(filepath.Separator))
var parentServiceDir string

// Find "services" in the path and extract the next component
for i, part := range pathParts {
if part == "services" && i+1 < len(pathParts) {
parentServiceDir = pathParts[i+1]
break
}
}

if parentServiceDir == "" {
return "", fmt.Errorf("invalid saasFile path: 'services' directory not found in %s", relPath)
}

if parentServiceDir != componentName && parentServiceDir != "cicd" {
// Nested structure: data/services/{parent}/{component}/app.yml
return filepath.Join(gitDirectory, "data", "services", parentServiceDir, componentName, "app.yml"), nil
}

// Flat structure; data/services/{component}/app.yml
return filepath.Join(gitDirectory, "data", "services", componentName, "app.yml"), nil
}

// searchFilesystem searches for app.yml in specific "likely" paths
func searchFilesystem(gitDirectory, componentName string) (string, error) {
parentDirs := []string{
"", // services/{component}
"osd-operators", // services/osd-operators/{component}
"backplane", // services/backplane/{component}
"configuration-anomaly-detection",
}

for _, parent := range parentDirs {
var candidatePath string
if parent == "" {
candidatePath = filepath.Join(gitDirectory, "data", "services", componentName, "app.yml")
} else {
candidatePath = filepath.Join(gitDirectory, "data", "services", parent, componentName, "app.yml")
}

if _, err := os.Stat(candidatePath); err == nil {
return candidatePath, nil
}
}

return "", fmt.Errorf("app.yml not found for component %s in any known location", componentName)
}
Loading