Skip to content
Merged

1.3.0 #147

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
5 changes: 4 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ go.work.sum

# env file
.env
dist/
dist/

# testdata
testdata/
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ on:
- main

env:
VERSION_NUMBER: 'v1.2.4'
VERSION_NUMBER: 'v1.3.0'
DOCKERHUB_REGISTRY_NAME: 'digitalghostdev/poke-cli'
AWS_REGION: 'us-west-2'

Expand Down
2 changes: 1 addition & 1 deletion .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ builds:
- windows
- darwin
ldflags:
- -s -w -X main.version=v1.2.4
- -s -w -X main.version=v1.3.0

archives:
- format: tar.gz
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ RUN go mod download

COPY . .

RUN go build -ldflags "-X main.version=v1.2.4" -o poke-cli .
RUN go build -ldflags "-X main.version=v1.3.0" -o poke-cli .

# build 2
FROM --platform=$BUILDPLATFORM alpine:latest
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img height="250" width="350" src="pokemon.svg" alt="pokemon-logo"/>
<h1>Pokémon CLI</h1>
<img src="https://img.shields.io/github/v/release/digitalghost-dev/poke-cli?style=flat-square&logo=git&logoColor=FFCC00&label=Release%20Version&labelColor=EEE&color=FFCC00" alt="version-label">
<img src="https://img.shields.io/docker/image-size/digitalghostdev/poke-cli/v1.2.4?arch=arm64&style=flat-square&logo=docker&logoColor=FFCC00&labelColor=EEE&color=FFCC00" alt="docker-image-size">
<img src="https://img.shields.io/docker/image-size/digitalghostdev/poke-cli/v1.3.0?arch=arm64&style=flat-square&logo=docker&logoColor=FFCC00&labelColor=EEE&color=FFCC00" alt="docker-image-size">
<img src="https://img.shields.io/github/actions/workflow/status/digitalghost-dev/poke-cli/ci.yml?branch=main&style=flat-square&logo=github&logoColor=FFCC00&label=CI&labelColor=EEE&color=FFCC00" alt="ci-status-badge">
</div>
<div align="center">
Expand Down Expand Up @@ -76,11 +76,11 @@ View future plans in the [Roadmap](#roadmap) section.
3. Choose how to interact with the container:
* Run a single command and exit:
```bash
docker run --rm -it digitalghostdev/poke-cli:v1.2.4 <command> [subcommand] flag]
docker run --rm -it digitalghostdev/poke-cli:v1.3.0 <command> [subcommand] flag]
```
* Enter the container and use its shell:
```bash
docker run --rm -it --name poke-cli --entrypoint /bin/sh digitalghostdev/poke-cli:v1.2.4 -c "cd /app && exec sh"
docker run --rm -it --name poke-cli --entrypoint /bin/sh digitalghostdev/poke-cli:v1.3.0 -c "cd /app && exec sh"
# placed into the /app directory, run the program with './poke-cli'
# example: ./poke-cli ability swift-swim
```
Expand Down Expand Up @@ -150,7 +150,7 @@ Below is a list of the planned/completed commands and flags:
- [x] `-i | --image`: display a pixel image of the Pokémon.
- [x] `-s | --stats`: display the Pokémon's base stats.
- [x] `-t | --types`: display the Pokémon's typing.
- [ ] `-m | --moves`: display learnable moves.
- [x] `-m | --moves`: display learnable moves.
- [x] `search`: search for a resource (`ability`, `berry`, `pokemon`, `move`)
- [ ] `speed`: compare speed stats between two Pokémon.
- [x] `types`: get data about a specific typing.
Expand Down
10 changes: 9 additions & 1 deletion cmd/pokemon/pokemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@
fmt.Sprintf("\n\t%-30s %s", "-a, --abilities", "Prints the Pokémon's abilities."),
fmt.Sprintf("\n\t%-30s %s", "-i=xx, --image=xx", "Prints out the Pokémon's default sprite."),
fmt.Sprintf("\n\t%5s%-15s", "", hintMessage),
fmt.Sprintf("\n\t%-30s %s", "-m, --moves", "Prints the Pokemon's learnable moves."),
fmt.Sprintf("\n\t%-30s %s", "-s, --stats", "Prints the Pokémon's base stats."),
fmt.Sprintf("\n\t%-30s %s", "-t, --types", "Prints the Pokémon's typing."),
fmt.Sprintf("\n\t%-30s %s", "-h, --help", "Prints the help menu."),
)
output.WriteString(helpMessage)
}

pokeFlags, abilitiesFlag, shortAbilitiesFlag, imageFlag, shortImageFlag, statsFlag, shortStatsFlag, typesFlag, shortTypesFlag := flags.SetupPokemonFlagSet()
pokeFlags, abilitiesFlag, shortAbilitiesFlag, imageFlag, shortImageFlag, moveFlag, shortMoveFlag, statsFlag, shortStatsFlag, typesFlag, shortTypesFlag := flags.SetupPokemonFlagSet()

args := os.Args

Expand Down Expand Up @@ -115,6 +116,13 @@
}
}

if *moveFlag || *shortMoveFlag {
if err := flags.MovesFlag(&output, endpoint, pokemonName); err != nil {
output.WriteString(fmt.Sprintf("error parsing flags: %v\n", err))
return "", fmt.Errorf("error parsing flags: %w", err)
}

Check warning on line 123 in cmd/pokemon/pokemon.go

View check run for this annotation

Codecov / codecov/patch

cmd/pokemon/pokemon.go#L120-L123

Added lines #L120 - L123 were not covered by tests
}

if *typesFlag || *shortTypesFlag {
if err := flags.TypesFlag(&output, endpoint, pokemonName); err != nil {
output.WriteString(fmt.Sprintf("error parsing flags: %v\n", err))
Expand Down
2 changes: 1 addition & 1 deletion cmd/utils/validateargs.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func ValidatePokemonArgs(args []string) error {
return fmt.Errorf("%s", errMessage)
}

if err := checkLength(args, 7); err != nil {
if err := checkLength(args, 8); err != nil {
return err
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/utils/validateargs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func TestValidatePokemonArgs(t *testing.T) {

// Testing too many arguments
tooManyArgs := [][]string{
{"poke-cli", "pokemon", "hypo", "--abilities", "-s", "--types", "--image=sm", "-m"},
{"poke-cli", "pokemon", "hypo", "--abilities", "-s", "--types", "--image=sm", "-m", "-p"},
}

expectedError := styling.StripANSI("╭──────────────────╮\n│Error! │\n│Too many arguments│\n╰──────────────────╯")
Expand Down
146 changes: 122 additions & 24 deletions flags/pokemonflagset.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@
"flag"
"fmt"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
"github.com/digitalghost-dev/poke-cli/connections"
"github.com/digitalghost-dev/poke-cli/styling"
"github.com/disintegration/imaging"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"image"
"io"
"log"
"net/http"
"os"
"sort"
"strconv"
"strings"
)

Expand All @@ -33,7 +37,7 @@
return output.String()
}

func SetupPokemonFlagSet() (*flag.FlagSet, *bool, *bool, *string, *string, *bool, *bool, *bool, *bool) {
func SetupPokemonFlagSet() (*flag.FlagSet, *bool, *bool, *string, *string, *bool, *bool, *bool, *bool, *bool, *bool) {
pokeFlags := flag.NewFlagSet("pokeFlags", flag.ExitOnError)

abilitiesFlag := pokeFlags.Bool("abilities", false, "Print the Pokémon's abilities")
Expand All @@ -42,6 +46,9 @@
imageFlag := pokeFlags.String("image", "", "Print the Pokémon's default sprite")
shortImageFlag := pokeFlags.String("i", "", "Print the Pokémon's default sprite")

moveFlag := pokeFlags.Bool("moves", false, "Print the Pokémon's learnable moves")
shortMoveFlag := pokeFlags.Bool("m", false, "Print the Pokémon's learnable moves")

statsFlag := pokeFlags.Bool("stats", false, "Print the Pokémon's base stats")
shortStatsFlag := pokeFlags.Bool("s", false, "Print the Pokémon's base stats")

Expand All @@ -56,14 +63,15 @@
fmt.Sprintf("\n\t%-30s %s", "-a, --abilities", "Prints the Pokémon's abilities."),
fmt.Sprintf("\n\t%-30s %s", "-i=xx, --image=xx", "Prints out the Pokémon's default sprite."),
fmt.Sprintf("\n\t%5s%-15s", "", hintMessage),
fmt.Sprintf("\n\t%-30s %s", "-m, --moves", "Prints the Pokemon's learnable moves."),

Check warning on line 66 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L66

Added line #L66 was not covered by tests
fmt.Sprintf("\n\t%-30s %s", "-s, --stats", "Prints the Pokémon's base stats."),
fmt.Sprintf("\n\t%-30s %s", "-t, --types", "Prints the Pokémon's typing."),
fmt.Sprintf("\n\t%-30s %s", "-h, --help", "Prints the help menu."),
)
fmt.Println(helpMessage)
}

return pokeFlags, abilitiesFlag, shortAbilitiesFlag, imageFlag, shortImageFlag, statsFlag, shortStatsFlag, typesFlag, shortTypesFlag
return pokeFlags, abilitiesFlag, shortAbilitiesFlag, imageFlag, shortImageFlag, moveFlag, shortMoveFlag, statsFlag, shortStatsFlag, typesFlag, shortTypesFlag
}

func AbilitiesFlag(w io.Writer, endpoint string, pokemonName string) error {
Expand Down Expand Up @@ -198,6 +206,117 @@
return nil
}

func MovesFlag(w io.Writer, endpoint string, pokemonName string) error {
baseURL := "https://pokeapi.co/api/v2/"
pokemonStruct, _, _, _, _, _ := connections.PokemonApiCall(endpoint, pokemonName, baseURL)

_, err := fmt.Fprintln(w, header("Learnable Moves"))
if err != nil {
return err
}

Check warning on line 216 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L209-L216

Added lines #L209 - L216 were not covered by tests

type MoveInfo struct {
Accuracy int
Level int
Name string
Power int
Type string
}

var moves []MoveInfo

for _, pokeMove := range pokemonStruct.Moves {
for _, detail := range pokeMove.VersionGroupDetails {
if detail.VersionGroup.Name != "scarlet-violet" || detail.MoveLearnedMethod.Name != "level-up" {
continue

Check warning on line 231 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L218-L231

Added lines #L218 - L231 were not covered by tests
}

moveName := pokeMove.Move.Name
moveStruct, _, err := connections.MoveApiCall("move", moveName, baseURL)
if err != nil {
log.Printf("Error fetching move %s: %v", moveName, err)
continue

Check warning on line 238 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L234-L238

Added lines #L234 - L238 were not covered by tests
}

capitalizedMove := cases.Title(language.English).String(strings.ReplaceAll(moveName, "-", " "))
capitalizedType := cases.Title(language.English).String(moveStruct.Type.Name)

moves = append(moves, MoveInfo{
Accuracy: moveStruct.Accuracy,
Level: detail.LevelLearnedAt,
Name: capitalizedMove,
Power: moveStruct.Power,
Type: capitalizedType,
})

Check warning on line 250 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L241-L250

Added lines #L241 - L250 were not covered by tests
}
}

if len(moves) == 0 {
_, err := fmt.Fprintln(w, "No level-up moves found for Scarlet & Violet.")
if err != nil {
return err
}
return nil

Check warning on line 259 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L254-L259

Added lines #L254 - L259 were not covered by tests
}

// Sort by level
sort.Slice(moves, func(i, j int) bool {
return moves[i].Level < moves[j].Level
})

Check warning on line 265 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L263-L265

Added lines #L263 - L265 were not covered by tests

// Convert to table rows
var rows [][]string
for _, m := range moves {
styledType := lipgloss.
NewStyle().
Bold(true).
Foreground(lipgloss.Color(styling.ColorMap[strings.ToLower(m.Type)])).
Render(m.Type)

rows = append(rows, []string{
m.Name,
strconv.Itoa(m.Level),
styledType,
strconv.Itoa(m.Accuracy),
strconv.Itoa(m.Power),
})
}

Check warning on line 283 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L268-L283

Added lines #L268 - L283 were not covered by tests

// Build and print table
color := lipgloss.AdaptiveColor{Light: "#4B4B4B", Dark: "#D3D3D3"}

t := table.New().
Border(lipgloss.NormalBorder()).
BorderStyle(lipgloss.NewStyle().Foreground(color)).
StyleFunc(func(row, column int) lipgloss.Style {
var style lipgloss.Style

switch column {
case 0:
style = style.Width(18)
case 1:
style = style.Width(8)
case 2:
style = style.Width(10)
case 3:
style = style.Width(10)
case 4:
style = style.Width(8)

Check warning on line 304 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L286-L304

Added lines #L286 - L304 were not covered by tests
}

return style

Check warning on line 307 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L307

Added line #L307 was not covered by tests
}).
Headers("Name", "Level", "Type", "Accuracy", "Power").
Rows(rows...)

_, err = fmt.Fprintln(w, t)
if err != nil {
return err
}

Check warning on line 315 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L312-L315

Added lines #L312 - L315 were not covered by tests

return nil

Check warning on line 317 in flags/pokemonflagset.go

View check run for this annotation

Codecov / codecov/patch

flags/pokemonflagset.go#L317

Added line #L317 was not covered by tests
}

func StatsFlag(w io.Writer, endpoint string, pokemonName string) error {
baseURL := "https://pokeapi.co/api/v2/"
pokemonStruct, _, _, _, _, _ := connections.PokemonApiCall(endpoint, pokemonName, baseURL)
Expand Down Expand Up @@ -298,35 +417,14 @@
baseURL := "https://pokeapi.co/api/v2/"
pokemonStruct, _, _, _, _, _ := connections.PokemonApiCall(endpoint, pokemonName, baseURL)

colorMap := map[string]string{
"normal": "#B7B7A9",
"fire": "#FF4422",
"water": "#3499FF",
"electric": "#FFCC33",
"grass": "#77CC55",
"ice": "#66CCFF",
"fighting": "#BB5544",
"poison": "#AA5699",
"ground": "#DEBB55",
"flying": "#889AFF",
"psychic": "#FF5599",
"bug": "#AABC22",
"rock": "#BBAA66",
"ghost": "#6666BB",
"dragon": "#7766EE",
"dark": "#775544",
"steel": "#AAAABB",
"fairy": "#EE99EE",
}

// Print the header from header func
_, err := fmt.Fprintln(w, header("Typing"))
if err != nil {
return err
}

for _, pokeType := range pokemonStruct.Types {
colorHex, exists := colorMap[pokeType.Type.Name]
colorHex, exists := styling.ColorMap[pokeType.Type.Name]
if exists {
color := lipgloss.Color(colorHex)
style := lipgloss.NewStyle().Bold(true).Foreground(color)
Expand Down
4 changes: 3 additions & 1 deletion flags/pokemonflagset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

func TestSetupPokemonFlagSet(t *testing.T) {
// Call the function to get the flag set and flags
pokeFlags, abilitiesFlag, shortAbilitiesFlag, imageFlag, shortImageFlag, statsFlag, shortStatsFlag, typesFlag, shortTypesFlag := SetupPokemonFlagSet()
pokeFlags, abilitiesFlag, shortAbilitiesFlag, imageFlag, shortImageFlag, moveFlag, shortMoveFlag, statsFlag, shortStatsFlag, typesFlag, shortTypesFlag := SetupPokemonFlagSet()

// Check flag set properties
assert.NotNil(t, pokeFlags, "Flag set should not be nil")
Expand All @@ -29,6 +29,8 @@ func TestSetupPokemonFlagSet(t *testing.T) {
{shortAbilitiesFlag, false, "Short abilities flag should be 'a'"},
{imageFlag, "", "Image flag default value should be 'md'"},
{shortImageFlag, "", "Short image flag default value should be 'md'"},
{moveFlag, false, "Move flag default value should be 'moves'"},
{shortMoveFlag, false, "Short move flag default value should be 'm'"},
{typesFlag, false, "Types flag should be 'types'"},
{shortTypesFlag, false, "Short types flag should be 't'"},
{statsFlag, false, "Stats flag should be 'stats'"},
Expand Down
17 changes: 17 additions & 0 deletions structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,23 @@ type PokemonJSONStruct struct {
Hidden bool `json:"hidden"`
Slot int `json:"slot"`
} `json:"abilities"`
Moves []struct {
Move struct {
Name string `json:"name"`
URL string `json:"url"`
} `json:"move"`
VersionGroupDetails []struct {
LevelLearnedAt int `json:"level_learned_at"`
MoveLearnedMethod struct {
Name string `json:"name"`
URL string `json:"url"`
} `json:"move_learn_method"`
VersionGroup struct {
Name string `json:"name"`
URL string `json:"url"`
} `json:"version_group"`
} `json:"version_group_details"`
} `json:"moves"`
Types []struct {
Slot int `json:"slot"`
Type struct {
Expand Down
1 change: 1 addition & 0 deletions testdata/pokemon_help.golden
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
│ -a, --abilities Prints the Pokémon's abilities. │
│ -i=xx, --image=xx Prints out the Pokémon's default sprite. │
│ options: [sm, md, lg] │
│ -m, --moves Prints the Pokemon's learnable moves. │
│ -s, --stats Prints the Pokémon's base stats. │
│ -t, --types Prints the Pokémon's typing. │
│ -h, --help Prints the help menu. │
Expand Down
Loading