diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 68ff96c5..362b3335 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -30,7 +30,7 @@ on:
- main
env:
- VERSION_NUMBER: 'v1.7.3'
+ VERSION_NUMBER: 'v1.7.4'
DOCKERHUB_REGISTRY_NAME: 'digitalghostdev/poke-cli'
AWS_REGION: 'us-west-2'
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 38286ad4..04c0950f 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -14,7 +14,7 @@ builds:
- windows
- darwin
ldflags:
- - -s -w -X main.version=v1.7.3
+ - -s -w -X main.version=v1.7.4
archives:
- formats: [ 'zip' ]
diff --git a/Dockerfile b/Dockerfile
index 3b3f34f2..8db3b266 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# build 1
-FROM golang:1.24.6-alpine3.22 AS build
+FROM golang:1.24.9-alpine3.22 AS build
WORKDIR /app
@@ -8,7 +8,7 @@ RUN go mod download
COPY . .
-RUN go build -ldflags "-X main.version=v1.7.3" -o poke-cli .
+RUN go build -ldflags "-X main.version=v1.7.4" -o poke-cli .
# build 2
FROM --platform=$BUILDPLATFORM alpine:3.22
diff --git a/README.md b/README.md
index 1f939c28..a4529df4 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
Pokémon CLI
-
+
@@ -94,11 +94,11 @@ Cloudsmith is a fully cloud-based service that lets you easily create, store, an
3. Choose how to interact with the container:
* Run a single command and exit:
```bash
- docker run --rm -it digitalghostdev/poke-cli:v1.7.3 [subcommand] flag]
+ docker run --rm -it digitalghostdev/poke-cli:v1.7.4 [subcommand] flag]
```
* Enter the container and use its shell:
```bash
- docker run --rm -it --name poke-cli --entrypoint /bin/sh digitalghostdev/poke-cli:v1.7.3 -c "cd /app && exec sh"
+ docker run --rm -it --name poke-cli --entrypoint /bin/sh digitalghostdev/poke-cli:v1.7.4 -c "cd /app && exec sh"
# placed into the /app directory, run the program with './poke-cli'
# example: ./poke-cli ability swift-swim
```
diff --git a/card_data/pipelines/poke_cli_dbt/dbt_project.yml b/card_data/pipelines/poke_cli_dbt/dbt_project.yml
index 74a0c6c4..104f295f 100644
--- a/card_data/pipelines/poke_cli_dbt/dbt_project.yml
+++ b/card_data/pipelines/poke_cli_dbt/dbt_project.yml
@@ -1,5 +1,5 @@
name: 'poke_cli_dbt'
-version: '1.7.3'
+version: '1.7.4'
profile: 'poke_cli_dbt'
diff --git a/cli.go b/cli.go
index 2752f612..cca5a412 100644
--- a/cli.go
+++ b/cli.go
@@ -130,7 +130,10 @@ func runCLI(args []string) int {
mainFlagSet.Usage()
return 1
case *latestFlag || *shortLatestFlag:
- _, _ = flags.LatestFlag()
+ _, err := flags.LatestFlag()
+ if err != nil {
+ return 1
+ }
return 0
case *currentVersionFlag || *shortCurrentVersionFlag:
currentVersion()
diff --git a/cmd/utils/validateargs_test.go b/cmd/utils/validateargs_test.go
index 8094c978..99c60dc0 100644
--- a/cmd/utils/validateargs_test.go
+++ b/cmd/utils/validateargs_test.go
@@ -182,6 +182,125 @@ func TestValidatePokemonArgs(t *testing.T) {
}
}
+// TestValidateBerryArgs tests the ValidateBerryArgs function
+func TestValidateBerryArgs(t *testing.T) {
+ validInputs := [][]string{
+ {"poke-cli", "berry"},
+ {"poke-cli", "berry", "--help"},
+ }
+
+ for _, input := range validInputs {
+ err := ValidateBerryArgs(input)
+ require.NoError(t, err, "Expected no error for valid input")
+ }
+
+ invalidInputs := [][]string{
+ {"poke-cli", "berry", "oran"},
+ }
+
+ for _, input := range invalidInputs {
+ err := ValidateBerryArgs(input)
+ require.Error(t, err, "Expected error for invalid input")
+ }
+
+ tooManyArgs := [][]string{
+ {"poke-cli", "berry", "oran", "sitrus"},
+ }
+
+ expectedError := styling.StripANSI("╭──────────────────╮\n│✖ Error! │\n│Too many arguments│\n╰──────────────────╯")
+
+ for _, input := range tooManyArgs {
+ err := ValidateBerryArgs(input)
+
+ if err == nil {
+ t.Fatalf("Expected an error for input %v, but got nil", input)
+ }
+
+ strippedErr := styling.StripANSI(err.Error())
+ assert.Equal(t, expectedError, strippedErr, "Unexpected error message for invalid input")
+ }
+}
+
+// TestValidateItemArgs tests the ValidateItemArgs function
+func TestValidateItemArgs(t *testing.T) {
+ validInputs := [][]string{
+ {"poke-cli", "item", "--help"},
+ {"poke-cli", "item", "potion"},
+ {"poke-cli", "item", "master-ball"},
+ }
+
+ for _, input := range validInputs {
+ err := ValidateItemArgs(input)
+ require.NoError(t, err, "Expected no error for valid input")
+ }
+
+ invalidInputs := [][]string{
+ {"poke-cli", "item"},
+ }
+
+ for _, input := range invalidInputs {
+ err := ValidateItemArgs(input)
+ require.Error(t, err, "Expected error for invalid input")
+ }
+
+ tooManyArgs := [][]string{
+ {"poke-cli", "item", "potion", "super-potion"},
+ }
+
+ expectedError := styling.StripANSI("╭──────────────────╮\n│✖ Error! │\n│Too many arguments│\n╰──────────────────╯")
+
+ for _, input := range tooManyArgs {
+ err := ValidateItemArgs(input)
+
+ if err == nil {
+ t.Fatalf("Expected an error for input %v, but got nil", input)
+ }
+
+ strippedErr := styling.StripANSI(err.Error())
+ assert.Equal(t, expectedError, strippedErr, "Unexpected error message for invalid input")
+ }
+}
+
+// TestValidateMoveArgs tests the ValidateMoveArgs function
+func TestValidateMoveArgs(t *testing.T) {
+ validInputs := [][]string{
+ {"poke-cli", "move", "--help"},
+ {"poke-cli", "move", "thunderbolt"},
+ {"poke-cli", "move", "Dragon-Tail"},
+ }
+
+ for _, input := range validInputs {
+ err := ValidateMoveArgs(input)
+ require.NoError(t, err, "Expected no error for valid input")
+ }
+
+ invalidInputs := [][]string{
+ {"poke-cli", "move"},
+ }
+
+ for _, input := range invalidInputs {
+ err := ValidateMoveArgs(input)
+ require.Error(t, err, "Expected error for invalid input")
+ }
+
+ tooManyArgs := [][]string{
+ {"poke-cli", "move", "tackle", "scratch"},
+ }
+
+ expectedError := styling.StripANSI("╭──────────────────╮\n│✖ Error! │\n│Too many arguments│\n╰──────────────────╯")
+
+ for _, input := range tooManyArgs {
+ err := ValidateMoveArgs(input)
+
+ if err == nil {
+ t.Fatalf("Expected an error for input %v, but got nil", input)
+ }
+
+ strippedErr := styling.StripANSI(err.Error())
+ assert.Equal(t, expectedError, strippedErr, "Unexpected error message for invalid input")
+ }
+}
+
// TestValidateSearchArgs tests the ValidateSearchArgs function
func TestValidateSearchArgs(t *testing.T) {
validInputs := [][]string{
@@ -262,3 +381,42 @@ func TestValidateTypesArgs(t *testing.T) {
assert.Equal(t, expectedError, strippedErr, "Unexpected error message for invalid input")
}
}
+
+// TestValidateSpeedArgs tests the ValidateSpeedArgs function
+func TestValidateSpeedArgs(t *testing.T) {
+ validInputs := [][]string{
+ {"poke-cli", "speed"},
+ {"poke-cli", "speed", "--help"},
+ }
+
+ for _, input := range validInputs {
+ err := ValidateSpeedArgs(input)
+ require.NoError(t, err, "Expected no error for valid input")
+ }
+
+ invalidInputs := [][]string{
+ {"poke-cli", "speed", "100"},
+ }
+
+ for _, input := range invalidInputs {
+ err := ValidateSpeedArgs(input)
+ require.Error(t, err, "Expected error for invalid input")
+ }
+
+ tooManyArgs := [][]string{
+ {"poke-cli", "speed", "100", "200"},
+ }
+
+ expectedError := styling.StripANSI("╭──────────────────╮\n│✖ Error! │\n│Too many arguments│\n╰──────────────────╯")
+
+ for _, input := range tooManyArgs {
+ err := ValidateSpeedArgs(input)
+
+ if err == nil {
+ t.Fatalf("Expected an error for input %v, but got nil", input)
+ }
+
+ strippedErr := styling.StripANSI(err.Error())
+ assert.Equal(t, expectedError, strippedErr, "Unexpected error message for invalid input")
+ }
+}
diff --git a/flags/version.go b/flags/version.go
index a29d0db8..aa213518 100644
--- a/flags/version.go
+++ b/flags/version.go
@@ -2,6 +2,7 @@ package flags
import (
"encoding/json"
+ "errors"
"flag"
"fmt"
"io"
@@ -16,58 +17,62 @@ import (
func LatestFlag() (string, error) {
var output strings.Builder
- latestRelease(&output)
+ err := latestRelease(&output)
result := output.String()
fmt.Print(result)
- return result, nil
+ return result, err
}
-func latestRelease(output *strings.Builder) {
+func latestRelease(output *strings.Builder) error {
type Release struct {
TagName string `json:"tag_name"`
}
- // Parse and validate the URL
parsedURL, err := url.Parse("https://api.github.com/repos/digitalghost-dev/poke-cli/releases/latest")
if err != nil {
- fmt.Fprintf(output, "invalid URL: %v\n", err)
- return
+ err = fmt.Errorf("invalid URL: %w", err)
+ fmt.Fprintln(output, err)
+ return err
}
- // Implementing gosec error
if flag.Lookup("test.v") == nil {
if parsedURL.Scheme != "https" {
- fmt.Fprint(output, "only HTTPS URLs are allowed for security reasons\n")
- return
+ err := errors.New("only HTTPS URLs are allowed for security reasons")
+ fmt.Fprintln(output, err)
+ return err
}
if parsedURL.Host != "api.github.com" {
- fmt.Fprint(output, "url host is not allowed\n")
- return
+ err := errors.New("url host is not allowed")
+ fmt.Fprintln(output, err)
+ return err
}
}
response, err := http.Get(parsedURL.String())
if err != nil {
- fmt.Fprintf(output, "error fetching data: %v\n", err)
- return
+ err = fmt.Errorf("error fetching data: %w", err)
+ fmt.Fprintln(output, err)
+ return err
}
defer response.Body.Close()
body, err := io.ReadAll(response.Body)
if err != nil {
- fmt.Fprintf(output, "error reading response body: %v\n", err)
- return
+ err = fmt.Errorf("error reading response body: %w", err)
+ fmt.Fprintln(output, err)
+ return err
}
var release Release
if err := json.Unmarshal(body, &release); err != nil {
- fmt.Fprintf(output, "error unmarshalling JSON: %v\n", err)
- return
+ err = fmt.Errorf("error unmarshalling JSON: %w", err)
+ fmt.Fprintln(output, err)
+ return err
}
- releaseString := "Latest available version:"
+ releaseString := "Latest available release on GitHub:"
releaseTag := styling.ColoredBullet.Render("") + release.TagName
docStyle := lipgloss.NewStyle().
@@ -80,4 +85,6 @@ func latestRelease(output *strings.Builder) {
output.WriteString(docStyle.Render(fullDoc))
output.WriteString("\n")
+
+ return nil
}
diff --git a/flags/version_test.go b/flags/version_test.go
index fef1b1e7..869c1279 100644
--- a/flags/version_test.go
+++ b/flags/version_test.go
@@ -7,6 +7,7 @@ import (
"github.com/digitalghost-dev/poke-cli/cmd/utils"
"github.com/digitalghost-dev/poke-cli/styling"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestLatestVersionFlag(t *testing.T) {
@@ -32,11 +33,13 @@ func TestLatestVersionFlag(t *testing.T) {
name: "Get latest version with short flag",
args: []string{"-l"},
expectedOutput: utils.LoadGolden(t, "main_latest_flag.golden"),
+ expectedError: false,
},
{
name: "Get latest version with long flag",
args: []string{"--latest"},
expectedOutput: utils.LoadGolden(t, "main_latest_flag.golden"),
+ expectedError: false,
},
}
@@ -46,9 +49,15 @@ func TestLatestVersionFlag(t *testing.T) {
os.Args = append([]string{"poke-cli"}, tt.args...)
defer func() { os.Args = originalArgs }()
- output, _ := LatestFlag()
+ output, err := LatestFlag()
cleanOutput := styling.StripANSI(output)
+ if tt.expectedError {
+ require.Error(t, err, "Expected an error")
+ } else {
+ require.NoError(t, err, "Expected no error")
+ }
+
assert.Equal(t, tt.expectedOutput, cleanOutput, "Output should match expected")
})
}
diff --git a/go.mod b/go.mod
index 5b5957b2..6dfd4ea1 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/digitalghost-dev/poke-cli
-go 1.24.6
+go 1.24.9
require (
github.com/charmbracelet/bubbles v0.21.0
diff --git a/nfpm.yaml b/nfpm.yaml
index 9949708c..d5ff4ad5 100644
--- a/nfpm.yaml
+++ b/nfpm.yaml
@@ -1,7 +1,7 @@
name: "poke-cli"
arch: "arm64"
platform: "linux"
-version: "v1.7.3"
+version: "v1.7.4"
section: "default"
version_schema: semver
maintainer: "Christian S"
diff --git a/styling/styling_test.go b/styling/styling_test.go
index 0df10ba6..efd7f501 100644
--- a/styling/styling_test.go
+++ b/styling/styling_test.go
@@ -97,3 +97,20 @@ func TestColor_Hex(t *testing.T) {
t.Errorf("Expected %s, got %s", expected, hex)
}
}
+
+func TestFormTheme(t *testing.T) {
+ theme := FormTheme()
+
+ assert.NotNil(t, theme, "FormTheme should return a non-nil theme")
+ assert.NotNil(t, theme.Focused, "Focused state should be configured")
+ assert.NotNil(t, theme.Blurred, "Blurred state should be configured")
+ assert.NotNil(t, theme.Group, "Group state should be configured")
+
+ focusedButtonStyle := theme.Focused.FocusedButton
+ assert.NotNil(t, focusedButtonStyle, "Focused button style should be set")
+
+ assert.Equal(t, theme.Focused.FocusedButton, theme.Focused.Next, "Next button should use focused button style")
+ assert.NotNil(t, theme.Blurred.Base, "Blurred base should be configured")
+ assert.Equal(t, theme.Focused.Title, theme.Group.Title, "Group title should match focused title")
+ assert.Equal(t, theme.Focused.Description, theme.Group.Description, "Group description should match focused description")
+}
diff --git a/testdata/main_latest_flag.golden b/testdata/main_latest_flag.golden
index 5f94b689..262d4786 100644
--- a/testdata/main_latest_flag.golden
+++ b/testdata/main_latest_flag.golden
@@ -1,6 +1,7 @@
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ ┃
-┃ Latest available version: ┃
-┃ • v1.7.2 ┃
+┃ Latest available release ┃
+┃ on GitHub: ┃
+┃ • v1.7.3 ┃
┃ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛