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
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
.vscode
.vagrant
dist
docs
website
vendor
helm
10 changes: 2 additions & 8 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,12 @@
/pkg/ @skyoo2003
/api/ @skyoo2003

# Root library
/kvs.go @skyoo2003

# Documentation
/content/ @skyoo2003
/docs/ @skyoo2003
/website/ @skyoo2003

# CI/CD and GitHub config
/.github/ @skyoo2003

# Build and release
/.goreleaser.yml @skyoo2003
/build/ @skyoo2003
/Makefile @skyoo2003
/Dockerfile @skyoo2003
/Dockerfile.goreleaser @skyoo2003
5 changes: 2 additions & 3 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ documentation:
- changed-files:
- any-glob-to-any-file:
- "*.md"
- "docs/**"
- "content/**"
- "website/**"

dependencies:
- changed-files:
Expand All @@ -28,4 +27,4 @@ github_actions:
docker:
- changed-files:
- any-glob-to-any-file:
- "Dockerfile*"
- "build/package/Dockerfile*"
16 changes: 8 additions & 8 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ on:
- "**/*.go"
- "go.mod"
- "go.sum"
- "Dockerfile"
- "Dockerfile.goreleaser"
- "build/package/Dockerfile"
- "build/package/Dockerfile.goreleaser"
- ".dockerignore"
- ".goreleaser.yml"
- "build/package/goreleaser.yaml"
- ".github/workflows/cd.yml"
pull_request:
branches: [main]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- "Dockerfile"
- "Dockerfile.goreleaser"
- "build/package/Dockerfile"
- "build/package/Dockerfile.goreleaser"
- ".dockerignore"
- ".goreleaser.yml"
- "build/package/goreleaser.yaml"
- ".github/workflows/cd.yml"

concurrency:
Expand Down Expand Up @@ -52,7 +52,7 @@ jobs:
- uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
file: build/package/Dockerfile
push: ${{ github.event_name == 'push' }}
load: ${{ github.event_name == 'pull_request' }}
tags: |
Expand Down Expand Up @@ -90,4 +90,4 @@ jobs:
uses: goreleaser/goreleaser-action@v7.2.3
with:
version: "~> v2"
args: release --snapshot --clean
args: release --snapshot --clean --config build/package/goreleaser.yaml
14 changes: 4 additions & 10 deletions .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,15 @@ on:
- main
paths:
- ".github/workflows/docs.yaml"
- "hugo.toml"
- "content/**"
- "layouts/**"
- "static/**"
- "website/**"
- "README.md"
- "CONTRIBUTING.md"
pull_request:
branches:
- main
paths:
- ".github/workflows/docs.yaml"
- "hugo.toml"
- "content/**"
- "layouts/**"
- "static/**"
- "website/**"
- "README.md"
- "CONTRIBUTING.md"
workflow_dispatch:
Expand Down Expand Up @@ -52,12 +46,12 @@ jobs:
hugo-version: '0.148.2'

- name: Build documentation site
run: hugo build --gc --minify
run: hugo --source website build --gc --minify

- name: Upload documentation artifact
uses: actions/upload-pages-artifact@v5
with:
path: public
path: website/public

deploy:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
uses: goreleaser/goreleaser-action@v7.2.3
with:
version: "~> v2"
args: release --clean --release-notes changes/${{ github.ref_name }}.md
args: release --clean --config build/package/goreleaser.yaml --release-notes changes/${{ github.ref_name }}.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_TOKEN: ${{ steps.tap_token.outputs.token }}
Expand Down
7 changes: 4 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Thumbs.db
*.swp
.vscode/
.idea/
.serena/

# Go
vendor/
Expand All @@ -25,6 +26,6 @@ coverage.html
dist/

# Hugo
/public/
/resources/
/.hugo_build.lock
/website/public/
/website/resources/
/website/.hugo_build.lock
35 changes: 29 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,41 @@ Thanks for your interest in contributing!

```
.
├── kvs.go # Store (Get, Put, Delete), in memory unless Open gives it a log
├── log.go # Append log the keyspace survives a restart through
├── replication.go # The store methods a cluster drives the keyspace through
├── cmd/kvs/ # CLI entrypoint (Cobra)
├── cmd/kvs/ # Thin CLI entrypoint
├── pkg/kvs/ # Public Store library and append log
├── internal/app/kvs/ # Cobra/Viper CLI application
├── internal/server/ # HTTP, gRPC, and RESP server implementations
├── internal/cluster/ # Raft membership, kept out of the library API
├── api/kvsv1/ # Generated protobuf/gRPC code
├── pkg/resp/ # RESP2 wire protocol codec
├── content/ # Hugo documentation site
├── internal/resp/ # Private RESP2 wire protocol codec
├── website/ # Hugo documentation site
└── changes/ # Changelog fragments (Changie)
```

### Project Layout Guidelines

Follow [golang-standards/project-layout](https://github.com/golang-standards/project-layout)
where it fits this repository. Create directories only when they have a clear purpose; do not
add empty placeholders or a top-level `src/` directory.

- `cmd/<binary>/` contains a minimal `main` package that wires arguments, standard streams, and
build metadata into an internal application package.
- `internal/app/<binary>/` owns CLI composition. `internal/` owns code that external Go modules
must not import, including server, cluster, persistence, and protocol implementation.
- `pkg/<library>/` contains libraries intentionally supported for external import. Public KVS
code belongs in `pkg/kvs`; do not add non-public packages under `pkg/`.
- `api/` contains source protocol contracts and generated API bindings.
- `build/package/` contains Docker and release-packaging configuration. Keep tool-required
workflow files and repository-root configuration at their required locations.
- `website/` contains the Hugo project; do not commit its generated `public/` and `resources/`
directories.
- Keep unit tests next to their packages and package-specific Go test fixtures in that package's
`testdata/` directory.

When relocating code, preserve public import paths and behavior unless a change explicitly
authorizes a breaking API migration. Update imports, build/release automation, ownership rules,
and documentation in the same change.

## Getting Started

1. **Fork** the repository
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A key-value store you can run as a server or import as a Go module.

[![CI](https://github.com/skyoo2003/kvs/actions/workflows/ci.yaml/badge.svg)](https://github.com/skyoo2003/kvs/actions/workflows/ci.yaml) [![Go Reference](https://pkg.go.dev/badge/github.com/skyoo2003/kvs.svg)](https://pkg.go.dev/github.com/skyoo2003/kvs) [![Go Report Card](https://goreportcard.com/badge/github.com/skyoo2003/kvs)](https://goreportcard.com/report/github.com/skyoo2003/kvs)
[![CI](https://github.com/skyoo2003/kvs/actions/workflows/ci.yaml/badge.svg)](https://github.com/skyoo2003/kvs/actions/workflows/ci.yaml) [![Go Reference](https://pkg.go.dev/badge/github.com/skyoo2003/kvs/pkg/kvs.svg)](https://pkg.go.dev/github.com/skyoo2003/kvs/pkg/kvs) [![Go Report Card](https://goreportcard.com/badge/github.com/skyoo2003/kvs)](https://goreportcard.com/report/github.com/skyoo2003/kvs)

## Features

Expand All @@ -13,7 +13,7 @@ A key-value store you can run as a server or import as a Go module.
- **Durability** — `--data-dir` appends every change to a log and replays it at startup, so the keyspace survives a restart
- **Clustering** — `--raft-addr` joins a Raft cluster, so losing the leader costs an election rather than a person
- **Cobra/Viper CLI** — `serve` command with configurable listen addresses
- **Library** — import `github.com/skyoo2003/kvs` directly in Go programs
- **Library** — import `github.com/skyoo2003/kvs/pkg/kvs` in Go programs
- **Docker** — container images published to `ghcr.io/skyoo2003/kvs`

## Installation
Expand Down Expand Up @@ -55,7 +55,7 @@ package main

import (
"fmt"
"github.com/skyoo2003/kvs"
"github.com/skyoo2003/kvs/pkg/kvs"
)

func main() {
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion .goreleaser.yml → build/package/goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ homebrew_casks:
dockers_v2:
- images:
- ghcr.io/skyoo2003/kvs
dockerfile: Dockerfile.goreleaser
dockerfile: build/package/Dockerfile.goreleaser
ids:
- kvs
platforms:
Expand Down
75 changes: 2 additions & 73 deletions cmd/kvs/main.go
Original file line number Diff line number Diff line change
@@ -1,88 +1,17 @@
// Package main implements to execute the program.
package main

import (
"fmt"
"io"
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"
app "github.com/skyoo2003/kvs/internal/app/kvs"
)

var version = "dev"

func main() {
if err := execute(os.Args[1:], os.Stdout, os.Stderr); err != nil {
if err := app.Execute(os.Args[1:], os.Stdout, os.Stderr, version); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

func execute(args []string, stdout, stderr io.Writer) error {
cmd := newRootCmd(stdout, stderr)
cmd.SetArgs(args)

return cmd.Execute()
}

func newRootCmd(stdout, stderr io.Writer) *cobra.Command {
var cfgFile string
var showVersion bool

rootCmd := &cobra.Command{
Use: "kvs",
Short: "A simple key-value store CLI",
Args: cobra.NoArgs,
SilenceErrors: true,
SilenceUsage: true,
PersistentPreRunE: func(_ *cobra.Command, _ []string) error {
return initConfig(cfgFile)
},
RunE: func(cmd *cobra.Command, _ []string) error {
if showVersion {
_, err := fmt.Fprintln(cmd.OutOrStdout(), version)
return err
}

return cmd.Help()
},
}

rootCmd.SetOut(stdout)
rootCmd.SetErr(stderr)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file path")
rootCmd.Flags().BoolVarP(&showVersion, "version", "v", false, "print version")
rootCmd.AddCommand(newVersionCmd())
rootCmd.AddCommand(newServeCmd())

return rootCmd
}

func newVersionCmd() *cobra.Command {
return &cobra.Command{
Use: "version",
Short: "Print the CLI version",
SilenceErrors: true,
SilenceUsage: true,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
_, err := fmt.Fprintln(cmd.OutOrStdout(), version)
return err
},
}
}

func initConfig(cfgFile string) error {
viper.Reset()
viper.SetEnvPrefix("KVS")
viper.AutomaticEnv()

if cfgFile == "" {
return nil
}

viper.SetConfigFile(cfgFile)

return viper.ReadInConfig()
}
Loading
Loading