From 9ed64a4d2876bb1ca974b0b27eb14a4fd11808e5 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 16 Sep 2026 19:01:07 +0000 Subject: [PATCH] cleanup: remove stale docs and duplicate docker-compose files - Delete docs/idea.md (superseded by docs/ARCHITECTURE.md) - Delete docs/npm-publishing.md (superseded by PUBLISHING.md and AUTOMATED-RELEASE.md) - Delete duplicate /docker/*.yml files (kept /cmd/docker/*.yml as source) - Update runtime_contract_test.go to reference embedded compose files correctly Co-authored-by: Mohit Nagaraj --- cmd/runtime_contract_test.go | 28 +- docker/docker-compose.dev.yml | 31 -- docker/docker-compose.hybrid-core.yml | 48 --- docker/docker-compose.hybrid-ui.yml | 51 --- docker/docker-compose.prod.yml | 64 ---- docs/idea.md | 386 -------------------- docs/npm-publishing.md | 501 -------------------------- 7 files changed, 14 insertions(+), 1095 deletions(-) delete mode 100644 docker/docker-compose.dev.yml delete mode 100644 docker/docker-compose.hybrid-core.yml delete mode 100644 docker/docker-compose.hybrid-ui.yml delete mode 100644 docker/docker-compose.prod.yml delete mode 100644 docs/idea.md delete mode 100644 docs/npm-publishing.md diff --git a/cmd/runtime_contract_test.go b/cmd/runtime_contract_test.go index 86ffe4f..7cdecaf 100644 --- a/cmd/runtime_contract_test.go +++ b/cmd/runtime_contract_test.go @@ -273,21 +273,21 @@ func TestEmbeddedComposeContract(t *testing.T) { } for _, name := range files { t.Run(name, func(t *testing.T) { - embedded, err := embeddedComposeFiles.ReadFile("docker/" + name) - if err != nil { - t.Fatal(err) - } - if strings.Contains(string(embedded), "version: '3.8'") { - t.Fatal("obsolete Compose version declaration is present") - } - if strings.Contains(string(embedded), ":latest") { - t.Fatal("runtime image is not pinned") - } + embedded, err := embeddedComposeFiles.ReadFile("docker/" + name) + if err != nil { + t.Fatal(err) + } + if strings.Contains(string(embedded), "version: '3.8'") { + t.Fatal("obsolete Compose version declaration is present") + } + if strings.Contains(string(embedded), ":latest") { + t.Fatal("runtime image is not pinned") + } - shipped, err := os.ReadFile(filepath.Join("..", "docker", name)) - if err != nil { - t.Fatal(err) - } + shipped, err := os.ReadFile(filepath.Join("docker", name)) + if err != nil { + t.Fatal(err) + } if string(embedded) != string(shipped) { t.Fatal("embedded and repository Compose files differ") } diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml deleted file mode 100644 index adcecbb..0000000 --- a/docker/docker-compose.dev.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Development mode - both UI and Core run on host -# Only MongoDB runs in Docker - -services: - mongodb: - image: mongo:8.0@sha256:02a0cc7939f5ed38f30f9bc714ef5f682d49baf9350c54acf302ce833087fe8a - container_name: kubeorchestra-mongodb-dev - restart: unless-stopped - environment: - MONGO_INITDB_DATABASE: kubeorchestra - ports: - - "27017:27017" - volumes: - - mongodb_data:/data/db - - mongodb_config:/data/configdb - healthcheck: - test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - -# UI runs on host: cd ui && npm install && npm run dev (port 3001) -# Core runs on host: cd core && air (port 3000) -# Both connect to MongoDB at localhost:27017 - -volumes: - mongodb_data: - name: kubeorchestra_mongodb_data_dev - mongodb_config: - name: kubeorchestra_mongodb_config_dev diff --git a/docker/docker-compose.hybrid-core.yml b/docker/docker-compose.hybrid-core.yml deleted file mode 100644 index dcc38d3..0000000 --- a/docker/docker-compose.hybrid-core.yml +++ /dev/null @@ -1,48 +0,0 @@ -# Hybrid Core mode - Core repo cloned, UI from Docker image -# MongoDB and UI run in Docker; Core runs on the host. - -networks: - kubeorchestra-net: - driver: bridge - name: kubeorchestra-network-hybrid - -services: - mongodb: - image: mongo:8.0@sha256:02a0cc7939f5ed38f30f9bc714ef5f682d49baf9350c54acf302ce833087fe8a - container_name: kubeorchestra-mongodb-hybrid - restart: unless-stopped - networks: - - kubeorchestra-net - environment: - MONGO_INITDB_DATABASE: kubeorchestra - ports: - - "27017:27017" - volumes: - - mongodb_data:/data/db - - mongodb_config:/data/configdb - healthcheck: - test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - - ui: - image: ghcr.io/kubeorch/ui:v0.0.3@sha256:7ae131ccca459c582bfa14287bd53e1c74bd79f3b3015560ab6c45d8686839f3 - container_name: kubeorchestra-ui-hybrid - restart: unless-stopped - networks: - - kubeorchestra-net - ports: - - "3001:3000" - environment: - NEXT_PUBLIC_API_URL: http://localhost:3000/v1/api - -# Core runs on host: cd core && go run . (port 3000) -# Core connects to MongoDB at localhost:27017. - -volumes: - mongodb_data: - name: kubeorchestra_mongodb_data_hybrid - mongodb_config: - name: kubeorchestra_mongodb_config_hybrid diff --git a/docker/docker-compose.hybrid-ui.yml b/docker/docker-compose.hybrid-ui.yml deleted file mode 100644 index 0072095..0000000 --- a/docker/docker-compose.hybrid-ui.yml +++ /dev/null @@ -1,51 +0,0 @@ -# Hybrid UI mode - UI runs on host, Core from Docker image -# MongoDB and Core run in Docker - -networks: - kubeorchestra-net: - driver: bridge - name: kubeorchestra-network-hybrid - -services: - mongodb: - image: mongo:8.0@sha256:02a0cc7939f5ed38f30f9bc714ef5f682d49baf9350c54acf302ce833087fe8a - container_name: kubeorchestra-mongodb-hybrid - restart: unless-stopped - networks: - - kubeorchestra-net - environment: - MONGO_INITDB_DATABASE: kubeorchestra - ports: - - "27017:27017" - volumes: - - mongodb_data:/data/db - - mongodb_config:/data/configdb - healthcheck: - test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - - core: - image: ghcr.io/kubeorch/core:v0.0.3@sha256:eafafc2187bda39981bc9ae2fe5f80b77d00d26550b985e8a86c184fc8d4452e - container_name: kubeorchestra-core-hybrid - restart: unless-stopped - networks: - - kubeorchestra-net - ports: - - "3000:3000" - environment: - KUBEORCH_MONGO_URI: mongodb://mongodb:27017/kubeorchestra - depends_on: - mongodb: - condition: service_healthy - -# UI runs on host: cd ui && npm install && npm run dev (port 3001) -# UI connects to Core at localhost:3000/v1/api - -volumes: - mongodb_data: - name: kubeorchestra_mongodb_data_hybrid - mongodb_config: - name: kubeorchestra_mongodb_config_hybrid diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml deleted file mode 100644 index 68fb700..0000000 --- a/docker/docker-compose.prod.yml +++ /dev/null @@ -1,64 +0,0 @@ -networks: - kubeorchestra-net: - driver: bridge - name: kubeorchestra-network - -services: - mongodb: - image: mongo:8.0@sha256:02a0cc7939f5ed38f30f9bc714ef5f682d49baf9350c54acf302ce833087fe8a - container_name: kubeorchestra-mongodb - restart: unless-stopped - networks: - - kubeorchestra-net - environment: - MONGO_INITDB_DATABASE: kubeorchestra - ports: - - "27017:27017" - expose: - - "27017" - volumes: - - mongodb_data:/data/db - - mongodb_config:/data/configdb - healthcheck: - test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - - core: - image: ghcr.io/kubeorch/core:v0.0.3@sha256:eafafc2187bda39981bc9ae2fe5f80b77d00d26550b985e8a86c184fc8d4452e - container_name: kubeorchestra-core - restart: unless-stopped - networks: - - kubeorchestra-net - ports: - - "3000:3000" - expose: - - "3000" - environment: - KUBEORCH_MONGO_URI: mongodb://mongodb:27017/kubeorchestra - depends_on: - mongodb: - condition: service_healthy - - ui: - image: ghcr.io/kubeorch/ui:v0.0.3@sha256:7ae131ccca459c582bfa14287bd53e1c74bd79f3b3015560ab6c45d8686839f3 - container_name: kubeorchestra-ui - restart: unless-stopped - networks: - - kubeorchestra-net - ports: - - "3001:3000" - expose: - - "3000" - environment: - NEXT_PUBLIC_API_URL: http://localhost:3000/v1/api - depends_on: - - core - -volumes: - mongodb_data: - name: kubeorchestra_mongodb_data - mongodb_config: - name: kubeorchestra_mongodb_config diff --git a/docs/idea.md b/docs/idea.md deleted file mode 100644 index 76ff2b0..0000000 --- a/docs/idea.md +++ /dev/null @@ -1,386 +0,0 @@ -# OrchCLI - KubeOrchestra Developer CLI - -## What is OrchCLI? - -A developer tool for working on KubeOrchestra platform. It helps: -- Clone and setup UI/Core repositories for development -- Run local development environment with hot reload -- Handle fork-based contributions for external developers -- Quick production testing with latest images - -## Repository Structure - -``` -cli/ -├── .gitignore # Ignores cloned ui/ and core/ directories -├── cmd/ -│ ├── root.go -│ ├── init.go # Clone repos or setup forks -│ ├── dev.go # Development commands -│ └── run.go # Run production images locally -├── docker/ # Orchestration files (moved from core repo) -│ ├── docker-compose.dev.yml # For development (mounts local code) -│ ├── docker-compose.prod.yml # For production testing -│ ├── Dockerfile.core.dev # Core development container -│ └── Dockerfile.ui.dev # UI development container -├── scripts/ -│ └── setup.sh # Setup helper scripts -└── docs/ -``` - -## Commands Overview - -```bash -# Development workflow (clones repos) -orchcli init # Clone official repos -orchcli init --fork-ui=user/ui # Clone from forks -orchcli dev start # Start with local code -orchcli dev start --ui-only # Only UI local, others as containers - -# Production testing (uses published images) -orchcli run # Run latest published images -orchcli run --version=1.2.3 # Run specific version - -# Utilities -orchcli update # Pull latest changes -orchcli status # Check what's running -``` - -## Git Workflow - -### 1. Organization Members -When you run `orchcli init`, it clones the official repos: -```bash -orchcli init -# Clones: -# - https://github.com/KubeOrchestra/ui → ./ui -# - https://github.com/KubeOrchestra/core → ./core - -cd ui -# Already connected to origin, can push directly -git add . -git commit -m "feat: add new component" -git push origin main -``` - -### 2. External Contributors (Forks) -```bash -# First, fork repos on GitHub, then: -orchcli init --fork-ui=johndoe/ui --fork-core=johndoe/core - -# This sets up: -# - origin: your fork (for pushing) -# - upstream: official repo (for pulling updates) - -cd ui -git checkout -b feature/new-component -git add . -git commit -m "feat: add new component" -git push origin feature/new-component -# Then create PR from fork to upstream -``` - -## Implementation Details - -### Init Command (cmd/init.go) -```go -package cmd - -import ( - "fmt" - "os/exec" - "github.com/spf13/cobra" -) - -var ( - forkUI string - forkCore string -) - -var initCmd = &cobra.Command{ - Use: "init", - Short: "Initialize KubeOrchestra development environment", - RunE: func(cmd *cobra.Command, args []string) error { - // Determine if using forks or official repos - uiRepo := "https://github.com/KubeOrchestra/ui" - coreRepo := "https://github.com/KubeOrchestra/core" - - if forkUI != "" { - uiRepo = fmt.Sprintf("https://github.com/%s", forkUI) - } - if forkCore != "" { - coreRepo = fmt.Sprintf("https://github.com/%s", forkCore) - } - - // Clone repositories - fmt.Println("📦 Cloning UI repository...") - if err := cloneRepo(uiRepo, "./ui"); err != nil { - return err - } - - fmt.Println("📦 Cloning Core repository...") - if err := cloneRepo(coreRepo, "./core"); err != nil { - return err - } - - // Setup upstream for forks - if forkUI != "" { - fmt.Println("🔗 Setting up upstream for UI fork...") - setupUpstream("./ui", "https://github.com/KubeOrchestra/ui") - } - if forkCore != "" { - fmt.Println("🔗 Setting up upstream for Core fork...") - setupUpstream("./core", "https://github.com/KubeOrchestra/core") - } - - // Install dependencies - fmt.Println("📥 Installing dependencies...") - installDependencies() - - fmt.Println("✅ Development environment ready!") - fmt.Println("Run 'orchcli dev start' to begin development") - return nil - }, -} - -func cloneRepo(url, path string) error { - cmd := exec.Command("git", "clone", url, path) - return cmd.Run() -} - -func setupUpstream(path, upstream string) error { - cmd := exec.Command("git", "remote", "add", "upstream", upstream) - cmd.Dir = path - return cmd.Run() -} - -func installDependencies() { - // Install UI dependencies - cmd := exec.Command("npm", "install") - cmd.Dir = "./ui" - cmd.Run() - - // Download Go modules - cmd = exec.Command("go", "mod", "download") - cmd.Dir = "./core" - cmd.Run() -} - -func init() { - initCmd.Flags().StringVar(&forkUI, "fork-ui", "", "UI fork repository (e.g., username/ui)") - initCmd.Flags().StringVar(&forkCore, "fork-core", "", "Core fork repository (e.g., username/core)") - rootCmd.AddCommand(initCmd) -} -``` - -### Dev Command (cmd/dev.go) -```go -var devStartCmd = &cobra.Command{ - Use: "start", - Short: "Start development environment with local code", - RunE: func(cmd *cobra.Command, args []string) error { - uiOnly, _ := cmd.Flags().GetBool("ui-only") - coreOnly, _ := cmd.Flags().GetBool("core-only") - - if uiOnly { - // Run UI locally, Core as container - return runDockerCompose("docker/docker-compose.prod.yml", "core", "postgres") - } else if coreOnly { - // Run Core locally, UI as container - return runDockerCompose("docker/docker-compose.prod.yml", "ui", "postgres") - } - - // Run everything with local code - return runDockerCompose("docker/docker-compose.dev.yml") - }, -} -``` - -### Run Command (cmd/run.go) -```go -var runCmd = &cobra.Command{ - Use: "run", - Short: "Run production images locally for testing", - Long: "Runs the latest published Docker images without cloning repositories", - RunE: func(cmd *cobra.Command, args []string) error { - version, _ := cmd.Flags().GetString("version") - - // Use docker-compose.prod.yml which pulls images - return runDockerCompose("docker/docker-compose.prod.yml") - }, -} -``` - -### Docker Compose Files - -**docker/docker-compose.dev.yml** (for development): -```yaml -services: - postgres: - image: postgres:14 - environment: - POSTGRES_DB: kubeorchestra - ports: - - "5432:5432" - - core: - build: - context: ../core - dockerfile: Dockerfile.dev - volumes: - - ../core:/app # Mount local code - - /app/vendor - ports: - - "3000:3000" - environment: - DB_HOST: postgres - depends_on: - - postgres - command: air # Hot reload - - ui: - build: - context: ../ui - dockerfile: Dockerfile.dev - volumes: - - ../ui:/app # Mount local code - - /app/node_modules - ports: - - "3001:3000" - environment: - NEXT_PUBLIC_API_URL: http://localhost:3000 - depends_on: - - core - command: npm run dev # Hot reload -``` - -**docker/docker-compose.prod.yml** (for production testing): -```yaml -services: - postgres: - image: postgres:14 - environment: - POSTGRES_DB: kubeorchestra - ports: - - "5432:5432" - - core: - image: ghcr.io/kubeorchestra/core:${VERSION:-latest} - ports: - - "3000:3000" - environment: - DB_HOST: postgres - depends_on: - - postgres - - ui: - image: ghcr.io/kubeorchestra/ui:${VERSION:-latest} - ports: - - "3001:3000" - environment: - NEXT_PUBLIC_API_URL: http://localhost:3000 - depends_on: - - core -``` - -### .gitignore -```gitignore -# Cloned repositories (managed separately) -/ui/ -/core/ - -# Binary builds -/bin/ -/dist/ -orchcli -*.exe - -# Go -vendor/ -*.mod.sum - -# Node -node_modules/ -npm/binaries/ - -# Environment -.env -.env.local - -# OS -.DS_Store -``` - -## Workflows Summary - -### For Team Members -```bash -# One-time setup -orchcli init - -# Daily development -cd ui # or core -git pull origin main -orchcli dev start -# Make changes... -git add . -git commit -m "feat: something" -git push origin main -``` - -### For External Contributors -```bash -# Fork repos on GitHub first, then: -orchcli init --fork-ui=myuser/ui --fork-core=myuser/core - -# Development -orchcli dev start -cd ui -git checkout -b feature/cool-feature -# Make changes... -git push origin feature/cool-feature -# Create PR on GitHub -``` - -### For Testing Production -```bash -# No need to clone anything -orchcli run # Latest versions -orchcli run --version=1.2.3 # Specific version -``` - -## Benefits - -1. **Clean Separation**: Cloned repos are gitignored, no nested git issues -2. **Direct Git Access**: Developers work directly in ui/ and core/ folders -3. **Fork Support**: External contributors can easily work with forks -4. **Production Testing**: Can run latest images without cloning code -5. **Flexible Workflows**: Support for UI-only, Core-only, or full development - -## Why CLI Owns Docker Compose & Orchestration - -### Architecture Decision -The CLI repository owns all development orchestration (docker-compose, Dockerfiles) while Core and UI repos focus purely on their application code. - -### Benefits -1. **Single Source of Truth**: All orchestration in one place -2. **Clean Core/UI Repos**: No docker-compose clutter -3. **Easier Maintenance**: Update orchestration without touching app repos -4. **Better for Contributors**: They only need to understand orchcli commands - -### What Lives Where -- **CLI Repo**: docker-compose files, dev Dockerfiles, orchestration scripts -- **Core Repo**: Go application code, minimal Makefile for Go tasks -- **UI Repo**: Next.js application code, package.json scripts - -## Installation - -```bash -# Via npm -npm install -g @kubeorchestra/orchcli - -# Via go -go install github.com/kubeorchestra/cli@latest - -# Binary will be called orchcli -``` \ No newline at end of file diff --git a/docs/npm-publishing.md b/docs/npm-publishing.md deleted file mode 100644 index bedcaf9..0000000 --- a/docs/npm-publishing.md +++ /dev/null @@ -1,501 +0,0 @@ -# Publishing OrchCTL to npm - -This guide explains how to publish the OrchCTL CLI to npm so users can install it via `npm install -g @kubeorchestra/orchcli`. - -## Overview - -The npm package acts as a wrapper that downloads the appropriate Go binary for the user's platform during installation. - -## Directory Structure - -``` -cli/ -├── main.go # Go CLI source -├── npm/ # npm package files -│ ├── package.json -│ ├── bin/ -│ │ └── orchcli.js # Node.js wrapper -│ └── scripts/ -│ └── postinstall.js # Download binary script -├── .goreleaser.yml # Build configuration -└── .github/ - └── workflows/ - └── release.yml # Automated release -``` - -## Step 1: Create npm Package Files - -### package.json -Create `npm/package.json`: - -```json -{ - "name": "@kubeorchestra/orchcli", - "version": "0.1.0", - "description": "OrchCTL - KubeOrchestra Developer CLI", - "bin": { - "orchcli": "./bin/orchcli.js" - }, - "scripts": { - "postinstall": "node scripts/postinstall.js" - }, - "files": [ - "bin/", - "scripts/", - "README.md" - ], - "keywords": [ - "kubernetes", - "orchestration", - "cli", - "kubeorchestra", - "developer-tools" - ], - "repository": { - "type": "git", - "url": "https://github.com/KubeOrchestra/cli" - }, - "bugs": { - "url": "https://github.com/KubeOrchestra/cli/issues" - }, - "homepage": "https://github.com/KubeOrchestra/cli#readme", - "author": "KubeOrchestra", - "license": "Apache-2.0", - "engines": { - "node": ">=14.0.0" - } -} -``` - -### Binary Wrapper -Create `npm/bin/orchcli.js`: - -```javascript -#!/usr/bin/env node - -const { spawn } = require('child_process'); -const path = require('path'); -const fs = require('fs'); - -// Determine binary name based on platform -const platform = process.platform; -const binaryName = platform === 'win32' ? 'orchcli.exe' : 'orchcli'; -const binaryPath = path.join(__dirname, '..', 'binaries', binaryName); - -// Check if binary exists -if (!fs.existsSync(binaryPath)) { - console.error('Error: orchcli binary not found.'); - console.error('Please try reinstalling: npm install -g @kubeorchestra/orchcli'); - process.exit(1); -} - -// Spawn the binary with all arguments -const child = spawn(binaryPath, process.argv.slice(2), { - stdio: 'inherit', - env: process.env -}); - -// Handle exit -child.on('exit', (code) => { - process.exit(code); -}); - -// Handle errors -child.on('error', (err) => { - console.error('Failed to start orchcli:', err); - process.exit(1); -}); -``` - -### Post-Install Script -Create `npm/scripts/postinstall.js`: - -```javascript -#!/usr/bin/env node - -const https = require('https'); -const fs = require('fs'); -const path = require('path'); -const { execSync } = require('child_process'); - -// Get package version -const { version } = require('../package.json'); - -// Platform mapping -const PLATFORM_MAP = { - 'darwin-x64': 'darwin-amd64', - 'darwin-arm64': 'darwin-arm64', - 'linux-x64': 'linux-amd64', - 'linux-arm64': 'linux-arm64', - 'linux-arm': 'linux-arm', - 'win32-x64': 'windows-amd64', - 'win32-ia32': 'windows-386' -}; - -// Get platform -const platform = `${process.platform}-${process.arch}`; -const binaryName = PLATFORM_MAP[platform]; - -if (!binaryName) { - console.error(`Unsupported platform: ${platform}`); - console.error('Please visit https://github.com/KubeOrchestra/cli/releases to download manually.'); - process.exit(1); -} - -// Construct download URL -const ext = process.platform === 'win32' ? '.exe' : ''; -const binaryUrl = `https://github.com/KubeOrchestra/cli/releases/download/v${version}/orchcli-${binaryName}${ext}`; - -// Prepare paths -const binariesDir = path.join(__dirname, '..', 'binaries'); -const outputFile = path.join(binariesDir, `orchcli${ext}`); - -// Create binaries directory -if (!fs.existsSync(binariesDir)) { - fs.mkdirSync(binariesDir, { recursive: true }); -} - -console.log(`Downloading orchcli v${version} for ${platform}...`); -console.log(`URL: ${binaryUrl}`); - -// Download function -function download(url, dest) { - return new Promise((resolve, reject) => { - const file = fs.createWriteStream(dest); - - https.get(url, (response) => { - // Handle redirects - if (response.statusCode === 302 || response.statusCode === 301) { - file.close(); - fs.unlinkSync(dest); - return download(response.headers.location, dest).then(resolve).catch(reject); - } - - if (response.statusCode !== 200) { - file.close(); - fs.unlinkSync(dest); - reject(new Error(`Failed to download: ${response.statusCode}`)); - return; - } - - response.pipe(file); - - file.on('finish', () => { - file.close(); - // Make binary executable on Unix-like systems - if (process.platform !== 'win32') { - fs.chmodSync(dest, 0o755); - } - resolve(); - }); - }).on('error', (err) => { - file.close(); - fs.unlinkSync(dest); - reject(err); - }); - }); -} - -// Download and install -download(binaryUrl, outputFile) - .then(() => { - console.log('✓ orchcli installed successfully!'); - console.log('Run "orchcli --help" to get started.'); - }) - .catch((err) => { - console.error('✗ Failed to download orchcli:', err.message); - console.error('Please visit https://github.com/KubeOrchestra/cli/releases to download manually.'); - process.exit(1); - }); -``` - -### npm README -Create `npm/README.md`: - -```markdown -# @kubeorchestra/orchcli - -OrchCTL - The official CLI for KubeOrchestra development and deployment. - -## Installation - -```bash -npm install -g @kubeorchestra/orchcli -``` - -## Usage - -```bash -# Initialize development environment -orchcli init - -# Start local development -orchcli dev start - -# Deploy to Kubernetes -orchcli deploy -``` - -## Documentation - -Full documentation available at: https://github.com/KubeOrchestra/cli - -## License - -Apache-2.0 -``` - -## Step 2: Configure GoReleaser - -Create `.goreleaser.yml` in the repository root: - -```yaml -project_name: orchcli - -before: - hooks: - - go mod tidy - -builds: - - id: orchcli - main: ./main.go - binary: orchcli - env: - - CGO_ENABLED=0 - goos: - - linux - - darwin - - windows - goarch: - - amd64 - - arm64 - - arm - goarm: - - "7" - ignore: - - goos: windows - goarch: arm64 - - goos: windows - goarch: arm - -archives: - - id: orchcli-archive - format: binary - name_template: "{{ .Binary }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" - -checksum: - name_template: 'checksums.txt' - -snapshot: - name_template: "{{ incpatch .Version }}-next" - -changelog: - sort: asc - filters: - exclude: - - '^docs:' - - '^test:' - - '^chore:' - -release: - github: - owner: KubeOrchestra - name: cli - name_template: "v{{.Version}}" - draft: false - prerelease: auto -``` - -## Step 3: Setup GitHub Actions - -Create `.github/workflows/release.yml`: - -```yaml -name: Release - -on: - push: - tags: - - 'v*' - -permissions: - contents: write - packages: write - -jobs: - goreleaser: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: '1.21' - - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v5 - with: - version: latest - args: release --clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - npm-publish: - needs: goreleaser - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '18' - registry-url: 'https://registry.npmjs.org' - - - name: Update npm package version - run: | - VERSION=${GITHUB_REF#refs/tags/v} - cd npm - npm version $VERSION --no-git-tag-version - echo "Updated package.json to version $VERSION" - - - name: Publish to npm - run: | - cd npm - npm publish --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -``` - -## Step 4: Setup npm Authentication - -### 1. Create npm Account -If you don't have one, create an account at https://www.npmjs.com/ - -### 2. Generate npm Token -```bash -# Login to npm -npm login - -# Generate token -npm token create --read-only=false -``` - -### 3. Add Token to GitHub Secrets -1. Go to https://github.com/KubeOrchestra/cli/settings/secrets/actions -2. Click "New repository secret" -3. Name: `NPM_TOKEN` -4. Value: Your npm token - -## Step 5: Publishing Process - -### Manual Publishing (First Release) - -```bash -# 1. Build and test locally -go build -o orchcli main.go -./orchcli --version - -# 2. Login to npm -npm login - -# 3. Publish npm package -cd npm -npm publish --access public -``` - -### Automated Publishing (Recommended) - -```bash -# 1. Update version in npm/package.json -cd npm -npm version patch # or minor, major - -# 2. Commit changes -git add . -git commit -m "chore: bump version to 0.1.1" - -# 3. Create and push tag -git tag v0.1.1 -git push origin main -git push origin v0.1.1 - -# GitHub Actions will automatically: -# - Build binaries for all platforms -# - Create GitHub release with binaries -# - Publish npm package -``` - -## Step 6: Verify Installation - -After publishing, users can install: - -```bash -# Install globally -npm install -g @kubeorchestra/orchcli - -# Verify installation -orchcli --version -orchcli --help -``` - -## Troubleshooting - -### Binary Download Fails -- Check GitHub release exists with correct tag -- Verify binary names match pattern: `orchcli-{os}-{arch}` -- Check network/proxy settings - -### npm Publish Fails -- Verify npm token is valid -- Check package name availability -- Ensure you're a member of @kubeorchestra org on npm - -### Platform Not Supported -Add platform mapping in `postinstall.js`: -```javascript -const PLATFORM_MAP = { - 'your-platform': 'go-platform-name', - // ... -}; -``` - -## Version Management - -### Semantic Versioning -- MAJOR version: Breaking changes -- MINOR version: New features (backwards compatible) -- PATCH version: Bug fixes - -### Version Sync -Keep versions synchronized: -1. `npm/package.json` - npm package version -2. Git tags - `v0.1.0` format -3. Go binary version - Set in build flags - -## Security Notes - -1. **Checksums**: GoReleaser generates checksums.txt -2. **HTTPS Only**: Downloads use HTTPS -3. **Version Pinning**: npm package downloads specific version -4. **Error Handling**: Graceful failures with helpful messages - -## Testing Before Release - -```bash -# Test npm package locally -cd npm -npm pack -npm install -g kubeorchestra-orchcli-0.1.0.tgz - -# Test binary download -node scripts/postinstall.js - -# Verify installation -orchcli --version -``` \ No newline at end of file