Skip to content

Commit

Permalink
Pre release/refactorings (#5)
Browse files Browse the repository at this point in the history
* Update Go version in go.mod to 1.23
* Adds comments to ExecutableCommand interface and BaseCommand
* Refactor CommandArgs initialization with options pattern
* Refactor command structure and consolidate types.
* Refactor: Centralize command types and update dependencies
* Refactor and reorganize internal packages
  • Loading branch information
matzefriedrich authored Sep 25, 2024
1 parent d748f61 commit 55e96a4
Show file tree
Hide file tree
Showing 35 changed files with 423 additions and 268 deletions.
11 changes: 6 additions & 5 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Set up Go
- name: Setup Go environment
uses: actions/setup-go@v4
with:
go-version: '1.21'
go-version: '1.23'

- name: Test
run: go test -v ./...
- name: Run tests with coverage
run: go test -v -race -covermode atomic -coverprofile=covprofile -coverpkg ./... ./...

14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.0] - cobra-extensions v0.3.0, 2024-09-26

### Added

* Introduced the `types` package to centralize command type definitions.

### Changed

* Updated import paths and references across the project to use the new `types` package.
* Removed type definitions from the `commands` and `reflection` packages; moved interface types to the new `types` package.
* The `reflection` package is now internal because it supports the functionality of the extensions package and is not intended for use by user code.
* Upgraded Go SDK version from 1.21 to 1.23.


## [0.2.6] - cobra-extensions v0.2.6, 2024-08-27

### Added
Expand Down
51 changes: 38 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
[![CI](https://github.com/matzefriedrich/cobra-extensions/actions/workflows/go.yml/badge.svg)](https://github.com/matzefriedrich/cobra-extensions/actions/workflows/go.yml)
[![Go Reference](https://pkg.go.dev/badge/github.com/matzefriedrich/cobra-extensions.svg)](https://pkg.go.dev/github.com/matzefriedrich/cobra-extensions)
[![Go Report Card](https://goreportcard.com/badge/github.com/matzefriedrich/cobra-extensions)](https://goreportcard.com/report/github.com/matzefriedrich/cobra-extensions)
![License](https://img.shields.io/github/license/matzefriedrich/cobra-extensions)
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/matzefriedrich/cobra-extensions)
![GitHub Release](https://img.shields.io/github/v/release/matzefriedrich/cobra-extensions?include_prereleases)

# cobra-extensions

**An extension library for Cobra**, adding a declarative approach to simplify the configuration of commands and flags.
Expand All @@ -13,7 +20,11 @@ $ go get -u github.com/matzefriedrich/cobra-extensions@latest
Next, include Cobra extensions in your application.

````go
import "github.com/matzefriedrich/cobra-extensions/pkg"
import (
"github.com/matzefriedrich/cobra-extensions/pkg/commands"
"github.com/matzefriedrich/cobra-extensions/pkg/types"
"github.com/spf13/cobra"
)
````

## Example
Expand All @@ -25,24 +36,35 @@ package commands

import (
"fmt"

"github.com/matzefriedrich/cobra-extensions/pkg"
"github.com/matzefriedrich/cobra-extensions/pkg/commands"
"github.com/matzefriedrich/cobra-extensions/pkg/types"
"github.com/spf13/cobra"
)

type helloCommand struct {
use pkg.CommandName `flag:"hello"`
Name string `flag:"name" usage:"Your name"`
use types.CommandName `flag:"hello"`
Arguments helloArgs
}

var _ types.TypedCommand = (*helloCommand)(nil)

type helloArgs struct {
types.CommandArgs
Name string
}

func CreateHelloCommand() *cobra.Command {
instance := &helloCommand{}
return pkg.CreateTypedCommand(instance)
instance := &helloCommand{
Arguments: helloArgs{
CommandArgs: types.NewCommandArgs(types.MinimumArgumentsRequired(1)),
}}
return commands.CreateTypedCommand(instance)
}

func (c *helloCommand) Execute() {
_ = fmt.Sprintf("Hello %s.", c.Name)
fmt.Printf("Hello %s.\n", c.Arguments.Name)
}

````

A `CreateHelloCommand` factory method creates a new `helloCommand` instance and utilizes the `CreateTypedCommand` method to create and initialize a Cobra command.
Expand All @@ -52,16 +74,19 @@ package main

import (
"github.com/matzefriedrich/cobra-extensions/example/commands"
"github.com/matzefriedrich/cobra-extensions/pkg/charmer"
"github.com/spf13/cobra"
"os"
)

func main() {

app := &cobra.Command{}
app := charmer.NewRootCommand("simple-example", "")

app.AddCommand(commands.CreateHelloCommand())

app.AddCommand(commands.CreateHelloCommand())

_ = app.Execute()
err := app.Execute()
if err != nil {
panic(err)
}
}
````
3 changes: 2 additions & 1 deletion example/cmd/charmer/charmer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"github.com/matzefriedrich/cobra-extensions/example/commands"
"github.com/matzefriedrich/cobra-extensions/pkg/charmer"
"github.com/matzefriedrich/cobra-extensions/pkg/types"
"log"
)

Expand All @@ -11,7 +12,7 @@ func main() {
err :=
charmer.NewCommandLineApplication("charmer-example", "").
AddCommand(commands.CreateHelloCommand()).
AddGroupCommand(commands.CreateCryptCommand(), func(crypto charmer.CommandSetup) {
AddGroupCommand(commands.CreateCryptCommand(), func(crypto types.CommandSetup) {
crypto.AddCommand(
commands.CreateEncryptMessageCommand(),
commands.CreateDecryptMessageCommand())
Expand Down
12 changes: 6 additions & 6 deletions example/commands/crypto_commands.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package commands

import (
"github.com/matzefriedrich/cobra-extensions/pkg"
"github.com/matzefriedrich/cobra-extensions/pkg/abstractions"
"github.com/matzefriedrich/cobra-extensions/pkg/commands"
"github.com/matzefriedrich/cobra-extensions/pkg/types"
"github.com/spf13/cobra"
)

type cryptoCommand struct {
abstractions.BaseCommand
use abstractions.CommandName `flag:"crypt"`
types.BaseCommand
use types.CommandName `flag:"crypt"`
}

func CreateCryptCommand() *cobra.Command {
instance := &cryptoCommand{
BaseCommand: abstractions.BaseCommand{},
BaseCommand: types.BaseCommand{},
}
return pkg.CreateTypedCommand(instance)
return commands.CreateTypedCommand(instance)
}
10 changes: 5 additions & 5 deletions example/commands/decrypt.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package commands

import (
"github.com/matzefriedrich/cobra-extensions/pkg"
"github.com/matzefriedrich/cobra-extensions/pkg/abstractions"
"github.com/matzefriedrich/cobra-extensions/pkg/commands"
"github.com/matzefriedrich/cobra-extensions/pkg/types"
"io"
"os"

"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/spf13/cobra"
)

var _ abstractions.ExecutableCommand = &decryptMessageCommand{}
var _ types.TypedCommand = &decryptMessageCommand{}

type decryptMessageCommand struct {
cryptCommand
use abstractions.CommandName `flag:"decrypt" short:"Decrypt a message." long:"Reads an armored message from stdin and decrypts it."`
use types.CommandName `flag:"decrypt" short:"Decrypt a message." long:"Reads an armored message from stdin and decrypts it."`
}

func CreateDecryptMessageCommand() *cobra.Command {
instance := &decryptMessageCommand{cryptCommand: cryptCommand{}}
return pkg.CreateTypedCommand(instance)
return commands.CreateTypedCommand(instance)
}

func (d *decryptMessageCommand) Execute() {
Expand Down
12 changes: 6 additions & 6 deletions example/commands/encrypt.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package commands

import (
"github.com/matzefriedrich/cobra-extensions/pkg"
"github.com/matzefriedrich/cobra-extensions/pkg/abstractions"
"github.com/matzefriedrich/cobra-extensions/pkg/commands"
"github.com/matzefriedrich/cobra-extensions/pkg/types"
"os"

"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/spf13/cobra"
)

var _ abstractions.ExecutableCommand = &encryptMessageCommand{}
var _ types.TypedCommand = &encryptMessageCommand{}

type encryptMessageCommand struct {
cryptCommand
use abstractions.CommandName `flag:"encrypt" short:"Encrypt a message." long:"Encrypt a message and protects it with a passphrase."`
Message string `flag:"message" usage:"The message to encrypt."`
use types.CommandName `flag:"encrypt" short:"Encrypt a message." long:"Encrypt a message and protects it with a passphrase."`
Message string `flag:"message" usage:"The message to encrypt."`
}

func CreateEncryptMessageCommand() *cobra.Command {
instance := &encryptMessageCommand{cryptCommand: cryptCommand{}}
return pkg.CreateTypedCommand(instance)
return commands.CreateTypedCommand(instance)
}

func (e *encryptMessageCommand) Execute() {
Expand Down
19 changes: 10 additions & 9 deletions example/commands/hello.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,32 @@ package commands

import (
"fmt"
"github.com/matzefriedrich/cobra-extensions/pkg"
"github.com/matzefriedrich/cobra-extensions/pkg/abstractions"

"github.com/matzefriedrich/cobra-extensions/pkg/commands"

"github.com/matzefriedrich/cobra-extensions/pkg/types"

"github.com/spf13/cobra"
)

// helloCommand A command handler type for the hello command.
type helloCommand struct {
use abstractions.CommandName `flag:"hello"`
use types.CommandName `flag:"hello" short:"Prints a greeting to the specified name."`
Arguments helloArgs
}

// helloArgs Stores values for positional arguments of the hello command.
var _ types.TypedCommand = (*helloCommand)(nil)

type helloArgs struct {
abstractions.CommandArgs
types.CommandArgs
Name string
}

// CreateHelloCommand Creates a new helloCommand instance.
func CreateHelloCommand() *cobra.Command {
instance := &helloCommand{
Arguments: helloArgs{
CommandArgs: abstractions.NewCommandArgs(1),
CommandArgs: types.NewCommandArgs(types.MinimumArgumentsRequired(1)),
}}
return pkg.CreateTypedCommand(instance)
return commands.CreateTypedCommand(instance)
}

func (c *helloCommand) Execute() {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/matzefriedrich/cobra-extensions

go 1.21
go 1.23

require (
github.com/ProtonMail/gopenpgp/v2 v2.7.5
Expand Down
32 changes: 32 additions & 0 deletions internal/reflection/argument_descriptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package reflection

import (
"reflect"
)

// ArgumentDescriptor represents metadata for an argument, including its index, value, and type kind.
type ArgumentDescriptor struct {
argumentIndex int
value reflect.Value
typeKind reflect.Kind
}

// ArgumentIndex returns the index of the argument represented by the ArgumentDescriptor.
func (a *ArgumentDescriptor) ArgumentIndex() int {
return a.argumentIndex
}

// SetString Applies a string argument to the underlying structure.
func (a *ArgumentDescriptor) SetString(value string) {
a.value.SetString(value)
}

// SetInt64 Applies an int64 argument to the underlying structure.
func (a *ArgumentDescriptor) SetInt64(n int64) {
a.value.SetInt(n)
}

// SetBool Applies a boolean argument to the underlying structure.
func (a *ArgumentDescriptor) SetBool(b bool) {
a.value.SetBool(b)
}
58 changes: 58 additions & 0 deletions internal/reflection/arguments_descriptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package reflection

import (
"github.com/matzefriedrich/cobra-extensions/pkg/types"
"github.com/spf13/cobra"
"reflect"
"strconv"
)

// ArgumentsDescriptor Stores arguments metadata.
type argumentsDescriptor struct {
minimumArgs int
args []ArgumentDescriptor
}

var _ types.ArgumentsDescriptor = (*argumentsDescriptor)(nil)

// BindArguments sets the minimum number of positional arguments required for the given Cobra command.
func (d *argumentsDescriptor) BindArguments(target *cobra.Command) {
target.Args = cobra.MinimumNArgs(d.minimumArgs)
}

// BindArgumentValues Sets the given set of values to positional argument fields.
func (d *argumentsDescriptor) BindArgumentValues(args ...string) {
for _, a := range d.args {
index := a.argumentIndex
if index < len(args) {
value := args[index]
switch a.typeKind {
case reflect.String:
a.SetString(value)
case reflect.Int64:
n, err := strconv.ParseInt(value, 10, 64)
if err == nil {
a.SetInt64(n)
}
case reflect.Bool:
b, err := strconv.ParseBool(value)
if err == nil {
a.SetBool(b)
}
default:
panic("unsupported type")
}
}
}
}

// NewArgumentsDescriptorWith Creates a new ArgumentsDescriptor.
func NewArgumentsDescriptorWith(options ...types.ArgumentsDescriptorOption) types.ArgumentsDescriptor {
argumentsDescriptor := &argumentsDescriptor{
args: make([]ArgumentDescriptor, 0),
}
for _, option := range options {
option(argumentsDescriptor)
}
return argumentsDescriptor
}
Loading

0 comments on commit 55e96a4

Please sign in to comment.