Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.1.0 #4

Merged
merged 13 commits into from
Jun 2, 2024
25 changes: 25 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
*.DS_Store
*.idea

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work
go.work.sum

# env file
.env
dist/
27 changes: 27 additions & 0 deletions .github/workflows/go_lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Lint

on:
pull_request:
types: [opened, reopened]

permissions:
contents: read
pull-requests: read

jobs:
linter:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.21

- name: Lint
uses: golangci/golangci-lint-action@v4
with:
version: v1.56
skip-cache: true
24 changes: 24 additions & 0 deletions .github/workflows/go_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Test

on:
pull_request:
types: [opened, reopened]

jobs:
tests:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: 1.21

- name: Install dependencies
run: |
go get .

- name: Run tests
run: go test -v ./...
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
*.DS_Store
*.idea

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work
go.work.sum

# env file
.env
dist/
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM golang:1.21-alpine3.19

WORKDIR /app

ENV TERM xterm-256color
ENV COLOR_OUTPUT true

COPY . /app

RUN PATH="$PATH:~/go/bin:/usr/local/go/bin:$GOPATH/bin"

RUN go install

ENTRYPOINT ["poke-cli"]
55 changes: 54 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,54 @@
# poke-cli
<p align="center">
<img height="250" width="350" src="https://cdn.simpleicons.org/pokemon/FFCC00" alt="pokemon-logo"/>
</p>

<div align="center">
<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.0.0?arch=arm64&style=flat-square&logo=docker&logoColor=FFCC00&labelColor=EEE&color=FFCC00" alt="docker-image-size">
</div>

<div align="center">
<img src="https://img.shields.io/github/actions/workflow/status/digitalghost-dev/poke-cli/go_tests.yml?style=flat-square&logo=go&logoColor=00ADD8&label=Tests&labelColor=EEE&color=00ADD8" alt="tests-label">
<img src="https://img.shields.io/github/go-mod/go-version/digitalghost-dev/poke-cli?style=flat-square&logo=Go&labelColor=EEE&color=00ADD8" alt="go-version">
</div>

## Overview
A CLI tool for viewing data about Pokémon from your terminal!

## Install

### Go Build
1. Make sure [Go is installed](https://go.dev/dl/) on your machine. This project uses `v1.21`.
2. Clone the repository in a root directory: `git clone https://github.com/digitalghost-dev/poke-cli.git`
3. Change directories into the `poke-cli` directory.
4. Run `go build -o poke-cli`
5. A binary will be created then the tool can be used! It can also be added to your path to run the binary from anywhere.

### Docker
Use a Docker Image instead:
```bash
docker run --rm -it digitalghostdev/poke-cli:1.0.0 [command] [flag]
```

> [!NOTE]
> Currently working on more ways to distribute the binary.

## Usage
By running `poke-cli --help`, it'll display information on how to use the tool.
```
Welcome! This tool displays data about a selected Pokémon in the terminal!

USAGE:
poke-cli [flag]
poke-cli [pokemon name] [flag]
----------
Example: poke-cli bulbasaur or poke-cli flutter-mane --types

GLOBAL FLAGS:
-h, --help Shows the help menu

POKEMON NAME FLAGS:
Add a flag after declaring a Pokémon's name for more details!
--types
```
43 changes: 43 additions & 0 deletions cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"flag"
"fmt"
"github.com/charmbracelet/lipgloss"
"github.com/digitalghost-dev/poke-cli/subcommands"
"os"
)

var styleBold = lipgloss.NewStyle().Bold(true)
var styleItalic = lipgloss.NewStyle().Italic(true)

func main() {

flag.Usage = func() {
fmt.Println("Welcome! This tool displays data about a selected Pokémon in the terminal!")

fmt.Println(styleBold.Render("\nUSAGE:"))
fmt.Println("\t", "poke-cli [flag]")
fmt.Println("\t", "poke-cli [pokemon name] [flag]")
fmt.Println("\t", "----------")
fmt.Println("\t", styleItalic.Render("Example:"), "poke-cli bulbasaur", styleItalic.Render("or"), "poke-cli flutter-mane --types")

fmt.Println(styleBold.Render("\nGLOBAL FLAGS:"))
fmt.Println("\t", "-h, --help", "\t", "Shows the help menu")
fmt.Print("\n")

fmt.Println(styleBold.Render("POKEMON NAME FLAGS:"))
fmt.Println("\t", "Add a flag after declaring a Pokémon's name for more details!")
fmt.Print("\t", "--types", "\t\t", "Prints out the Pokémon's typing.\n\n")
}

flag.Parse()

if len(os.Args) < 2 {
fmt.Println("Please declare a Pokémon's name after the CLI name")
fmt.Println("Run 'poke-cli --help' for more details")
os.Exit(1)
}

subcommands.PokemonCommand()
}
66 changes: 66 additions & 0 deletions cli_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package main

import (
"bytes"
"os/exec"
"testing"
)

func TestCLI(t *testing.T) {

tests := []struct {
args []string
expectedOutput string
expectedExit int
}{
{
args: []string{},
expectedOutput: "Please declare a Pokémon's name after the CLI name\nRun 'poke-cli --help' for more details\n",
expectedExit: 1,
},
{
args: []string{"bulbasaur"},
expectedOutput: "Selected Pokémon: Bulbasaur\n",
expectedExit: 0,
},
{
args: []string{"mew", "--types"},
expectedOutput: "Selected Pokémon: Mew\nType 1: psychic\n",
expectedExit: 0,
},
{
args: []string{"cacturne", "--types"},
expectedOutput: "Selected Pokémon: Cacturne\nType 1: grass\nType 2: dark\n",
expectedExit: 0,
},
{
args: []string{"chimchar", "types"},
expectedOutput: "error: only flags are allowed after declaring a Pokémon's name\n",
expectedExit: 1,
},
{
args: []string{"flutter-mane", "types"},
expectedOutput: "Selected Pokémon: Flutter-Mane\nType 1: ghost\nType 2: fairy\n",
expectedExit: 0,
},
}

for _, test := range tests {
cmd := exec.Command("poke-cli", test.args...)
var out bytes.Buffer
cmd.Stdout = &out

err := cmd.Run()
if err != nil {
return
}

if out.String() != test.expectedOutput {
t.Errorf("Expected output: %s, Got: %s", test.expectedOutput, out.String())
}

if cmd.ProcessState.ExitCode() != test.expectedExit {
t.Errorf("Expected exit code: %d, Got: %d", test.expectedExit, cmd.ProcessState.ExitCode())
}
}
}
76 changes: 76 additions & 0 deletions connections/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package connections

import (
"encoding/json"
"fmt"
"github.com/charmbracelet/lipgloss"
"io"
"log"
"net/http"
)

var httpGet = http.Get
var red = lipgloss.Color("#F2055C")
var errorColor = lipgloss.NewStyle().Foreground(red)

// Helper function to handle API calls and JSON unmarshalling
func baseApiCall(url string, target interface{}) {
res, err := httpGet(url)
if err != nil {
log.Fatalf("Error making GET request: %v", err)
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
log.Printf("Failed to close body: %v", err)
}
}(res.Body)

if res.StatusCode == http.StatusNotFound {
fmt.Println(errorColor.Render("Couldn't find that Pokémon... perhaps its named was misspelled?"))
}

body, err := io.ReadAll(res.Body)
if err != nil {
log.Fatalf("Error reading response body: %v", err)
}

err = json.Unmarshal(body, target)
if err != nil {
log.Fatalf("Error unmarshalling JSON: %v", err)
}
}

func PokemonNameApiCall(pokemonName string, baseURL string) string {
type Pokemon struct {
Name string `json:"name"`
}

url := baseURL + pokemonName
var pokemon Pokemon

baseApiCall(url, &pokemon)

return pokemon.Name
}

func PokemonTypeApiCall(pokemonName string, baseURL string) {
type Pokemon struct {
Types []struct {
Slot int `json:"slot"`
Type struct {
Name string `json:"name"`
URL string `json:"url"`
} `json:"type"`
} `json:"types"`
}

url := baseURL + pokemonName
var pokemon Pokemon

baseApiCall(url, &pokemon)

for _, pokeType := range pokemon.Types {
fmt.Printf("Type %d: %s\n", pokeType.Slot, pokeType.Type.Name)
}
}
26 changes: 26 additions & 0 deletions connections/connection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package connections

import (
"encoding/json"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"testing"
)

func TestBaseApiCallSuccess(t *testing.T) {
expectedData := map[string]string{"key": "value"}

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
err := json.NewEncoder(w).Encode(expectedData)
assert.Nil(t, err)
}))
defer ts.Close()

var target map[string]string

baseApiCall(ts.URL, &target)

assert.Equal(t, expectedData, target)
}
Loading