Skip to content
Draft
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
49 changes: 38 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,15 @@ test: .install-gotestfmt
echo "$(BOLD)$(RED)🧪 ❌ Some tests failed$(RESET)"
@echo

# Run all tests with race detector
.PHONY: test-race
test-race: .install-gotestfmt
$(call print_step,"Running all tests with race detector...")
@go test -json -race -v ./... | $(GOTESTFMT_BIN) -hide all && \
echo "$(BOLD)$(GREEN)🧪 ✅ All tests passed (race detector clean)$(RESET)" || \
echo "$(BOLD)$(RED)🧪 ❌ Some tests failed$(RESET)"
@echo

# Run short tests
.PHONY: test-short
test-short: .install-gotestfmt
Expand All @@ -119,6 +128,14 @@ test-short: .install-gotestfmt
echo "$(BOLD)$(RED)🧪 ❌ Some short tests failed$(RESET)"
@echo

# Run integration tests keeping work dir for inspection
# Usage: make test-integration [TEST=sync_basic_propagation]
.PHONY: test-integration
test-integration: .install-gotestfmt
$(call print_step,"Running integration tests — keeping work dir...")
@go test -json -v -run "Test(Bump|Sync)$(if $(TEST),/$(TEST),)" ./test/ -args -testwork | $(GOTESTFMT_BIN)
@echo

# Build launchr
.PHONY: build
build:
Expand All @@ -137,6 +154,13 @@ install: all
@cp $(LOCAL_BIN)/launchr $(GOBIN)/launchr
$(call print_success,"🚀 launchr installed to $(GOBIN)/launchr")

# Install launchr without running tests
.PHONY: install-bin
install-bin: deps build
$(call print_step,"Installing launchr to GOPATH...")
@cp $(LOCAL_BIN)/launchr $(GOBIN)/launchr
$(call print_success,"🚀 launchr installed to $(GOBIN)/launchr")

# Install and run linters
.PHONY: lint
lint: .install-lint .lint-fix
Expand Down Expand Up @@ -189,19 +213,22 @@ help:
$(call print_header)
@echo "$(BOLD)$(WHITE)Available targets:$(RESET)"
@echo ""
@echo " $(BOLD)$(GREEN)all$(RESET) 🎯 Run deps, test, and build"
@echo " $(BOLD)$(GREEN)deps$(RESET) 📦 Install go dependencies"
@echo " $(BOLD)$(GREEN)test$(RESET) 🧪 Run all tests"
@echo " $(BOLD)$(GREEN)test-short$(RESET) ⚡ Run short tests only"
@echo " $(BOLD)$(GREEN)build$(RESET) 🔨 Build launchr binary"
@echo " $(BOLD)$(GREEN)install$(RESET) 🚀 Install launchr to GOPATH"
@echo " $(BOLD)$(GREEN)lint$(RESET) 🔍 Run linters with auto-fix"
@echo " $(BOLD)$(GREEN)clean$(RESET) 🧹 Clean build artifacts"
@echo " $(BOLD)$(GREEN)help$(RESET) ❓ Show this help message"
@echo " $(BOLD)$(GREEN)all$(RESET) 🎯 Run deps, test, and build"
@echo " $(BOLD)$(GREEN)deps$(RESET) 📦 Install go dependencies"
@echo " $(BOLD)$(GREEN)test$(RESET) 🧪 Run all tests"
@echo " $(BOLD)$(GREEN)test-race$(RESET) 🏁 Run all tests with race detector"
@echo " $(BOLD)$(GREEN)test-integration$(RESET) 🔬 Run integration tests keeping work dir (TEST=name to filter)"
@echo " $(BOLD)$(GREEN)test-short$(RESET) ⚡ Run short tests only"
@echo " $(BOLD)$(GREEN)build$(RESET) 🔨 Build launchr binary"
@echo " $(BOLD)$(GREEN)install$(RESET) 🚀 Install launchr to GOPATH (with tests)"
@echo " $(BOLD)$(GREEN)install-bin$(RESET) 🚀 Install launchr to GOPATH (without tests)"
@echo " $(BOLD)$(GREEN)lint$(RESET) 🔍 Run linters with auto-fix"
@echo " $(BOLD)$(GREEN)clean$(RESET) 🧹 Clean build artifacts"
@echo " $(BOLD)$(GREEN)help$(RESET) ❓ Show this help message"
@echo ""
@echo "$(BOLD)$(CYAN)Environment variables:$(RESET)"
@echo " $(BOLD)$(YELLOW)DEBUG=1$(RESET) Enable debug build"
@echo " $(BOLD)$(YELLOW)BIN=path$(RESET) Custom binary output path"
@echo " $(BOLD)$(YELLOW)DEBUG=1$(RESET) Enable debug build"
@echo " $(BOLD)$(YELLOW)BIN=path$(RESET) Custom binary output path"
@echo ""

# Default target shows help
Expand Down
36 changes: 14 additions & 22 deletions actionSync.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ var (
const (
vaultpassKey = "vaultpass"
domainNamespace = "domain"
buildHackAuthor = "override"
)

// syncAction is a type representing a resources version synchronization action.
Expand Down Expand Up @@ -60,9 +59,10 @@ type syncAction struct {
}

type hashStruct struct {
hash string
hashTime time.Time
author string
hash string
hashTime time.Time
author string
overridden bool // true = version was manually overridden, not sourced from git
}

// Execute the sync action to propagate resources' versions.
Expand Down Expand Up @@ -192,16 +192,15 @@ func (s *syncAction) getResourcesMaps(buildInv *sync.Inventory) (map[string]*syn
resourcesMap := make(map[string]*sync.OrderedMap[*sync.Resource])
packagePathMap := make(map[string]string)

plasmaCompose, err := compose.Lookup(os.DirFS(s.domainDir))
lock, err := compose.LookupLock(os.DirFS(s.buildDir))
if err != nil {
return nil, nil, err
}

var priorityOrder []string
for _, dep := range plasmaCompose.Dependencies {
pkg := dep.ToPackage(dep.Name)
packagePathMap[dep.Name] = filepath.Join(s.packagesDir, pkg.GetName(), pkg.GetTarget())
priorityOrder = append(priorityOrder, dep.Name)
for _, entry := range lock.Packages {
packagePathMap[entry.Name] = filepath.Join(s.domainDir, entry.Path)
priorityOrder = append(priorityOrder, entry.Name)
}

packagePathMap[domainNamespace] = s.domainDir
Expand Down Expand Up @@ -633,21 +632,14 @@ func (s *syncAction) updateResources(resourceVersionMap map[string]string, toPro
}

func composeVersion(oldVersion string, newVersion string) string {
var version string
if len(strings.Split(newVersion, "-")) > 1 {
version = newVersion
} else {
split := strings.Split(oldVersion, "-")
if len(split) == 1 {
version = fmt.Sprintf("%s-%s", oldVersion, newVersion)
} else if len(split) > 1 {
version = fmt.Sprintf("%s-%s", split[0], newVersion)
} else {
version = newVersion
}
return newVersion
}

return version
split := strings.Split(oldVersion, "-")
if len(split) > 1 {
return fmt.Sprintf("%s-%s", split[0], newVersion)
}
return fmt.Sprintf("%s-%s", oldVersion, newVersion)
}

func (s *syncAction) getResourcesMapFrom(dir string) (*sync.OrderedMap[*sync.Resource], error) {
Expand Down
31 changes: 14 additions & 17 deletions actionSync.resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func (s *syncAction) populateTimelineResources(resources map[string]*sync.Ordere
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// @todo this goroutine-pool pattern (workChan + errorChan + wg + maxWorkers) is duplicated
// 4 times across actionSync.go, actionSync.resources.go, actionSync.variables.go and
// inventory.variable.go. Consider extracting a generic runWorkers[T] helper.
errorChan := make(chan error, 1)
maxWorkers := min(runtime.NumCPU(), len(packagePathMap))
workChan := make(chan map[string]any, len(packagePathMap))
Expand Down Expand Up @@ -236,7 +239,6 @@ func (s *syncAction) findResourcesChangeTime(ctx context.Context, namespaceResou

var wg async.WaitGroup
errorChan := make(chan error, 1)
//maxWorkers := 3
maxWorkers := runtime.NumCPU()
resourcesChan := make(chan *sync.Resource, namespaceResources.Len())

Expand All @@ -250,13 +252,13 @@ func (s *syncAction) findResourcesChangeTime(ctx context.Context, namespaceResou
if !ok {
return
}
if err = s.processResource(r, groups, commitsMap, repo, gitPath, mx); err != nil {
if errR := s.processResource(r, groups, commitsMap, repo, gitPath, mx); errR != nil {
if p != nil {
_, _ = p.Stop()
}

select {
case errorChan <- err:
case errorChan <- errR:
default:
}
}
Expand Down Expand Up @@ -311,9 +313,8 @@ func (s *syncAction) processResource(resource *sync.Resource, commitsGroups *syn
}

versionHash := &hashStruct{
hash: buildHackAuthor,
hashTime: time.Now(),
author: buildHackAuthor,
hashTime: time.Now(),
overridden: true,
}

head, err := repo.Head()
Expand Down Expand Up @@ -346,26 +347,22 @@ func (s *syncAction) processResource(resource *sync.Resource, commitsGroups *syn
// If override is not allowed, return error.
// In other case add new timeline item with overridden version.

overridden := false
if currentVersion != headVersion {
msg := fmt.Sprintf("Version of `%s` doesn't match HEAD commit", resource.GetName())
if !s.allowOverride {
return errors.New(msg)
}

s.Log().Warn(msg)
overridden = true
} else {
versionHash.hash = headCommit.Hash.String()
versionHash.hashTime = headCommit.Author.When
versionHash.author = headCommit.Author.Name
versionHash.overridden = false
}

if !overridden {
// @todo rewrite to concurrent map ?
//mx.Lock()
if !versionHash.overridden {
item, ok := commitsMap[currentVersion]
//mx.Unlock()
if !ok {
s.Log().Warn(fmt.Sprintf("Latest version of `%s` doesn't match any existing commit", resource.GetName()))
}
Expand Down Expand Up @@ -411,7 +408,7 @@ func (s *syncAction) processResource(resource *sync.Resource, commitsGroups *syn
slog.Time("date", versionHash.hashTime),
)

if versionHash.author != repository.Author && versionHash.author != buildHackAuthor {
if !versionHash.overridden && versionHash.author != repository.Author {
s.Log().Warn(fmt.Sprintf("Latest commit of %s is not a bump commit", resource.GetName()))
}

Expand Down Expand Up @@ -551,11 +548,11 @@ func (s *syncAction) processUnknownSection(commitsGroups *sync.OrderedMap[*Commi
if errItem != nil {
// How it's possible to not have meta file in commit before bump ?
// @todo case looks impossible, maybe makes sense to panic here
if errors.Is(err, object.ErrFileNotFound) {
if errors.Is(errItem, object.ErrFileNotFound) {
return nil, errRunBruteProcess
}

return nil, fmt.Errorf("can't hash meta file from commit %s > %w", itemCommit.Hash.String(), err)
return nil, fmt.Errorf("can't hash meta file from commit %s > %w", itemCommit.Hash.String(), errItem)
}

// Hashes don't match, as expected
Expand Down Expand Up @@ -623,11 +620,11 @@ func (s *syncAction) processBumpSection(group *CommitsGroup, resourceMetaPath, c
if errItem != nil {
// How it's possible to not have meta file in commit before bump ?
// @todo case looks impossible, maybe makes sense to panic here
if errors.Is(err, object.ErrFileNotFound) {
if errors.Is(errItem, object.ErrFileNotFound) {
return nil, errRunBruteProcess
}

return nil, fmt.Errorf("can't hash meta file from commit %s - %w", itemCommit.Hash.String(), err)
return nil, fmt.Errorf("can't hash meta file from commit %s - %w", itemCommit.Hash.String(), errItem)
}

// Hashes don't match, as expected
Expand Down
9 changes: 7 additions & 2 deletions actionSync.variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func (s *syncAction) findVariableUpdateTime(varsFile string, inv *sync.Inventory

hashesMap[k].hash = fmt.Sprint(v.GetHash())
hashesMap[k].hashTime = time.Now()
hashesMap[k].author = buildHackAuthor
hashesMap[k].overridden = true
}

varsFileHash := ""
Expand Down Expand Up @@ -193,6 +193,7 @@ func (s *syncAction) findVariableUpdateTime(varsFile string, inv *sync.Inventory
hashesMap[k].hash = danglingCommit.Hash.String()
hashesMap[k].hashTime = danglingCommit.Author.When
hashesMap[k].author = danglingCommit.Author.Name
hashesMap[k].overridden = false
}

danglingCommit = nil
Expand All @@ -203,6 +204,8 @@ func (s *syncAction) findVariableUpdateTime(varsFile string, inv *sync.Inventory
s.Log().Debug(d)
}
if errIt != nil {
// @todo replace strings.Contains checks with sentinel errors or errors.As once
// ansible-vault-go and go-yaml expose typed errors (currently they don't).
if strings.Contains(errIt.Error(), "did not find expected key") ||
strings.Contains(errIt.Error(), "did not find expected comment or line break") ||
strings.Contains(errIt.Error(), "could not find expected") {
Expand Down Expand Up @@ -255,6 +258,7 @@ func (s *syncAction) findVariableUpdateTime(varsFile string, inv *sync.Inventory
hashesMap[k].hash = c.Hash.String()
hashesMap[k].hashTime = c.Author.When
hashesMap[k].author = c.Author.Name
hashesMap[k].overridden = false
}

return nil
Expand All @@ -269,6 +273,7 @@ func (s *syncAction) findVariableUpdateTime(varsFile string, inv *sync.Inventory
hashesMap[k].hash = danglingCommit.Hash.String()
hashesMap[k].hashTime = danglingCommit.Author.When
hashesMap[k].author = danglingCommit.Author.Name
hashesMap[k].overridden = false
}

danglingCommit = nil
Expand All @@ -287,7 +292,7 @@ func (s *syncAction) findVariableUpdateTime(varsFile string, inv *sync.Inventory
slog.String("path", v.GetPath()),
)

if hm.author == buildHackAuthor {
if hm.overridden {
msg := fmt.Sprintf("Value of `%s` doesn't match HEAD commit", n)
if !s.allowOverride {
return errors.New(msg)
Expand Down
Loading
Loading