550 lines
15 KiB
Markdown
550 lines
15 KiB
Markdown
# Independent Component Versioning (Future Design)
|
|
|
|
This document describes a future enhancement for Wild Cloud where each component (API, CLI, Web) can have independent versions while still being bundled together in versioned packages.
|
|
|
|
**Status**: Design document for future implementation
|
|
**Current Implementation**: Unified versioning (single VERSION file)
|
|
**Migration Path**: Can be implemented once we reach v1.0.0 and need API stability
|
|
|
|
---
|
|
|
|
## Why Independent Versioning?
|
|
|
|
### Current Limitations (Unified Versioning)
|
|
- CLI can't be updated without releasing entire package
|
|
- API bug fix requires new package even if CLI/Web unchanged
|
|
- Can't signal API breaking changes vs CLI enhancements independently
|
|
- Users can't install just CLI on CI machines with specific version
|
|
|
|
### Benefits of Independent Versioning
|
|
- **CLI Independence**: Download/install CLI separately for CI/automation
|
|
- **API Stability Signals**: API version communicates breaking changes
|
|
- **Flexible Release Cadence**: Update components on different schedules
|
|
- **Better Compatibility Communication**: "CLI v0.9 works with API v1.2-1.3"
|
|
- **Reduced Package Churn**: Don't republish entire package for small fixes
|
|
|
|
---
|
|
|
|
## Architecture Overview
|
|
|
|
### Version Files (4 files)
|
|
|
|
```
|
|
wild-cloud/
|
|
├── VERSION # Package/distribution version: 0.1.1
|
|
├── api/VERSION # API version: 1.2.3
|
|
├── cli/VERSION # CLI version: 0.8.1
|
|
└── web/VERSION # Web version: 0.5.2
|
|
```
|
|
|
|
### Compatibility Matrix
|
|
|
|
```yaml
|
|
# wild-cloud/MANIFEST.yaml
|
|
package:
|
|
version: "0.1.1"
|
|
name: "wild-cloud-central"
|
|
description: "Wild Cloud Central Management Service"
|
|
|
|
components:
|
|
api:
|
|
version: "1.2.3"
|
|
compatibility:
|
|
min_cli_version: "0.7.0" # Oldest CLI that works
|
|
max_cli_version: "0.9.x" # Newest CLI tested
|
|
|
|
cli:
|
|
version: "0.8.1"
|
|
compatibility:
|
|
min_api_version: "1.1.0" # Oldest API supported
|
|
max_api_version: "1.2.x" # Newest API supported
|
|
|
|
web:
|
|
version: "0.5.2"
|
|
compatibility:
|
|
requires_api_version: "1.2.3" # Exact API version required
|
|
|
|
# What combinations have been tested and certified
|
|
tested_combinations:
|
|
- package: "0.1.1"
|
|
api: "1.2.3"
|
|
cli: "0.8.1"
|
|
web: "0.5.2"
|
|
notes: "Stable release, all features tested"
|
|
|
|
- package: "0.1.0"
|
|
api: "1.2.2"
|
|
cli: "0.8.0"
|
|
web: "0.5.1"
|
|
notes: "Previous stable release"
|
|
```
|
|
|
|
---
|
|
|
|
## Version Semantics
|
|
|
|
### API Version (Server/Backend)
|
|
**Format**: `MAJOR.MINOR.PATCH`
|
|
|
|
- **MAJOR**: Breaking API changes
|
|
- Endpoints removed or renamed
|
|
- Request/response format changes
|
|
- Authentication mechanism changes
|
|
- Example: `1.2.3` → `2.0.0`
|
|
|
|
- **MINOR**: New features, backward compatible
|
|
- New endpoints added
|
|
- New optional parameters
|
|
- New response fields
|
|
- Example: `1.2.3` → `1.3.0`
|
|
|
|
- **PATCH**: Bug fixes only
|
|
- No API contract changes
|
|
- Performance improvements
|
|
- Security patches
|
|
- Example: `1.2.3` → `1.2.4`
|
|
|
|
**Stability Promise**:
|
|
- CLI version `0.8.x` guaranteed to work with API `1.2.x`
|
|
- CLI version `0.8.x` should work with API `1.3.x` (newer minor)
|
|
- CLI version `0.8.x` will NOT work with API `2.0.x` (major bump)
|
|
|
|
### CLI Version (Client Tool)
|
|
**Format**: `MAJOR.MINOR.PATCH`
|
|
|
|
- **MAJOR**: Breaking CLI changes
|
|
- Command structure changes
|
|
- Flag renames or removal
|
|
- Configuration format changes
|
|
- Example: `0.8.1` → `1.0.0`
|
|
|
|
- **MINOR**: New features
|
|
- New commands
|
|
- New flags (backward compatible)
|
|
- Can use new API features if available
|
|
- Example: `0.8.1` → `0.9.0`
|
|
|
|
- **PATCH**: Bug fixes and improvements
|
|
- Error message improvements
|
|
- Performance fixes
|
|
- Documentation updates
|
|
- Example: `0.8.1` → `0.8.2`
|
|
|
|
**Compatibility Promise**:
|
|
- CLI gracefully degrades when API doesn't support new features
|
|
- `wild app deploy` with new flag works with old API (ignores new features)
|
|
- CLI checks API version and warns about incompatibilities
|
|
|
|
### Web Version (Frontend UI)
|
|
**Format**: `MAJOR.MINOR.PATCH`
|
|
|
|
- **MAJOR**: Major UI redesign or breaking changes
|
|
- **MINOR**: New features, new pages
|
|
- **PATCH**: Bug fixes, UX improvements
|
|
|
|
**Note**: Web is typically tightly coupled to API and bundled together. Rarely released independently.
|
|
|
|
### Package Version (Distribution)
|
|
**Format**: `MAJOR.MINOR.PATCH`
|
|
|
|
- **MAJOR**: Major milestone releases (v1.0.0, v2.0.0)
|
|
- **MINOR**: New features or significant updates
|
|
- **PATCH**: Bug fixes, component version bumps
|
|
|
|
**Purpose**: Tracks the tested, certified combination of components.
|
|
|
|
---
|
|
|
|
## Implementation Details
|
|
|
|
### 1. Build System Changes
|
|
|
|
#### Makefile Reads All Versions
|
|
```makefile
|
|
# Read all version files
|
|
PACKAGE_VERSION := $(shell cat ../VERSION 2>/dev/null || echo "0.0.0-dev")
|
|
API_VERSION := $(shell cat ../api/VERSION 2>/dev/null || echo "0.0.0-dev")
|
|
CLI_VERSION := $(shell cat ../cli/VERSION 2>/dev/null || echo "0.0.0-dev")
|
|
WEB_VERSION := $(shell cat ../web/VERSION 2>/dev/null || echo "0.0.0-dev")
|
|
|
|
# Version info target
|
|
version:
|
|
@echo "Package: v$(PACKAGE_VERSION)"
|
|
@echo " API: v$(API_VERSION)"
|
|
@echo " CLI: v$(CLI_VERSION)"
|
|
@echo " Web: v$(WEB_VERSION)"
|
|
|
|
# Build with component versions injected
|
|
build-api:
|
|
cd $(API_SOURCE) && GOOS=linux GOARCH=amd64 \
|
|
go build -ldflags="-X main.Version=$(API_VERSION) -X main.PackageVersion=$(PACKAGE_VERSION)" \
|
|
-o ../dist/$(AMD64_BINARY) .
|
|
|
|
build-cli:
|
|
cd ../cli && GOOS=linux GOARCH=amd64 \
|
|
go build -ldflags="-X main.Version=$(CLI_VERSION)" \
|
|
-o ../dist/build/wild-cli-$(CLI_VERSION)-amd64 .
|
|
```
|
|
|
|
### 2. CLI Version Command with Compatibility Check
|
|
|
|
```go
|
|
// cli/cmd/version.go
|
|
package cmd
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var Version = "dev" // Injected at build time
|
|
|
|
type APIVersion struct {
|
|
Version string `json:"version"`
|
|
MinCLIVersion string `json:"minCliVersion"`
|
|
}
|
|
|
|
var versionCmd = &cobra.Command{
|
|
Use: "version",
|
|
Short: "Show version information and API compatibility",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
fmt.Printf("Wild CLI v%s\n", Version)
|
|
|
|
// Try to get API version if connected
|
|
apiURL := getAPIURL() // From config
|
|
if apiURL != "" {
|
|
apiVersion, err := getAPIVersion(apiURL)
|
|
if err == nil {
|
|
compatible := checkCompatibility(Version, apiVersion)
|
|
status := "✓"
|
|
if !compatible {
|
|
status = "⚠️"
|
|
}
|
|
fmt.Printf("Connected to API v%s %s\n", apiVersion.Version, status)
|
|
|
|
if !compatible {
|
|
fmt.Printf(" Warning: CLI v%s may not be fully compatible with API v%s\n",
|
|
Version, apiVersion.Version)
|
|
fmt.Printf(" Recommended CLI version: >= v%s\n", apiVersion.MinCLIVersion)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
}
|
|
|
|
func getAPIVersion(apiURL string) (*APIVersion, error) {
|
|
resp, err := http.Get(apiURL + "/api/v1/version")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var version APIVersion
|
|
if err := json.NewDecoder(resp.Body).Decode(&version); err != nil {
|
|
return nil, err
|
|
}
|
|
return &version, nil
|
|
}
|
|
|
|
func checkCompatibility(cliVersion string, apiVersion *APIVersion) bool {
|
|
// Simple semantic version comparison
|
|
// Full implementation would use proper semver library
|
|
cliMajor := strings.Split(cliVersion, ".")[0]
|
|
minMajor := strings.Split(apiVersion.MinCLIVersion, ".")[0]
|
|
|
|
return cliMajor >= minMajor
|
|
}
|
|
```
|
|
|
|
### 3. API Version Endpoint
|
|
|
|
```go
|
|
// api/internal/api/v1/handlers_version.go
|
|
package v1
|
|
|
|
import (
|
|
"net/http"
|
|
)
|
|
|
|
var Version = "dev" // Injected at build
|
|
var PackageVersion = "dev" // Injected at build
|
|
|
|
type VersionResponse struct {
|
|
Version string `json:"version"`
|
|
PackageVersion string `json:"packageVersion"`
|
|
MinCLIVersion string `json:"minCliVersion"`
|
|
MaxCLIVersion string `json:"maxCliVersion"`
|
|
}
|
|
|
|
func (api *API) GetVersion(w http.ResponseWriter, r *http.Request) {
|
|
respondJSON(w, http.StatusOK, VersionResponse{
|
|
Version: Version,
|
|
PackageVersion: PackageVersion,
|
|
MinCLIVersion: "0.7.0", // Could read from MANIFEST.yaml
|
|
MaxCLIVersion: "0.9.x",
|
|
})
|
|
}
|
|
|
|
// Register route in handlers.go
|
|
// r.HandleFunc("/api/v1/version", api.GetVersion).Methods("GET")
|
|
```
|
|
|
|
### 4. Release Script Support for Component Releases
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# scripts/create-release.sh
|
|
|
|
PACKAGE_VERSION=$(cat ../VERSION)
|
|
API_VERSION=$(cat ../api/VERSION)
|
|
CLI_VERSION=$(cat ../cli/VERSION)
|
|
WEB_VERSION=$(cat ../web/VERSION)
|
|
|
|
RELEASE_TYPE="$1" # "package", "cli", "api"
|
|
|
|
case "$RELEASE_TYPE" in
|
|
"package")
|
|
# Full package release
|
|
TAG="v${PACKAGE_VERSION}"
|
|
TITLE="Wild Cloud Central v${PACKAGE_VERSION}"
|
|
BODY="Package includes: API v${API_VERSION}, CLI v${CLI_VERSION}, Web v${WEB_VERSION}"
|
|
|
|
create_release "$TAG" "$TITLE" "$BODY"
|
|
upload_debs
|
|
;;
|
|
|
|
"cli")
|
|
# CLI-only release
|
|
TAG="cli-v${CLI_VERSION}"
|
|
TITLE="Wild CLI v${CLI_VERSION}"
|
|
BODY="Standalone CLI release. Compatible with API v${API_VERSION}"
|
|
|
|
create_release "$TAG" "$TITLE" "$BODY"
|
|
upload_cli_binaries
|
|
;;
|
|
|
|
"api")
|
|
# API update within existing package
|
|
TAG="v${PACKAGE_VERSION}"
|
|
|
|
if release_exists "$TAG"; then
|
|
update_release_assets "$TAG"
|
|
else
|
|
echo "Package version not changed, updating existing release"
|
|
update_release_assets "$(get_latest_release_tag)"
|
|
fi
|
|
;;
|
|
esac
|
|
```
|
|
|
|
### 5. Compatibility Validation Script
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# scripts/check-compatibility.sh
|
|
|
|
MANIFEST="wild-cloud/MANIFEST.yaml"
|
|
|
|
API_VERSION=$(cat wild-cloud/api/VERSION)
|
|
CLI_VERSION=$(cat wild-cloud/cli/VERSION)
|
|
WEB_VERSION=$(cat wild-cloud/web/VERSION)
|
|
|
|
echo "Checking version compatibility..."
|
|
|
|
# Check if this combination is in tested_combinations
|
|
TESTED=$(yq eval ".tested_combinations[] | select(.api == \"$API_VERSION\" and .cli == \"$CLI_VERSION\" and .web == \"$WEB_VERSION\")" "$MANIFEST")
|
|
|
|
if [ -n "$TESTED" ]; then
|
|
echo "✓ Component versions have been tested together"
|
|
else
|
|
echo "⚠️ Warning: This combination has not been tested"
|
|
echo " API: $API_VERSION"
|
|
echo " CLI: $CLI_VERSION"
|
|
echo " Web: $WEB_VERSION"
|
|
echo ""
|
|
echo "Run full integration tests before release"
|
|
exit 1
|
|
fi
|
|
|
|
# Check CLI compatibility with API
|
|
MIN_CLI=$(yq eval ".components.api.compatibility.min_cli_version" "$MANIFEST")
|
|
if version_less_than "$CLI_VERSION" "$MIN_CLI"; then
|
|
echo "✗ CLI version $CLI_VERSION is older than minimum required $MIN_CLI"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✓ All compatibility checks passed"
|
|
```
|
|
|
|
---
|
|
|
|
## Migration Path
|
|
|
|
### Phase 1: Preparation (Current: v0.x.x)
|
|
- Continue using unified VERSION file
|
|
- Build foundation for independent versioning
|
|
- Document API surface and breaking changes
|
|
|
|
### Phase 2: Soft Migration (v0.9.x)
|
|
- Create component VERSION files
|
|
- Keep them in sync with package VERSION
|
|
- Add compatibility checking code (unused)
|
|
- Test infrastructure
|
|
|
|
### Phase 3: Independent Releases (v1.0.0+)
|
|
- Start versioning components independently
|
|
- First CLI-only release
|
|
- Update MANIFEST.yaml with compatibility matrix
|
|
- Enable compatibility warnings
|
|
|
|
### Phase 4: Mature State (v1.1.0+)
|
|
- Components release on different cadences
|
|
- API maintains backward compatibility
|
|
- CLI works with multiple API versions
|
|
- Well-tested compatibility matrix
|
|
|
|
---
|
|
|
|
## Release Workflows
|
|
|
|
### Workflow 1: Bug Fix in API Only
|
|
```bash
|
|
# Bump only API version
|
|
echo "1.2.4" > api/VERSION
|
|
|
|
# Optionally bump package patch version
|
|
echo "0.1.2" > VERSION
|
|
|
|
# Build and release
|
|
make package-all
|
|
make release-package # Updates/creates v0.1.2 with API v1.2.4
|
|
```
|
|
|
|
### Workflow 2: New CLI Feature (Standalone)
|
|
```bash
|
|
# Bump CLI version
|
|
echo "0.9.0" > cli/VERSION
|
|
|
|
# Build CLI
|
|
cd cli && make build
|
|
|
|
# Release CLI independently
|
|
make release-cli # Creates cli-v0.9.0 tag with standalone binary
|
|
|
|
# Users can: wget .../cli-v0.9.0/wild-amd64
|
|
```
|
|
|
|
### Workflow 3: Major Package Release
|
|
```bash
|
|
# Bump all versions
|
|
echo "2.0.0" > api/VERSION # Breaking API changes
|
|
echo "1.0.0" > cli/VERSION # CLI redesign
|
|
echo "1.0.0" > web/VERSION # New UI
|
|
echo "1.0.0" > VERSION # Major package milestone
|
|
|
|
# Update MANIFEST.yaml with new compatibility rules
|
|
vim wild-cloud/MANIFEST.yaml
|
|
|
|
# Run compatibility checks
|
|
./scripts/check-compatibility.sh
|
|
|
|
# Build and release
|
|
make package-all
|
|
make release-package # Creates v1.0.0
|
|
```
|
|
|
|
### Workflow 4: Hotfix in Testing
|
|
```bash
|
|
# Fix bug, no version bump
|
|
git commit -m "Fix: cluster deletion bug"
|
|
|
|
# Rebuild and update current release
|
|
make package-all
|
|
make release-package # Updates existing release assets
|
|
```
|
|
|
|
---
|
|
|
|
## Benefits Summary
|
|
|
|
### For Users
|
|
- Download just CLI for automation/CI (smaller, faster)
|
|
- Know when API changes might break scripts (version signals)
|
|
- Get bug fixes without reinstalling entire package
|
|
- Clear compatibility information (`wild --version`)
|
|
|
|
### For Developers
|
|
- Release components independently (faster iteration)
|
|
- Signal breaking changes appropriately (API major version)
|
|
- Test combinations in compatibility matrix
|
|
- Reduce package release churn
|
|
|
|
### For DevOps
|
|
- Pin CLI version in CI/CD pipelines
|
|
- Upgrade API without updating all CLI installations
|
|
- Clear upgrade paths and compatibility docs
|
|
- Automated compatibility checking
|
|
|
|
---
|
|
|
|
## Implementation Checklist
|
|
|
|
### Phase 1: Foundation
|
|
- [ ] Create component VERSION files (keep in sync initially)
|
|
- [ ] Add version injection to all components
|
|
- [ ] Create MANIFEST.yaml structure
|
|
- [ ] Add `GET /api/v1/version` endpoint
|
|
- [ ] Add `wild version` command with compatibility check
|
|
|
|
### Phase 2: Build System
|
|
- [ ] Update Makefile to read all VERSION files
|
|
- [ ] Add compatibility validation script
|
|
- [ ] Create release script for different release types
|
|
- [ ] Test version injection in builds
|
|
- [ ] Document version management workflow
|
|
|
|
### Phase 3: Release Infrastructure
|
|
- [ ] Support package releases (current behavior)
|
|
- [ ] Support CLI-only releases (new tag structure)
|
|
- [ ] Support updating existing release assets
|
|
- [ ] Create GitHub/Gitea release templates
|
|
- [ ] Add CI/CD integration for automated releases
|
|
|
|
### Phase 4: Documentation
|
|
- [ ] Document versioning strategy
|
|
- [ ] Create compatibility matrix documentation
|
|
- [ ] Write upgrade guides
|
|
- [ ] Add troubleshooting for version mismatches
|
|
- [ ] Create developer guide for version bumping
|
|
|
|
---
|
|
|
|
## Open Questions
|
|
|
|
1. **CLI Distribution**: Should CLI be in separate GitHub releases or same repo with different tags?
|
|
- Recommendation: Same repo, different tags (`cli-v0.9.0`)
|
|
|
|
2. **Version Discovery**: Should CLI auto-update check?
|
|
- Recommendation: No auto-update, but check for new versions on `--version`
|
|
|
|
3. **API Version in URL**: Should we support `/api/v2/` for major versions?
|
|
- Recommendation: Not initially, version in header is sufficient
|
|
|
|
4. **Deprecation Policy**: How long to support old API versions?
|
|
- Recommendation: N-1 major version (API v2.x supports v1.x clients)
|
|
|
|
---
|
|
|
|
## References
|
|
|
|
- **Kubernetes**: kubectl ±1 minor version skew policy
|
|
- **Docker**: CLI forward compatibility with engine
|
|
- **Terraform**: Provider versioning model
|
|
- **HashiCorp Consul**: API versioning strategy
|
|
|
|
This design provides maximum flexibility for component independence while maintaining package simplicity during development.
|