Skip to content

Commit 68d91a1

Browse files
Merge pull request #211 from digitalghost-dev/1.8.1
1.8.1
2 parents d55869a + ead7b3f commit 68d91a1

File tree

20 files changed

+352
-279
lines changed

20 files changed

+352
-279
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ on:
3030
- main
3131

3232
env:
33-
VERSION_NUMBER: 'v1.8.0'
33+
VERSION_NUMBER: 'v1.8.1'
3434
DOCKERHUB_REGISTRY_NAME: 'digitalghostdev/poke-cli'
3535
AWS_REGION: 'us-west-2'
3636

.goreleaser.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ builds:
1414
- windows
1515
- darwin
1616
ldflags:
17-
- -s -w -X main.version=v1.8.0
17+
- -s -w -X main.version=v1.8.1
1818

1919
archives:
2020
- formats: [ 'zip' ]

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ RUN go mod download
88

99
COPY . .
1010

11-
RUN go build -ldflags "-X main.version=v1.8.0" -o poke-cli .
11+
RUN go build -ldflags "-X main.version=v1.8.1" -o poke-cli .
1212

1313
# build 2
1414
FROM --platform=$BUILDPLATFORM alpine:3.22

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<img height="250" width="350" src="pokemon.svg" alt="pokemon-logo"/>
33
<h1>Pokémon CLI</h1>
44
<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">
5-
<img src="https://img.shields.io/docker/image-size/digitalghostdev/poke-cli/v1.8.0?arch=arm64&style=flat-square&logo=docker&logoColor=FFCC00&labelColor=EEE&color=FFCC00" alt="docker-image-size">
5+
<img src="https://img.shields.io/docker/image-size/digitalghostdev/poke-cli/v1.8.1?arch=arm64&style=flat-square&logo=docker&logoColor=FFCC00&labelColor=EEE&color=FFCC00" alt="docker-image-size">
66
<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">
77
</div>
88
<div align="center">
@@ -95,11 +95,11 @@ Cloudsmith is a fully cloud-based service that lets you easily create, store, an
9595
3. Choose how to interact with the container:
9696
* Run a single command and exit:
9797
```bash
98-
docker run --rm -it digitalghostdev/poke-cli:v1.8.0 <command> [subcommand] flag]
98+
docker run --rm -it digitalghostdev/poke-cli:v1.8.1 <command> [subcommand] [flag]
9999
```
100100
* Enter the container and use its shell:
101101
```bash
102-
docker run --rm -it --name poke-cli --entrypoint /bin/sh digitalghostdev/poke-cli:v1.8.0 -c "cd /app && exec sh"
102+
docker run --rm -it --name poke-cli --entrypoint /bin/sh digitalghostdev/poke-cli:v1.8.1 -c "cd /app && exec sh"
103103
# placed into the /app directory, run the program with './poke-cli'
104104
# example: ./poke-cli ability swift-swim
105105
```

card_data/README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,23 @@
33
This directory stores all the code for all backend data processing related to Pokémon TCG data.
44

55
Instead of calling directly to the PokéAPI for data from the video game, I took this a step further
6-
and decided to process all the data myself, load it into Supabase, and read from that API.
6+
and decided to process all the data myself, load it into Supabase, and read from that API.
7+
8+
## Data Architecture
9+
Runs at 2:00PM PST daily.
10+
![data_diagram](https://poke-cli-s3-bucket.s3.us-west-2.amazonaws.com/data_infrastructure.png)
11+
12+
13+
1. TCGPlayer pricing data and TCGDex card data are called and processed through a data pipeline orchestrated by Dagster and hosted on AWS.
14+
15+
2. When the pipeline starts, Pydantic validates the incoming API data against a pre-defined schema, ensuring the data types match the expected structure.
16+
17+
3. Polars is used to create DataFrames.
18+
19+
4. The data is loaded into a Supabase staging schema.
20+
21+
5. Soda data quality checks are performed.
22+
23+
6. `dbt` runs and builds the final tables in a Supabase production schema.
24+
25+
7. Users are then able to query the `pokeapi.co` or supabase APIs for either video game or trading card data, respectively.

card_data/pipelines/poke_cli_dbt/dbt_project.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: 'poke_cli_dbt'
2-
version: '1.8.0'
2+
version: '1.8.1'
33

44
profile: 'poke_cli_dbt'
55

cmd/ability/ability.go

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ package ability
33
import (
44
"flag"
55
"fmt"
6+
"os"
7+
"strings"
8+
69
"github.com/digitalghost-dev/poke-cli/cmd/utils"
710
"github.com/digitalghost-dev/poke-cli/connections"
811
"github.com/digitalghost-dev/poke-cli/flags"
912
"github.com/digitalghost-dev/poke-cli/styling"
1013
"golang.org/x/text/cases"
1114
"golang.org/x/text/language"
12-
"os"
13-
"strings"
1415
)
1516

1617
func AbilityCommand() (string, error) {
@@ -52,19 +53,14 @@ func AbilityCommand() (string, error) {
5253
if err := abilityFlags.Parse(args[3:]); err != nil {
5354
output.WriteString(fmt.Sprintf("error parsing flags: %v\n", err))
5455
abilityFlags.Usage()
55-
if os.Getenv("GO_TESTING") != "1" {
56-
os.Exit(1)
57-
}
56+
5857
return output.String(), err
5958
}
6059

6160
abilitiesStruct, abilityName, err := connections.AbilityApiCall(endpoint, abilityName, connections.APIURL)
6261
if err != nil {
63-
if os.Getenv("GO_TESTING") != "1" {
64-
fmt.Fprintln(os.Stderr, err)
65-
os.Exit(1)
66-
}
67-
return err.Error(), nil
62+
output.WriteString(err.Error())
63+
return output.String(), err
6864
}
6965

7066
// Extract English short_effect
@@ -88,7 +84,6 @@ func AbilityCommand() (string, error) {
8884
capitalizedAbility := cases.Title(language.English).String(strings.ReplaceAll(abilityName, "-", " "))
8985
output.WriteString(styling.StyleBold.Render(capitalizedAbility) + "\n")
9086

91-
// Print the generation where the ability was first introduced.
9287
generationParts := strings.Split(abilitiesStruct.Generation.Name, "-")
9388
if len(generationParts) > 1 {
9489
generationUpper := strings.ToUpper(generationParts[1])
@@ -100,15 +95,15 @@ func AbilityCommand() (string, error) {
10095
// API is missing some data for the short_effect for abilities from Generation 9.
10196
// If short_effect is empty, fallback to the move's flavor_text_entry.
10297
if englishShortEffect == "" {
103-
output.WriteString(fmt.Sprintf("%s Effect: "+englishFlavorEntry, styling.ColoredBullet))
98+
output.WriteString(fmt.Sprintf("%s Effect: %s", styling.ColoredBullet, englishFlavorEntry))
10499
} else {
105-
output.WriteString(fmt.Sprintf("%s Effect: "+englishShortEffect, styling.ColoredBullet))
100+
output.WriteString(fmt.Sprintf("%s Effect: %s", styling.ColoredBullet, englishShortEffect))
106101
}
107102

108103
if *pokemonFlag || *shortPokemonFlag {
109104
if err := flags.PokemonAbilitiesFlag(&output, endpoint, abilityName); err != nil {
110105
output.WriteString(fmt.Sprintf("error parsing flags: %v\n", err))
111-
return "", fmt.Errorf("error parsing flags: %w", err)
106+
return output.String(), fmt.Errorf("error parsing flags: %w", err)
112107
}
113108
}
114109

cmd/ability/ability_test.go

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,15 @@
11
package ability
22

33
import (
4+
"os"
5+
"testing"
6+
47
"github.com/digitalghost-dev/poke-cli/cmd/utils"
58
"github.com/digitalghost-dev/poke-cli/styling"
69
"github.com/stretchr/testify/assert"
7-
"os"
8-
"testing"
910
)
1011

1112
func TestAbilityCommand(t *testing.T) {
12-
err := os.Setenv("GO_TESTING", "1")
13-
if err != nil {
14-
t.Fatalf("Failed to set GO_TESTING env var: %v", err)
15-
}
16-
17-
defer func() {
18-
err := os.Unsetenv("GO_TESTING")
19-
if err != nil {
20-
t.Logf("Warning: failed to unset GO_TESTING: %v", err)
21-
}
22-
}()
23-
2413
tests := []struct {
2514
name string
2615
args []string
@@ -53,6 +42,11 @@ func TestAbilityCommand(t *testing.T) {
5342
args: []string{"ability", "anger-point", "--pokemon"},
5443
expectedOutput: utils.LoadGolden(t, "ability_flag_pokemon.golden"),
5544
},
45+
{
46+
name: "Ability command: special character in API call",
47+
args: []string{"ability", "poison-point"},
48+
expectedOutput: utils.LoadGolden(t, "ability_poison_point.golden"),
49+
},
5650
}
5751

5852
for _, tt := range tests {

cmd/card/imageviewer.go

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,60 @@
11
package card
22

33
import (
4+
"github.com/charmbracelet/bubbles/spinner"
45
tea "github.com/charmbracelet/bubbletea"
6+
"github.com/charmbracelet/lipgloss"
7+
"github.com/digitalghost-dev/poke-cli/styling"
58
)
69

710
type ImageModel struct {
8-
CardName string
9-
ImageURL string
10-
Error error
11+
CardName string
12+
ImageURL string
13+
Error error
14+
Loading bool
15+
Spinner spinner.Model
16+
ImageData string
17+
}
18+
19+
type imageReadyMsg struct {
20+
sixelData string
21+
err error
22+
}
23+
24+
// fetchImageCmd downloads and renders the image asynchronously
25+
func fetchImageCmd(imageURL string) tea.Cmd {
26+
return func() tea.Msg {
27+
sixelData, err := CardImage(imageURL)
28+
if err != nil {
29+
return imageReadyMsg{err: err}
30+
}
31+
return imageReadyMsg{sixelData: sixelData}
32+
}
1133
}
1234

1335
func (m ImageModel) Init() tea.Cmd {
14-
return nil
36+
return tea.Batch(
37+
m.Spinner.Tick,
38+
fetchImageCmd(m.ImageURL),
39+
)
1540
}
1641

1742
func (m ImageModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
1843
switch msg := msg.(type) {
44+
case imageReadyMsg:
45+
m.Loading = false
46+
if msg.err != nil {
47+
m.Error = msg.err
48+
m.ImageData = ""
49+
} else {
50+
m.Error = nil
51+
m.ImageData = msg.sixelData
52+
}
53+
return m, nil
54+
case spinner.TickMsg:
55+
var cmd tea.Cmd
56+
m.Spinner, cmd = m.Spinner.Update(msg)
57+
return m, cmd
1958
case tea.KeyMsg:
2059
switch msg.String() {
2160
case "ctrl+c", "esc":
@@ -26,15 +65,26 @@ func (m ImageModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
2665
}
2766

2867
func (m ImageModel) View() string {
29-
return m.ImageURL
68+
if m.Loading {
69+
return lipgloss.NewStyle().Padding(2).Render(
70+
m.Spinner.View() + "Loading image for \n" + m.CardName,
71+
)
72+
}
73+
if m.Error != nil {
74+
return styling.Red.Render(m.Error.Error())
75+
}
76+
return m.ImageData
3077
}
3178

3279
func ImageRenderer(cardName string, imageURL string) ImageModel {
33-
imageData, err := CardImage(imageURL)
80+
s := spinner.New()
81+
s.Spinner = spinner.Dot
82+
s.Style = styling.Yellow
3483

3584
return ImageModel{
3685
CardName: cardName,
37-
ImageURL: imageData,
38-
Error: err,
86+
ImageURL: imageURL,
87+
Loading: true,
88+
Spinner: s,
3989
}
4090
}

0 commit comments

Comments
 (0)