Skip to content

Commit

Permalink
all: basic commands done (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
fioncat authored Dec 9, 2024
1 parent 3d747ae commit 5483ee5
Show file tree
Hide file tree
Showing 42 changed files with 2,918 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
24 changes: 24 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Build Go

on:
push:
branches:
- "main"
pull_request:
branches:
- "main"

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up go
uses: actions/setup-go@v5
with:
go-version: 'stable'

- name: Build
run: make build
27 changes: 27 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Check Go

on:
push:
branches:
- "main"
pull_request:
branches:
- "main"

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up go
uses: actions/setup-go@v5
with:
go-version: 'stable'

- name: Check Go
run: make check

- name: Test Go
run: make test
32 changes: 32 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Release

on:
push:
tags:
- '*'

permissions:
contents: write

jobs:
release:
if: contains(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up go
uses: actions/setup-go@v5
with:
go-version: 'stable'

- name: Build Go
run: make cross

- name: Create release
uses: softprops/action-gh-release@v2
with:
draft: true
files: |
bin/*.tar.gz
17 changes: 17 additions & 0 deletions .github/workflows/typos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Spell Check

on:
push:
branches:
- "main"
pull_request:
branches:
- "main"

jobs:
spell-check:
name: Spell Check with Typos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crate-ci/typos@master
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ go.work.sum

# env file
.env

/bin
45 changes: 45 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
COMMIT_ID=$(shell git rev-parse HEAD)
COMMIT_ID_SHORT=$(shell git rev-parse --short HEAD)

TAG=$(shell git describe --tags --abbrev=0 2>/dev/null)

DATE=$(shell date '+%FT%TZ')

# If current commit is tagged, use tag as version, else, use dev-${COMMIT_ID} as version
VERSION=$(shell git tag --points-at ${COMMIT_ID})
VERSION:=$(if $(VERSION),$(VERSION),dev-${COMMIT_ID_SHORT})

.PHONY: build
build:
@bash build.sh

.PHONY: install
install:
@bash build.sh "install"

.PHONY: cross
cross:
@bash build.sh "linux" "amd64"
@tar -czf bin/kubewrap-linux-amd64.tar.gz -C bin kubewrap
@bash build.sh "linux" "arm64"
@tar -czf bin/kubewrap-linux-arm64.tar.gz -C bin kubewrap
@bash build.sh "darwin" "arm64"
@tar -czf bin/kubewrap-darwin-arm64.tar.gz -C bin kubewrap
@bash build.sh "darwin" "amd64"
@tar -czf bin/kubewrap-darwin-amd64.tar.gz -C bin kubewrap

.PHONY: test
test:
@CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go test ./...

.PHONY: fmt
fmt:
@find . -name \*.go -exec goimports -w {} \;

.PHONY: check
check:
@CGO_ENABLED=0 go vet ./...

.PHONY: typos
typos:
@typos ./
49 changes: 49 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/bash

GIT_DESC=$(git describe --tags 2> /dev/null)
GIT_TAG=$(git describe --tags --abbrev=0 2> /dev/null)
GIT_COMMIT=$(git rev-parse HEAD)
GIT_COMMIT_SHORT=$(git rev-parse --short HEAD)

if [[ "$GIT_DESC" == "$GIT_TAG" ]]; then
BUILD_TYPE="stable"
BUILD_VERSION="$GIT_TAG"
else
BUILD_TYPE="dev"
BUILD_VERSION="${GIT_TAG}-dev_${GIT_COMMIT_SHORT}"
fi

if [[ -z "$BUILD_VERSION" ]]; then
BUILD_TYPE="dev"
BUILD_VERSION="dev_${GIT_COMMIT_SHORT}"
fi

if git status --porcelain | grep -E '(M|A|D|R|\?)' > /dev/null; then
BUILD_TYPE="dev-uncommitted"
BUILD_VERSION="${BUILD_VERSION}-uncommitted"
fi

cat << EOF
Build Args:
GIT_DESC=${GIT_DESC}
GIT_TAG=${GIT_TAG}
GIT_COMMIT=${GIT_COMMIT}
GIT_COMMIT_SHORT=${GIT_COMMIT_SHORT}
BUILD_TYPE=${BUILD_TYPE}
BUILD_VERSION=${BUILD_VERSION}
EOF

BUILD_FLAGS="-X main.Version=${BUILD_VERSION} -X main.BuildType=${BUILD_TYPE} -X main.BuildCommit=${GIT_COMMIT} -X main.BuildTime=$(date +%F-%Z/%T)"

echo ""
if [[ "$1" == "install" ]]; then
echo "Install kubewrap..."
CGO_ENABLED=0 go install -ldflags "${BUILD_FLAGS}"
else
echo "Build kubewrap..."
CGO_ENABLED=0 GOOS="$1" GOARCH="$2" go build -ldflags "${BUILD_FLAGS}" -o ./bin/kubewrap
fi
if [[ $? -ne 0 ]]; then
echo "Build kubewrap failed"
exit 1
fi
64 changes: 64 additions & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"fmt"

"github.com/fioncat/kubewrap/config"
"github.com/fioncat/kubewrap/pkg/kubectl"
"github.com/fioncat/kubewrap/pkg/term"
"github.com/spf13/cobra"
)

type Context struct {
Command *cobra.Command
Config *config.Config
Kubectl kubectl.Kubectl
}

type Validator interface {
Validate(c *cobra.Command, args []string) error
}

type Options interface {
Validator
Run(cmdctx *Context) error
}

func Build(c *cobra.Command, opts Options) *cobra.Command {
var (
printConfig bool
configPath string
useDefaultConfig bool
)

c.RunE = func(cmd *cobra.Command, args []string) error {
err := opts.Validate(cmd, args)
if err != nil {
return fmt.Errorf("validate command args: %w", err)
}

cfg, err := config.Load(configPath, useDefaultConfig)
if err != nil {
return fmt.Errorf("load config: %w", err)
}

if printConfig {
return term.PrintJson(cfg)
}

kubectl := kubectl.NewCommand(cfg.Kubectl.Name, cfg.Kubectl.Args)
cmdctx := &Context{
Command: cmd,
Config: cfg,
Kubectl: kubectl,
}

return opts.Run(cmdctx)
}

c.Flags().StringVarP(&configPath, "config", "", "", "config file path")
c.Flags().BoolVarP(&useDefaultConfig, "default-config", "", false, "force to use default config")
c.Flags().BoolVarP(&printConfig, "print-config", "", false, "print the config and exit (skip main process), useful for debug")

return c
}
102 changes: 102 additions & 0 deletions cmd/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package cmd

import (
"fmt"
"os"
"path/filepath"

"github.com/fioncat/kubewrap/config"
"github.com/fioncat/kubewrap/pkg/kubeconfig"
"github.com/fioncat/kubewrap/pkg/kubectl"
"github.com/spf13/cobra"
)

func GetCompleteConfig(c *cobra.Command) *config.Config {
configPath := c.Flags().Lookup("config").Value.String()
useDefaultConfig := c.Flags().Lookup("default-config").Value.String() == "true"
cfg, err := config.Load(configPath, useDefaultConfig)
if err != nil {
WriteCompleteLogs("Load config failed: %v", err)
return nil
}
return cfg
}

func GetCompleteKubeconfigManager(c *cobra.Command) kubeconfig.Manager {
cfg := GetCompleteConfig(c)
if cfg == nil {
return nil
}

mgr, err := kubeconfig.NewManager(cfg.KubeConfig.Root, cfg.KubeConfig.Alias)
if err != nil {
WriteCompleteLogs("Create kubeconfig manager failed: %v", err)
return nil
}

return mgr
}

func getCompleteKubectl(c *cobra.Command) kubectl.Kubectl {
printConfig := c.Flags().Lookup("print-config").Value.String() == "true"
if printConfig {
WriteCompleteLogs("In print config mode, skip completion")
return nil
}

cfg := GetCompleteConfig(c)
if cfg == nil {
return nil
}

return kubectl.NewCommand(cfg.Kubectl.Name, cfg.Kubectl.Args)
}

func CompleteNodeItems(c *cobra.Command) ([]string, bool) {
nodes, ok := CompleteNodes(c)
if !ok {
return nil, false
}
items := make([]string, 0, len(nodes))
for _, node := range nodes {
items = append(items, fmt.Sprintf("%s\t%s", node.Name, node.Description))
}
return items, true
}

func CompleteNodes(c *cobra.Command) ([]*kubectl.Node, bool) {
kubectl := getCompleteKubectl(c)
if kubectl == nil {
return nil, false
}

nodes, err := kubectl.ListNodes()
if err != nil {
WriteCompleteLogs("List nodes failed: %v", err)
return nil, false
}
return nodes, true
}

func SingleNodeCompletionFunc(c *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
items, ok := CompleteNodeItems(c)
if !ok {
return nil, cobra.ShellCompDirectiveError
}

return items, cobra.ShellCompDirectiveNoFileComp
}

func WriteCompleteLogs(format string, args ...any) {
logs := fmt.Sprintf(format+"\n", args...)
path := filepath.Join(os.TempDir(), "kubewrap_complete.log")
file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return
}
defer file.Close()
_, _ = file.WriteString(logs)
}
Loading

0 comments on commit 5483ee5

Please sign in to comment.