This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Nexus CLI is a Go-based command-line tool for automating the management of Sonatype Nexus Repository Manager 3.x. It enables declarative configuration of users, repositories, roles, and permissions through YAML files.
# Build the binary
make build
# Run tests
make test
# Format code
make fmt
# Lint code
make vet
# Build for all platforms
make build-all
# Clean build artifacts
make cleanThe codebase follows a strict layered architecture with clear separation of concerns:
-
cmd/ - CLI interface layer using Cobra
root.go- Root command with global flagsapply.go- Main command for applying YAML configurationsversion.go- Version information command
-
pkg/nexus/ - HTTP API client layer
client.go- Base HTTP client with Basic Authuser.go,repository.go,role.go,privilege.go- Resource-specific API methods- Each file handles CRUD operations for one resource type
-
pkg/service/ - Business logic layer
apply.go- Orchestrates the application of configurations- Implements idempotent operations (safe to re-run)
- Handles the order of operations (privileges → roles → repositories → users → permissions)
-
pkg/config/ - Configuration management layer
types.go- All YAML configuration structuresloader.go- YAML parsing and environment variable handling
-
pkg/output/ - Output formatting layer
formatter.go- Multiple output formats (text, JSON, YAML, template)templates.go- Predefined output templates
Critical: Nexus admin credentials are NEVER stored in YAML files. They must be provided via environment variables:
export NEXUS_URL=http://localhost:8081
export NEXUS_USERNAME=admin
export NEXUS_PASSWORD=admin123YAML files only contain the resources to be created (users, repos, etc.), not authentication credentials.
The tool supports a hierarchical permission model:
-
Nexus Admin (uses system admin creds) → Creates Team Admins
- Config:
config/team-admin.yaml - Creates roles with user/role management permissions
- Config:
-
Team Admin (uses team admin creds) → Creates Repo Managers
- Config:
config/team-repo-manager.yaml - Creates roles with repository management permissions
- Config:
-
Repo Manager (uses repo manager creds) → Creates Repositories
- Config:
config/team-repositories.yaml - Creates actual repositories and assigns permissions
- Config:
Each tier uses different credentials via environment variables.
- Maven (maven2): hosted, proxy, group
- Docker: hosted, proxy, group
- NPM: hosted, proxy, group
- Python (pypi): hosted, proxy, group
- Go: proxy, group only (no hosted type supported by Nexus)
All apply operations are idempotent:
- Before creating, check if resource exists
- If exists, either skip or update (depending on resource type)
- Users and roles are updated; repositories are skipped
- Safe to run the same config multiple times
The service layer applies resources in a specific order to satisfy dependencies:
- Privileges (independent)
- Roles (depend on privileges)
- Repositories (independent)
- Users (depend on roles)
- User-Repository Permissions (depend on users and repositories)
This order is critical and should not be changed.
- Use
fmt.Errorfwith%wto wrap errors and preserve error chains - Return detailed context in error messages (e.g., "failed to create user %s: %w")
- The apply command stops on first error to prevent partial configurations
All config files follow this structure:
users: [] # User definitions
repositories: [] # Repository definitions
privileges: [] # Custom privileges
roles: [] # Custom roles
userRepositoryPermissions: [] # User-to-repo permission mappingsconfig/example.yaml- Complete reference exampleconfig/team-*.yaml- Three-tier workflow examplesconfig/repository-manager.yaml- Repository admin setup
Templates (in templates/) define how created resources are reported:
users: |
{{- range . }}
- userId: {{ .UserID }}
email: {{ .EmailAddress }}
{{- end }}Templates are pure Go templates operating on resource lists.
Tests use table-driven patterns:
tests := []struct {
name string
input SomeType
want ExpectedType
wantErr bool
}{
// test cases
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// test logic
})
}When adding new Nexus API methods, add corresponding tests in *_test.go files.
To add support for a new repository format (e.g., Helm):
-
Add API methods in
pkg/nexus/repository.go:func (c *Client) CreateHelmHostedRepository(req RepositoryRequest) error func (c *Client) CreateHelmProxyRepository(req RepositoryRequest) error
-
Add case in
pkg/service/apply.gocreateRepository():case "helm": switch repo.Type { case "hosted": return s.client.CreateHelmHostedRepository(req) // ... }
-
Update config types in
pkg/config/types.goif format needs specific config -
Update documentation in README.md
- Go repository limitation: Nexus Go repositories only support proxy/group, not hosted
- Write policies: Only apply to hosted repositories, not proxy/group
- Role updates: When updating roles, ALL privileges must be specified (not incremental)
- User password changes: Require a separate API call to
ChangePassword() - Repository URLs: Generated by Nexus, not configurable in request
GitHub Actions workflows in .github/workflows/:
ci.yml- Runs on PR: lint, test, buildrelease.yml- Runs on tag: multi-platform build and GitHub release
Version info is injected at build time via ldflags in Makefile.
The CLI supports customizable output templates for displaying created resources after apply command execution.
Location: cmd/apply.go
New Flags:
--output-template <file>: Path to template file (YAML format with Go text/template syntax)--output-file <file>: Optional file to write output (defaults to stdout)
Template Structure (see templates/ directory):
users: |
{{- range . }}
- userId: {{ .UserID }}
...
{{- end }}
repositories: |
{{- range . }}
- name: {{ .Name }}
...
{{- end }}
roles: |
{{- range . }}
- id: {{ .ID }}
...
{{- end }}
privileges: |
{{- range . }}
- name: {{ .Name }}
...
{{- end }}Data Structures:
- Users:
[]*nexus.UserResponse- from API - Repositories:
[]RepositoryOutput- custom struct (API returnsmap[string]interface{}) - Roles:
[]*nexus.RoleResponse- from API - Privileges:
[]*nexus.PrivilegeResponse- from API
How It Works:
- After successful apply, if
--output-templateis specified - Load template file and parse YAML to get 4 section templates
- Fetch each resource from Nexus API (only resources in config file)
- Render each template section with corresponding data
- Output to file or stdout
Key Functions:
outputResources(): Main orchestratorrenderTemplate(): Renders single template with datagetString(),getBool(): Extract values from repository map
Problem: Multiple compilation errors in pkg/service/apply.go
Errors Fixed:
- Function signature mismatch: All
apply*()functions changed from returningerrorto(int, error)for counting - Missing formatter: Replaced all
log.Printf()calls withs.formatter.Info/Success/Warning() - Counting logic: Added proper resource counting in each apply function
- Return values: Updated
Apply()to collect counts properly inApplyResult
Files Modified:
pkg/service/apply.go: Complete rewrite of all apply functions (433 lines)cmd/apply.go: Added output template feature (324 lines)
Template Files (already existed):
templates/resource-list.yaml: Standard formattemplates/simple.yaml: Names onlytemplates/detailed.yaml: All fieldstemplates/README.md: Comprehensive usage guide
# Apply and show resources with standard template
nexus-cli apply -c config.yaml --output-template templates/resource-list.yaml
# Apply and save resources to file
nexus-cli apply -c config.yaml \
--output-template templates/simple.yaml \
--output-file created-resources.yaml
# Apply only (no resource output)
nexus-cli apply -c config.yaml