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
1 change: 1 addition & 0 deletions AGENTS.md
79 changes: 79 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

`plasmactl-bump` is a launchr plugin to update the version of Ansible roles which were updated in last commit. It detects modified resources (Ansible roles) via git history, bumps their versions, and propagates version changes through dependency chains across the Plasma platform.

**Module**: `github.com/skilld-labs/plasmactl-bump/v2`
**Go version**: 1.25.0 (CGO disabled)
**Framework**: [launchr](https://github.com/launchrctl/launchr) plugin system

## Build & Development Commands

```bash
make build # Build binary to ./bin/launchr
make test # Run all tests (requires gotestfmt)
make test-short # Run short tests only
make lint # Run golangci-lint with auto-fix
make deps # Download Go dependencies
make all # deps + test-short + build
make clean # Remove ./bin/
DEBUG=1 make build # Build with debug symbols
```

## Architecture

### Plugin Registration

The plugin registers via `init()` in `plugin.go`, using `//go:embed` for YAML action definitions. Entry point is `cmd/launchr/main.go` which imports the plugin as a blank import.

### Three Actions

1. **bump** (`actionBump.go`): Detects files changed since the last "Bumper"-authored commit, maps them to resources, and sets each resource's version to the commit's short hash (first 13 chars) in `meta/plasma.yaml`. Creates a commit authored by `Bumper <no-reply@skilld.cloud>`.

2. **bump --sync** (`actionSync.go`, `actionSync.resources.go`, `actionSync.variables.go`): Propagates versions through dependency chains. Works on a post-`compose` build directory (`.compose/build`). Builds a chronological timeline of version changes, then applies propagation so dependent resources get composite versions like `original-propagated`.

3. **dependencies** (`dependencies.go`): Shows dependency tree for a given resource.

### Core Packages

- **`pkg/repository`** (`git.go`): Git operations via `go-git`. `Bumper` struct handles commit traversal, detecting own commits, and creating bump commits. All `PlainOpen` calls use `PlainOpenWithOptions` with `EnableDotGitCommonDir: true` to support git worktrees.

- **`pkg/sync`**: Resource/variable management and dependency resolution.
- `inventory.go`: Builds resource dependency graph by walking filesystem, parsing `tasks/*.yaml` for `include_role` references, topologically sorting with `topsort`.
- `inventory.resource.go`: `Resource` type, `OrderedMap[T]` generic ordered map, MRN (Machine Resource Name) format `platform__kind__role`, version read/write from `meta/plasma.yaml`.
- `inventory.variable.go`: Variable tracking from `group_vars/vars.yaml` and `vault.yaml`, variable-to-variable and variable-to-resource dependency maps.
- `timeline.go`: `TimelineItem` interface with `TimelineResourcesItem` and `TimelineVariablesItem` implementations, chronological sorting.
- `filesCrawler.go`: File discovery with Jinja2 template variable extraction.
- `yaml.go`: YAML parsing with ansible-vault support.

### Key Conventions

- **MRN format**: `platform__kind__role` (double underscore separator), e.g. `interaction__softwares__grafana`
- **Resource path pattern**: `{platform}/{kind}/roles/{role}/meta/plasma.yaml`
- **Valid kinds**: applications, services, softwares, executors, flows, skills, functions, libraries, entities
- **Version format**: Short git hash (`abc1234567890`) or composite `baseversion-propagatedversion`
- **Bump commit author**: `Bumper` with email `no-reply@skilld.cloud`, message `versions bump`

### Sync Flow (Propagation)

1. Initialize inventory from `.compose/build` directory
2. Gather resources from domain (`.`) and packages (`.compose/packages/`)
3. Resolve duplicate resources across namespaces by matching build version
4. Build timeline: find commits where each resource version was set
5. Build propagation map: iterate timeline chronologically, find dependents
6. Update resources: compose `original-propagated` version strings

### Concurrency

Worker goroutines (bounded by `runtime.NumCPU()`) process packages in parallel with mutex-protected shared state. The `sync` stdlib package is imported as `async` to avoid name collision with the `pkg/sync` package.

## Linting

Uses golangci-lint v2 with: dupl (threshold: 100), errcheck, goconst, gosec, govet, ineffassign, revive, staticcheck, unused. Formatter: goimports.

## CI

GitHub Actions workflow (`.github/workflows/commit.yml`) runs four jobs: sync with vault integration, basic bump commands, go-linters, go-tests.
1 change: 1 addition & 0 deletions GEMINI.md
11 changes: 3 additions & 8 deletions actionSync.resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func collectResourcesCommits(r *git.Repository, beforeDate string) (*sync.Ordere
}

func (s *syncAction) findResourcesChangeTime(ctx context.Context, namespaceResources *sync.OrderedMap[*sync.Resource], gitPath string, mx *async.Mutex, p *pterm.ProgressbarPrinter) error {
repo, err := git.PlainOpen(gitPath)
repo, err := git.PlainOpenWithOptions(gitPath, &git.PlainOpenOptions{EnableDotGitCommonDir: true})
if err != nil {
return fmt.Errorf("%s - %w", gitPath, err)
}
Expand All @@ -250,7 +250,7 @@ func (s *syncAction) findResourcesChangeTime(ctx context.Context, namespaceResou
if !ok {
return
}
if err = s.processResource(r, groups, commitsMap, repo, gitPath, mx); err != nil {
if err = s.processResource(r, groups, commitsMap, repo, mx); err != nil {
if p != nil {
_, _ = p.Stop()
}
Expand Down Expand Up @@ -295,12 +295,7 @@ func (s *syncAction) findResourcesChangeTime(ctx context.Context, namespaceResou
return nil
}

func (s *syncAction) processResource(resource *sync.Resource, commitsGroups *sync.OrderedMap[*CommitsGroup], commitsMap map[string]map[string]string, _ *git.Repository, gitPath string, mx *async.Mutex) error {
repo, err := git.PlainOpen(gitPath)
if err != nil {
return fmt.Errorf("%s - %w", gitPath, err)
}

func (s *syncAction) processResource(resource *sync.Resource, commitsGroups *sync.OrderedMap[*CommitsGroup], commitsMap map[string]map[string]string, repo *git.Repository, mx *async.Mutex) error {
buildResource := sync.NewResource(resource.GetName(), s.buildDir)
currentVersion, debug, err := buildResource.GetVersion()
for _, d := range debug {
Expand Down
14 changes: 7 additions & 7 deletions actionSync.variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ func (s *syncAction) populateTimelineVars(buildInv *sync.Inventory) error {
varsFiles = append(varsFiles, paths...)
}

repo, err := git.PlainOpenWithOptions(s.domainDir, &git.PlainOpenOptions{EnableDotGitCommonDir: true})
if err != nil {
return fmt.Errorf("%s - %w", s.domainDir, err)
}

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

Expand All @@ -66,7 +71,7 @@ func (s *syncAction) populateTimelineVars(buildInv *sync.Inventory) error {
if !ok {
return
}
if err = s.findVariableUpdateTime(varsFile, buildInv, s.domainDir, &mx); err != nil {
if err = s.findVariableUpdateTime(varsFile, buildInv, repo, &mx); err != nil {
if p != nil {
_, _ = p.Stop()
}
Expand Down Expand Up @@ -109,12 +114,7 @@ func (s *syncAction) populateTimelineVars(buildInv *sync.Inventory) error {
return nil
}

func (s *syncAction) findVariableUpdateTime(varsFile string, inv *sync.Inventory, gitPath string, mx *async.Mutex) error {
repo, err := git.PlainOpen(gitPath)
if err != nil {
return fmt.Errorf("%s - %w", gitPath, err)
}

func (s *syncAction) findVariableUpdateTime(varsFile string, inv *sync.Inventory, repo *git.Repository, mx *async.Mutex) error {
ref, err := repo.Head()
if err != nil {
return fmt.Errorf("can't get HEAD ref > %w", err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/repository/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type Commit struct {

// NewBumper returns new instance of [Bumper].
func NewBumper() (*Bumper, error) {
r, err := git.PlainOpen("./")
r, err := git.PlainOpenWithOptions("./", &git.PlainOpenOptions{EnableDotGitCommonDir: true})
if err != nil {
return nil, err
}
Expand Down
Loading