Skip to content

Add CLI tool and release automation#8

Merged
pfrederiksen merged 6 commits intomainfrom
feat/cli-and-release
Jan 16, 2026
Merged

Add CLI tool and release automation#8
pfrederiksen merged 6 commits intomainfrom
feat/cli-and-release

Conversation

@pfrederiksen
Copy link
Owner

Summary

Adds a full-featured CLI with stdin/stdout support and GoReleaser-based release automation with Homebrew tap integration.

CLI Implementation

New Packages

  • cmd/configdiff: CLI entry point with Cobra framework

    • main.go: Entry point with version vars for ldflags
    • root.go: Root command with all flags
    • version.go: Version command with build info
    • compare.go: Main comparison logic
  • internal/cli: CLI support functions

    • input.go: File/stdin reading, format auto-detection
    • output.go: Output formatting (report/compact/json/patch)
    • options.go: CLI flags → library options mapping

CLI Features

# Basic comparison
configdiff old.yaml new.yaml

# Stdin support
kubectl get deploy myapp -o yaml | configdiff old.yaml -

# Output formats
configdiff old.yaml new.yaml -o compact
configdiff old.yaml new.yaml -o json
configdiff old.yaml new.yaml -o patch

# Advanced options
configdiff old.yaml new.yaml -i /metadata/generation -i /status/*
configdiff old.yaml new.yaml --array-key /spec/containers=name
configdiff old.yaml new.yaml --numeric-strings --bool-strings

# CI mode
configdiff old.yaml new.yaml --exit-code  # Exit 1 if diffs found

Release Automation

GoReleaser Configuration (.goreleaser.yml)

  • Cross-platform builds: Linux, macOS, Windows (amd64, arm64, arm)
  • Version info injection via ldflags (version, commit, date, builtBy)
  • Archive generation with documentation
  • Automatic Homebrew formula updates to pfrederiksen/homebrew-tap
  • Smart changelog generation from conventional commits

Release Workflow (.github/workflows/release.yml)

  • Triggers on version tags (v*)
  • Runs full test suite before release
  • Uses GoReleaser action for build and publish
  • Uploads release artifacts
  • Updates Homebrew tap automatically

CI Updates

  • Added CLI binary build to existing CI workflow
  • Ensures CLI compiles on all PRs

Dependencies

  • github.com/spf13/cobra v1.10.2 - Industry standard CLI framework
  • github.com/fatih/color v1.18.0 - Colored output support

Installation (After v0.1.0 Release)

# Homebrew (macOS/Linux)
brew install pfrederiksen/tap/configdiff

# Direct download
# Available on GitHub releases page with binaries for all platforms

Testing Done

✅ CLI compiles and runs
✅ Basic file comparison works
✅ Stdin support works (cat file | configdiff - file2)
✅ All output formats work (report, compact, json, patch)
✅ Exit code mode works correctly
✅ All flags parse correctly
✅ GoReleaser config validates locally
✅ Homebrew tap token configured

Next Steps

  1. Merge this PR
  2. Create v0.1.0 tag to trigger first release
  3. Verify Homebrew formula is auto-generated
  4. Update README with CLI installation and usage

Versioning

First release will be v0.1.0 (pre-1.0 initial release).

Breaking Changes

None - library API unchanged, CLI is a new addition.

🤖 Generated with Claude Code

pfrederiksen and others added 4 commits January 16, 2026 15:20
Implements a full-featured CLI with stdin/stdout support and GoReleaser-based
release automation with Homebrew tap integration.

## CLI Implementation

- Add cmd/configdiff with main.go, root.go, version.go, compare.go
- Add internal/cli package:
  - input.go: File/stdin reading, format detection
  - output.go: Output formatting (report, compact, json, patch)
  - options.go: CLI flags to library options mapping
- Support all library features via flags
- Stdin support with "-" notation
- Exit code mode for CI integration
- Version command with build info

## CLI Features

- File comparison: configdiff old.yaml new.yaml
- Stdin input: kubectl get -o yaml | configdiff old.yaml -
- Output formats: report (default), compact, json, patch
- All diff options: ignore paths, array keys, coercions
- Exit code mode: --exit-code returns 1 if diffs found
- Quiet mode: -q suppresses output

## Release Automation

- Add .goreleaser.yml:
  - Cross-platform builds (Linux, macOS, Windows on amd64/arm64)
  - Version info injection via ldflags
  - Automatic Homebrew formula updates
  - Archive generation with README, LICENSE
- Add .github/workflows/release.yml:
  - Triggers on version tags (v*)
  - Runs tests before release
  - Uses GoReleaser action
  - Requires HOMEBREW_TAP_GITHUB_TOKEN secret
- Update CI workflow to build CLI binary

## Dependencies

- github.com/spf13/cobra v1.10.2 - CLI framework
- github.com/fatih/color v1.18.0 - Colored output (future use)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add CLI installation section (Homebrew + direct download)
- Add CLI quick start examples
- Add CLI reference with all flags documented
- Add output formats explanation
- Add exit codes reference
- Reorganize Quick Start into CLI and Library sections

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add internal/cli/input_test.go: File/stdin reading, format detection tests
- Add internal/cli/options_test.go: Options parsing and validation tests
- Add internal/cli/output_test.go: Output formatting tests
- Add cmd/configdiff/main_test.go: Basic integration tests

Coverage improved from 68.8% to 83.9%, exceeding 80% threshold.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Jan 16, 2026

Code Review

Missing Test Coverage

This PR adds substantial new CLI code without corresponding test files, which violates the project's CLAUDE.md requirements:

Test-Driven Development: Comprehensive test coverage with unit, integration, and golden tests

Affected files without tests:

  • internal/cli/input.go (94 lines) - view code
  • internal/cli/options.go (107 lines) - view code
  • internal/cli/output.go (57 lines) - view code
  • cmd/configdiff/compare.go (85 lines) - view code
  • cmd/configdiff/root.go (101 lines) - view code
  • cmd/configdiff/version.go (22 lines) - view code

What needs tests:

  1. internal/cli/input.go: Test ReadInput() and format detection

    • File reading vs stdin
    • Format detection from extensions (.yaml, .json, .hcl, .tf)
    • Content-based detection (JSON objects/arrays, YAML fallback)
    • Error cases (missing files, invalid data)
  2. internal/cli/options.go: Test option parsing and validation

    • Validate() with various invalid inputs
    • ToLibraryOptions() conversion logic
    • Array key parsing (path=key format, path normalization)
    • Format override logic
  3. internal/cli/output.go: Test output formatting

    • All output formats (report, compact, json, patch)
    • HasChanges() logic
    • NoColor and MaxValueLength options
  4. cmd/configdiff/compare.go: Integration tests for the compare flow

    • End-to-end comparisons with different options
    • Error handling
    • Exit code behavior

The existing codebase demonstrates this standard - every other package has comprehensive test coverage. Consider following the project's table-driven test pattern (see parse/parse_test.go, diff/diff_test.go).

@claude
Copy link

claude bot commented Jan 16, 2026

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

Expand Use Cases section with concrete examples:
- Kubernetes deployment reviews with kubectl integration
- GitOps PR validation with exit codes
- Infrastructure drift detection with Terraform
- Configuration management across environments
- CI/CD integration with GitHub Actions examples
- Docker Compose migration scenarios

Includes practical commands and CI/CD workflow examples.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Jan 16, 2026

Code Review - Issue Found

Silent Error Handling Bug in cmd/configdiff/main.go

Location:

func main() {
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}

Problem: When the CLI encounters an error (file not found, invalid format, parse errors, etc.), it will exit silently with no error message displayed to the user.

Root Cause:

  1. In root.go:49-50, the Cobra command is configured with SilenceErrors: true, which prevents Cobra from printing errors
  2. In main.go, when an error occurs, the code exits without printing the error:
func main() {
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)  // No error message printed!
	}
}

Impact: Users will have no feedback when errors occur, making debugging and troubleshooting impossible.

Suggested Fix:

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}

This ensures users see error messages while still maintaining the SilenceErrors: true setting in root.go.

Print error messages to stderr before exiting when errors occur.
Previously, errors were silently swallowed due to SilenceErrors: true
in Cobra configuration, leaving users with no feedback.

Resolves claude-review feedback.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Jan 16, 2026

Code review

I found one issue that needs to be addressed:

Missing Package Documentation

File: internal/cli/input.go (line 1)

The internal/cli package is missing package-level documentation. According to the Documentation-First requirement in CLAUDE.md, all packages should have GoDoc comments for all exports.

All other packages in the project follow this pattern:

Please add a package-level comment before the package cli declaration in internal/cli/input.go explaining the purpose of this package, for example:

// Package cli provides command-line interface support for configdiff,
// including input handling, output formatting, and option mapping.
package cli

Summary: Checked for bugs and CLAUDE.md compliance. Found 1 issue related to missing documentation.

@pfrederiksen pfrederiksen merged commit 098428c into main Jan 16, 2026
6 checks passed
@pfrederiksen pfrederiksen deleted the feat/cli-and-release branch January 16, 2026 23:34
@pfrederiksen
Copy link
Owner Author

Test Coverage - Resolved ✅

The missing test coverage issue has been addressed. Added comprehensive test files:

  • internal/cli/input_test.go (145 lines) - Tests for ReadInput(), format detection, error handling
  • internal/cli/options_test.go (172 lines) - Tests for Validate(), ToLibraryOptions(), array key parsing
  • internal/cli/output_test.go (146 lines) - Tests for all output formats, HasChanges()
  • cmd/configdiff/main_test.go (86 lines) - Integration tests for CLI flow

Coverage Results:

  • internal/cli: 88.7%
  • cmd/configdiff: 58.0%
  • Overall project: 83.9% (exceeds 80% threshold)

All tests follow the project's table-driven test pattern and passed in CI.

Commit: db7fcab

@pfrederiksen
Copy link
Owner Author

Silent Error Handling Bug - Resolved ✅

The silent error handling issue has been fixed.

Change made to cmd/configdiff/main.go:

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)  // ← Error now printed to stderr
		os.Exit(1)
	}
}

Tested: Errors now properly display to users:

$ configdiff /nonexistent/file.yaml test.yaml
Error: failed to read file "/nonexistent/file.yaml": open /nonexistent/file.yaml: no such file or directory

Commit: 0e4f164296c1e5f37c5bafa66a0a8e2450d51e68

pfrederiksen added a commit that referenced this pull request Jan 16, 2026
Add missing package-level GoDoc comment to comply with
CLAUDE.md documentation requirements. All packages should
have package documentation explaining their purpose.

Resolves claude-review feedback in PR #8.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
pfrederiksen added a commit that referenced this pull request Jan 16, 2026
Adds missing package-level GoDoc comment to comply with CLAUDE.md documentation requirements. Resolves claude-review feedback in PR #8.
@pfrederiksen
Copy link
Owner Author

Missing Package Documentation - Resolved ✅

The missing package documentation issue has been addressed in PR #9 and released in v0.1.1.

Change made to internal/cli/input.go:

// Package cli provides command-line interface support for configdiff,
// including input handling, output formatting, and option mapping between
// CLI flags and library options.
package cli

Resolution:

The internal/cli package now has the same documentation standard as all other packages in the project (diff, parse, tree, patch, report).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant