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: 8 additions & 0 deletions internal/adapters/secondary/repository/repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"io"
"os"
"path/filepath"
"testing"
"time"

Expand All @@ -27,13 +28,15 @@ func NewMockFileSystem() *MockFileSystem {
}

func (m *MockFileSystem) ReadFile(name string) ([]byte, error) {
name = filepath.ToSlash(name)
if data, ok := m.files[name]; ok {
return data, nil
}
return nil, errors.New("file not found")
}

func (m *MockFileSystem) WriteFile(name string, data []byte, _ os.FileMode) error {
name = filepath.ToSlash(name)
m.files[name] = data
return nil
}
Expand All @@ -43,6 +46,7 @@ func (m *MockFileSystem) MkdirAll(_ string, _ os.FileMode) error {
}

func (m *MockFileSystem) Stat(name string) (os.FileInfo, error) {
name = filepath.ToSlash(name)
if _, ok := m.files[name]; ok {
//nolint:nilnil // Mock for testing
return nil, nil
Expand All @@ -51,6 +55,7 @@ func (m *MockFileSystem) Stat(name string) (os.FileInfo, error) {
}

func (m *MockFileSystem) Remove(name string) error {
name = filepath.ToSlash(name)
delete(m.files, name)
return nil
}
Expand All @@ -60,6 +65,8 @@ func (m *MockFileSystem) RemoveAll(_ string) error {
}

func (m *MockFileSystem) Rename(oldpath, newpath string) error {
oldpath = filepath.ToSlash(oldpath)
newpath = filepath.ToSlash(newpath)
if data, ok := m.files[oldpath]; ok {
m.files[newpath] = data
delete(m.files, oldpath)
Expand All @@ -82,6 +89,7 @@ func (m *MockFileSystem) Create(_ string) (io.WriteCloser, error) {
}

func (m *MockFileSystem) Exists(name string) bool {
name = filepath.ToSlash(name)
_, ok := m.files[name]
return ok
}
Expand Down
3 changes: 3 additions & 0 deletions internal/core/domain/dependency.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ func (p *Dependency) GetURLPrefix() string {

// GetURL returns the full URL for the repository, handling SSH and HTTPS.
func (p *Dependency) GetURL() string {
if strings.HasPrefix(p.Repository, "git@") {
return p.Repository
}
prefix := p.GetURLPrefix()
auth := env.GlobalConfiguration().Auth[prefix]
if auth != nil {
Expand Down
58 changes: 45 additions & 13 deletions internal/core/services/installer/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,55 @@ var (
reHasMultiSlash = regexp.MustCompile(`(?m)([?^/].*)(([?^/]).*)`)
)

// EnsureDependency ensures that the dependencies are added to the package.
func EnsureDependency(pkg *domain.Package, args []string) {
for _, dependency := range args {
dependency = ParseDependency(dependency)
// parseUrlAndVersion parses the dependency URL and version, handling SSH git@ URLs safely.
func parseUrlAndVersion(input string) (url string, version string) {
if strings.HasPrefix(input, "git@") {
// SSH URL format: git@host:owner/repo[.git][:version] or git@host:owner/repo[.git]@version
firstColon := strings.Index(input, ":")
if firstColon == -1 {
return input, ""
}

match := make(map[string]string)
split := reURLVersion.FindStringSubmatch(dependency)
remainder := input[firstColon+1:]

// Look for last colon or @ in remainder to see if a version is specified
lastSep := strings.LastIndexAny(remainder, ":@")
if lastSep != -1 {
possibleVersion := remainder[lastSep+1:]
// Version shouldn't contain slashes (which paths do) and shouldn't be empty
if !strings.Contains(possibleVersion, "/") && possibleVersion != "" {
url = input[:firstColon+1+lastSep]
version = possibleVersion
return url, version
}
}
return input, ""
}

// For standard HTTP/HTTPS/standard paths, use the original regex
match := make(map[string]string)
split := reURLVersion.FindStringSubmatch(input)
if len(split) > 0 {
for i, name := range reURLVersion.SubexpNames() {
if i != 0 && name != "" {
if i != 0 && name != "" && i < len(split) {
match[name] = split[i]
}
}
var ver string
var dep string
dep = match["url"]
if len(match["version"]) == 0 {
}

url = match["url"]
version = match["version"]
return url, version
}

// EnsureDependency ensures that the dependencies are added to the package.
func EnsureDependency(pkg *domain.Package, args []string) {
for _, dependency := range args {
dependency = ParseDependency(dependency)

dep, ver := parseUrlAndVersion(dependency)
if ver == "" {
ver = consts.MinimalDependencyVersion
} else {
ver = match["version"]
}

if strings.HasSuffix(strings.ToLower(dep), ".git") {
Expand All @@ -50,6 +79,9 @@ func EnsureDependency(pkg *domain.Package, args []string) {

// ParseDependency parses the dependency name and returns the full URL if needed.
func ParseDependency(dependencyName string) string {
if strings.HasPrefix(dependencyName, "git@") || strings.HasPrefix(dependencyName, "http://") || strings.HasPrefix(dependencyName, "https://") {
return dependencyName
}
if !reHasSlash.MatchString(dependencyName) {
return "github.com/hashload/" + dependencyName
}
Expand Down
69 changes: 69 additions & 0 deletions internal/core/services/installer/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,72 @@ func TestEnsureDependency_HTTPSUrl(t *testing.T) {
t.Error("Should add dependency for HTTPS URL")
}
}

func TestEnsureDependency_SSHUrl(t *testing.T) {
tests := []struct {
name string
input string
expectedDep string
expectedVer string
}{
{
name: "SSH URL with version tag",
input: "git@github.com:hashload/boss.git:v1.0.0",
expectedDep: "git@github.com:hashload/boss",
expectedVer: "v1.0.0",
},
{
name: "SSH URL without version tag",
input: "git@github.com:hashload/boss.git",
expectedDep: "git@github.com:hashload/boss",
expectedVer: ">0.0.0",
},
{
name: "Self-hosted gitlab SSH URL without version",
input: "git@mygitlab.domain.de:delphi/libraries/mylib.git",
expectedDep: "git@mygitlab.domain.de:delphi/libraries/mylib",
expectedVer: ">0.0.0",
},
{
name: "Self-hosted gitlab SSH URL with version",
input: "git@mygitlab.domain.de:delphi/libraries/mylib.git:1.2.3",
expectedDep: "git@mygitlab.domain.de:delphi/libraries/mylib",
expectedVer: "1.2.3",
},
{
name: "SSH URL with @ version tag",
input: "git@github.com:hashload/boss.git@v2.5.0",
expectedDep: "git@github.com:hashload/boss",
expectedVer: "v2.5.0",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
pkg := &domain.Package{
Dependencies: make(map[string]string),
}

installer.EnsureDependency(pkg, []string{tt.input})

if len(pkg.Dependencies) != 1 {
t.Fatalf("EnsureDependency() did not add exactly 1 dependency for %s, got %d", tt.input, len(pkg.Dependencies))
}

actualVer, exists := pkg.Dependencies[tt.expectedDep]
if !exists {
// Print keys for debugging
var keys []string
for k := range pkg.Dependencies {
keys = append(keys, k)
}
t.Fatalf("Expected dependency %q not found, got keys: %v", tt.expectedDep, keys)
}

if actualVer != tt.expectedVer {
t.Errorf("pkg.Dependencies[%q] = %q, want %q", tt.expectedDep, actualVer, tt.expectedVer)
}
})
}
}

Loading