Skip to content
Merged
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
17 changes: 16 additions & 1 deletion .github/workflows/docs-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ jobs:
- name: Checkout kubara repo
uses: actions/checkout@v6

- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: src/go.mod
cache: true
cache-dependency-path: src/go.sum

- name: Install and setup uv
uses: astral-sh/setup-uv@v8.1.0
with:
Expand All @@ -40,4 +47,12 @@ jobs:
run: uv sync --frozen

- name: Validate docs build (strict)
run: uv run mkdocs build --strict
run: make docs-build

- name: Check command docs is up to date
run: |
if ! git diff-index --quiet HEAD -- docs; then
echo "::error::Commands document isn't up to date:"
echo "::error::Please run 'make docs-build' locally to fix it."
exit 1
fi
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ docs-serve-dev:
@$(MAKE) -C docs serve-dev

docs-build:
@$(MAKE) -C src docs
@$(MAKE) -C docs build

docs-deploy:
Expand Down
154 changes: 154 additions & 0 deletions docs/content/1_getting_started/commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# kubara commands

# NAME

kubara - Opinionated CLI for Kubernetes platform engineering

# SYNOPSIS

kubara

```
[--base64]
[--catalog-overwrite]
[--catalog]=[value]
[--check-update]
[--config-file|-c]=[value]
[--decode]
[--encode]
[--env-file]=[value]
[--file]=[value]
[--help|-h]
[--kubeconfig]=[value]
[--string]=[value]
[--test-connection]
[--version|-v]
[--work-dir|-w]=[value]
```

# DESCRIPTION

kubara is an opinionated CLI to bootstrap and operate Kubernetes platforms with GitOps-first workflows.

**Usage**:

```
kubara [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]
```

# GLOBAL OPTIONS

**--base64**: Enable base64 encode/decode mode

**--catalog**="": Path to external ServiceDefinition catalog directory.

**--catalog-overwrite**: Allow external service definitions from --catalog to overwrite built-in definitions on name collisions.

**--check-update**: Check online for a newer kubara release

**--config-file, -c**="": Path to the configuration file (default: "config.yaml")

**--decode**: Base64 decode input

**--encode**: Base64 encode input

**--env-file**="": Path to the .env file (default: ".env")

**--file**="": Input file path for base64 operation

**--help, -h**: show help

**--kubeconfig**="": Path to kubeconfig file (default: "~/.kube/config")

**--string**="": Input string for base64 operation

**--test-connection**: Check if Kubernetes cluster can be reached. List namespaces and exit

**--version, -v**: print the version

**--work-dir, -w**="": Working directory (default: ".")


# COMMANDS

## init

Initialize a new kubara directory

**--envVarPrefix**="": Prefix for envs read from envVars (default: "KUBARA_")

**--help, -h**: show help

**--overwrite**: Overwrite config if exists

**--prep**: Copy embedded prep/ folder into current working directory

### help, h

Shows a list of commands or help for one command

## generate

generates files from embedded templates and the config file; by default for both Helm and Terraform

>generate [--terraform|--helm] [--managed-catalog <path> --overlay-values <path>] [--catalog <path> [--catalog-overwrite]] [--dry-run]

**--dry-run**: Preview generation without creating files

**--helm**: Only generate Helm files

**--help, -h**: show help

**--managed-catalog**="": Path to the managed catalog directory. (default: "managed-service-catalog")

**--overlay-values**="": Path to overlay values directory. (default: "customer-service-catalog")

**--terraform**: Only generate Terraform files

### help, h

Shows a list of commands or help for one command

## bootstrap

Bootstrap ArgoCD onto the specified cluster with optional external-secrets and prometheus CRD

**--dry-run**: Run with dry-run

**--envVarPrefix**="": Prefix for envs read from envVars (default: "KUBARA_")

**--help, -h**: show help

**--managed-catalog**="": Path to the managed catalog directory (default: "managed-service-catalog")

**--overlay-values**="": Path to overlay values directory (default: "customer-service-catalog")

**--timeout**="": Timeout for kubernetes API calls (e.g. 10s, 1m) (default: 5m0s)

**--with-es-crds**: Also install external-secrets

**--with-es-css-file**="": Path to the ClusterSecretStore manifest file (supports go-template + sprig)

**--with-prometheus-crds**: Also install kube-prometheus-stack

### help, h

Shows a list of commands or help for one command

## schema

Generate JSON schema file for config structure

>schema [--output] [--catalog <path> [--catalog-overwrite]]

**--help, -h**: show help

**--output, -o**="": Output file path for the JSON schema (default: "config.schema.json")

### help, h

Shows a list of commands or help for one command

## help, h

Shows a list of commands or help for one command
18 changes: 18 additions & 0 deletions docs/content/1_getting_started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,21 @@ On macOS you can also use:
```bash
shasum -a 256 kubara_<version>_<os>_<arch>.<ext>
```

## Shell Completion

kubara supports shell completion for bash, zsh, fish and powershell.

```shell
# add the following line to your .bashrc
$ source <(kubara completion bash)
# or for zsh
$ source <(kubara completion zsh)
# after loading your rc file or opening a new terminal you will have tab completion for kubara
$ kubara <tab>
bootstrap -- Bootstrap ArgoCD onto the specified cluster with optional external-secrets and prometheus CRD
generate -- generates files from embedded templates and the config file; by default for both Helm and Terraform
help -- Shows a list of commands or help for one command
init -- Initialize a new kubara directory
schema -- Generate JSON schema file for config structure
```
1 change: 1 addition & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ nav:
- Bootstrapping: 1_getting_started/bootstrapping.md
- Providers:
- STACKIT: 1_getting_started/providers/stackit.md
- Commands: 1_getting_started/commands.md
- Managing Your Platform:
- Add Spoke Cluster: 2_managing_your_platform/add_spoke_cluster.md
- Add Project: 2_managing_your_platform/add_app_project.md
Expand Down
5 changes: 5 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ format:
@echo "Formatting Go code..."
@go fmt ./...

# Update command docs
docs:
@echo "Updating command docs..."
@go run main.go --docs ../docs/content/1_getting_started/commands.md

# Lint code (requires golangci-lint)
lint:
@echo "Linting Go code..."
Expand Down
10 changes: 10 additions & 0 deletions src/cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type GlobalFlags struct {
CatalogPath string
CatalogOverwrite bool
TestK8sConnection bool
DocsOutputPath string
Base64Mode bool
EncodeFlag bool
DecodeFlag bool
Expand All @@ -41,6 +42,7 @@ type RootOptions struct {
KubeconfigFilePath string
TestK8sConnection bool
CheckUpdateFlag bool
DocsOutputPath string
Base64Mode bool
Base64 Base64Options
}
Expand All @@ -66,6 +68,7 @@ func (flags *GlobalFlags) ToRootOptions() RootOptions {
KubeconfigFilePath: kubeconfigFilePath,
TestK8sConnection: flags.TestK8sConnection,
CheckUpdateFlag: flags.CheckUpdateFlag,
DocsOutputPath: flags.DocsOutputPath,
Base64Mode: flags.Base64Mode,
Base64: Base64Options{
Encode: flags.EncodeFlag,
Expand Down Expand Up @@ -123,6 +126,13 @@ func (flags *GlobalFlags) CLIFlags() []cli.Flag {
Usage: "Check if Kubernetes cluster can be reached. List namespaces and exit",
Destination: &flags.TestK8sConnection,
},
&cli.StringFlag{
Name: "docs",
Value: flags.DocsOutputPath,
Usage: "Output file path for generated command docs",
Destination: &flags.DocsOutputPath,
Hidden: true,
},
&cli.BoolFlag{
Name: "base64",
Value: flags.Base64Mode,
Expand Down
55 changes: 48 additions & 7 deletions src/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

"github.com/kubara-io/kubara/internal/k8s"
"github.com/kubara-io/kubara/internal/updatecheck"
"github.com/rs/zerolog/log"
docs "github.com/urfave/cli-docs/v3"
"github.com/urfave/cli/v3"
)

Expand All @@ -22,18 +24,24 @@ var Authors = []any{
var version string

type rootActionDeps struct {
notifyUpdate func(string)
checkUpdate func(string) error
testConnection func(string)
writeDocs func(*cli.Command, string) error
}

var defaultRootActionDeps = rootActionDeps{
notifyUpdate: func(ver string) {
updatecheck.NotifyIfNewReleaseAvailable(ver, os.Stderr)
},
checkUpdate: func(ver string) error {
if err := updatecheck.PrintLiveCheck(ver, os.Stdout); err != nil {
return cli.Exit(fmt.Sprintf("Error: update check failed: %v", err), 1)
}
return nil
},
testConnection: testConnection,
writeDocs: writeCommandDocs,
}

// NewRootCmd builds and returns the root CLI command. ver is injected from
Expand All @@ -43,26 +51,37 @@ func NewRootCmd(ver string) *cli.Command {
globalFlags := NewGlobalFlags()

return &cli.Command{
Name: AppName,
Version: ver,
Authors: Authors,
Copyright: "",
Usage: "Opinionated CLI for Kubernetes platform engineering",
Description: "kubara is an opinionated CLI to bootstrap and operate Kubernetes platforms with GitOps-first workflows.",
Flags: globalFlags.CLIFlags(),
Name: AppName,
Version: ver,
Authors: Authors,
Copyright: "",
Usage: "Opinionated CLI for Kubernetes platform engineering",
Description: "kubara is an opinionated CLI to bootstrap and operate Kubernetes platforms with GitOps-first workflows.",
Flags: globalFlags.CLIFlags(),
EnableShellCompletion: true,
Commands: []*cli.Command{
NewInitCmd(),
NewGenerateCmd(),
NewBootstrapCmd(),
NewSchemaCmd(),
},
Before: func(ctx context.Context, _ *cli.Command) (context.Context, error) {
if shouldNotifyStartupUpdate(globalFlags.ToRootOptions()) {
defaultRootActionDeps.notifyUpdate(ver)
}
return ctx, nil
},
Action: func(_ context.Context, cmd *cli.Command) error {
return newAppAction(cmd, globalFlags.ToRootOptions(), defaultRootActionDeps)
},
}
}

func newAppAction(cmd *cli.Command, options RootOptions, deps rootActionDeps) error {
if strings.TrimSpace(options.DocsOutputPath) != "" {
return deps.writeDocs(cmd, options.DocsOutputPath)
}

if options.Base64Mode {
return runBase64Mode(options.Base64)
}
Expand All @@ -82,6 +101,28 @@ func newAppAction(cmd *cli.Command, options RootOptions, deps rootActionDeps) er
return nil
}

func shouldNotifyStartupUpdate(options RootOptions) bool {
return !options.CheckUpdateFlag && strings.TrimSpace(options.DocsOutputPath) == ""
}

func writeCommandDocs(app *cli.Command, outputPath string) error {
md, err := docs.ToMarkdown(app)
if err != nil {
return fmt.Errorf("create markdown: %w", err)
}

if err := os.MkdirAll(filepath.Dir(outputPath), 0o755); err != nil {
return fmt.Errorf("create docs directory: %w", err)
}

if err := os.WriteFile(outputPath, []byte("# kubara commands\n\n"+md), 0o644); err != nil {
return fmt.Errorf("write docs file: %w", err)
}

log.Info().Str("path", outputPath).Msg("successfully created docs")
return nil
}

func executeRootAction(options RootOptions, deps rootActionDeps) error {
switch {
case options.TestK8sConnection:
Expand Down
Loading
Loading