Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
32 changes: 1 addition & 31 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,39 +62,9 @@ changelog:
- Merge pull request
- Merge branch

homebrew_casks:
- name: hevycli
repository:
owner: obay
name: homebrew-tap
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
directory: Casks
homepage: "https://github.com/obay/hevycli"
description: "CLI for the Hevy fitness tracking platform"
binaries:
- hevycli
commit_author:
name: goreleaserbot
email: bot@goreleaser.com
commit_msg_template: "Brew cask update for {{ .ProjectName }} version {{ .Tag }}"

scoops:
- name: hevycli
repository:
owner: obay
name: scoop-bucket
token: "{{ .Env.SCOOP_BUCKET_TOKEN }}"
homepage: "https://github.com/obay/hevycli"
description: "CLI for the Hevy fitness tracking platform"
license: MIT
commit_author:
name: goreleaserbot
email: bot@goreleaser.com
commit_msg_template: "Scoop manifest update for {{ .ProjectName }} version {{ .Tag }}"

release:
github:
owner: obay
owner: asabirov
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
name: hevycli
draft: false
prerelease: auto
Expand Down
2 changes: 1 addition & 1 deletion cmd/folder/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func runFolderCreate(cmd *cobra.Command, args []string) error {
fmt.Println(out)
} else {
fmt.Println("Folder created successfully!")
fmt.Printf("ID: %s\n", folder.ID)
fmt.Printf("ID: %d\n", folder.ID)
fmt.Printf("Title: %s\n", folder.Title)
}

Expand Down
15 changes: 10 additions & 5 deletions cmd/folder/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"fmt"
"os"
"strconv"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -54,9 +55,13 @@ func runFolderDelete(cmd *cobra.Command, args []string) error {

client := api.NewClient(apiKey)

var folderID string
var folderID int
if len(args) > 0 {
folderID = args[0]
var err error
folderID, err = strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid folder ID: %s", args[0])
}
} else {
// Interactive mode - let user select from folders
selected, err := prompt.SearchSelect(prompt.SearchSelectConfig{
Expand All @@ -71,7 +76,7 @@ func runFolderDelete(cmd *cobra.Command, args []string) error {
options := make([]prompt.SelectOption, len(folders.RoutineFolders))
for i, f := range folders.RoutineFolders {
options[i] = prompt.SelectOption{
ID: f.ID,
ID: fmt.Sprintf("%d", f.ID),
Title: f.Title,
Description: fmt.Sprintf("Index: %d", f.Index),
}
Expand All @@ -82,7 +87,7 @@ func runFolderDelete(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
folderID = selected.ID
folderID, _ = strconv.Atoi(selected.ID)
}

// Get folder details first to show what we're deleting
Expand All @@ -93,7 +98,7 @@ func runFolderDelete(cmd *cobra.Command, args []string) error {

// Confirm deletion unless --force is used
if !deleteForce {
fmt.Printf("Are you sure you want to delete folder '%s' (%s)?\n", folder.Title, folder.ID)
fmt.Printf("Are you sure you want to delete folder '%s' (%d)?\n", folder.Title, folder.ID)
fmt.Printf("This action cannot be undone. Routines inside will become unorganized.\n")
fmt.Print("Type 'yes' to confirm: ")

Expand Down
17 changes: 11 additions & 6 deletions cmd/folder/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package folder
import (
"fmt"
"os"
"strconv"

"github.com/spf13/cobra"

Expand Down Expand Up @@ -38,9 +39,13 @@ func runGet(cmd *cobra.Command, args []string) error {

client := api.NewClient(apiKey)

var folderID string
var folderID int
if len(args) > 0 {
folderID = args[0]
var err error
folderID, err = strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid folder ID: %s", args[0])
}
} else {
// Interactive mode - let user select from folders
selected, err := prompt.SearchSelect(prompt.SearchSelectConfig{
Expand All @@ -55,7 +60,7 @@ func runGet(cmd *cobra.Command, args []string) error {
options := make([]prompt.SelectOption, len(folders.RoutineFolders))
for i, f := range folders.RoutineFolders {
options[i] = prompt.SelectOption{
ID: f.ID,
ID: fmt.Sprintf("%d", f.ID),
Title: f.Title,
Description: fmt.Sprintf("Index: %d", f.Index),
}
Expand All @@ -66,7 +71,7 @@ func runGet(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
folderID = selected.ID
folderID, _ = strconv.Atoi(selected.ID)
}

// Search for the folder in the list
Expand All @@ -93,7 +98,7 @@ func runGet(cmd *cobra.Command, args []string) error {
}

if folder == nil {
return fmt.Errorf("folder not found: %s", folderID)
return fmt.Errorf("folder not found: %d", folderID)
}

// Determine output format
Expand Down Expand Up @@ -123,7 +128,7 @@ func runGet(cmd *cobra.Command, args []string) error {

func printFolderDetails(f *api.RoutineFolder, cfg *config.Config) {
fmt.Printf("Folder: %s\n", f.Title)
fmt.Printf("ID: %s\n", f.ID)
fmt.Printf("ID: %d\n", f.ID)
fmt.Printf("Index: %d\n", f.Index)
fmt.Printf("Created: %s\n", f.CreatedAt.Format(cfg.Display.DateFormat))
fmt.Printf("Updated: %s\n", f.UpdatedAt.Format(cfg.Display.DateFormat))
Expand Down
2 changes: 1 addition & 1 deletion cmd/folder/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func runList(cmd *cobra.Command, args []string) error {
for _, f := range allFolders {
updated := f.UpdatedAt.Format(cfg.Display.DateFormat)
table.AddRow(
f.ID,
fmt.Sprintf("%d", f.ID),
f.Title,
fmt.Sprintf("%d", f.Index),
updated,
Expand Down
15 changes: 10 additions & 5 deletions cmd/folder/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package folder
import (
"fmt"
"os"
"strconv"

"github.com/spf13/cobra"

Expand Down Expand Up @@ -48,9 +49,13 @@ func runFolderUpdate(cmd *cobra.Command, args []string) error {

client := api.NewClient(apiKey)

var folderID string
var folderID int
if len(args) > 0 {
folderID = args[0]
var err error
folderID, err = strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("invalid folder ID: %s", args[0])
}
} else {
// Interactive mode - let user select from folders
selected, err := prompt.SearchSelect(prompt.SearchSelectConfig{
Expand All @@ -65,7 +70,7 @@ func runFolderUpdate(cmd *cobra.Command, args []string) error {
options := make([]prompt.SelectOption, len(folders.RoutineFolders))
for i, f := range folders.RoutineFolders {
options[i] = prompt.SelectOption{
ID: f.ID,
ID: fmt.Sprintf("%d", f.ID),
Title: f.Title,
Description: fmt.Sprintf("Index: %d", f.Index),
}
Expand All @@ -76,7 +81,7 @@ func runFolderUpdate(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
folderID = selected.ID
folderID, _ = strconv.Atoi(selected.ID)
}

// Determine output format
Expand Down Expand Up @@ -112,7 +117,7 @@ func runFolderUpdate(cmd *cobra.Command, args []string) error {
fmt.Println(out)
} else {
fmt.Println("Folder updated successfully!")
fmt.Printf("ID: %s\n", folder.ID)
fmt.Printf("ID: %d\n", folder.ID)
fmt.Printf("Title: %s\n", folder.Title)
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/routine/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func printRoutineDetails(r *api.Routine, cfg *config.Config, formatter output.Fo
fmt.Printf("ID: %s\n", r.ID)

if r.FolderID != nil {
fmt.Printf("Folder: %s\n", *r.FolderID)
fmt.Printf("Folder: %d\n", *r.FolderID)
}

fmt.Printf("Created: %s\n", r.CreatedAt.Format(cfg.Display.DateFormat))
Expand Down
9 changes: 7 additions & 2 deletions cmd/routine/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package routine
import (
"fmt"
"os"
"strconv"

"github.com/spf13/cobra"

Expand Down Expand Up @@ -94,9 +95,13 @@ func runList(cmd *cobra.Command, args []string) error {

// Filter by folder if specified
if listFolder != "" {
folderID, err := strconv.Atoi(listFolder)
if err != nil {
return fmt.Errorf("invalid folder ID: %s", listFolder)
}
var filtered []api.Routine
for _, r := range allRoutines {
if r.FolderID != nil && *r.FolderID == listFolder {
if r.FolderID != nil && *r.FolderID == folderID {
filtered = append(filtered, r)
}
}
Expand All @@ -120,7 +125,7 @@ func runList(cmd *cobra.Command, args []string) error {
for _, r := range allRoutines {
folder := "-"
if r.FolderID != nil {
folder = *r.FolderID
folder = fmt.Sprintf("%d", *r.FolderID)
}

updated := r.UpdatedAt.Format(cfg.Display.DateFormat)
Expand Down
30 changes: 22 additions & 8 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,14 @@ func (c *Client) CreateRoutine(req *CreateRoutineRequest) (*Routine, error) {
return nil, err
}

return &result.Routine, nil
if len(result.Routines) == 0 {
return nil, &APIError{
ErrorCode: "EMPTY_RESPONSE",
ErrorMessage: "API returned no routines in response",
}
}

return &result.Routines[0], nil
}

// UpdateRoutine updates an existing routine
Expand All @@ -377,7 +384,14 @@ func (c *Client) UpdateRoutine(id string, req *UpdateRoutineRequest) (*Routine,
return nil, err
}

return &result.Routine, nil
if len(result.Routines) == 0 {
return nil, &APIError{
ErrorCode: "EMPTY_RESPONSE",
ErrorMessage: "API returned no routines in response",
}
}

return &result.Routines[0], nil
}

// CreateRoutineFolder creates a new routine folder
Expand All @@ -403,11 +417,11 @@ func (c *Client) CreateRoutineFolder(req *CreateRoutineFolderRequest) (*RoutineF
}

// GetRoutineFolder fetches a single routine folder by ID
func (c *Client) GetRoutineFolder(id string) (*RoutineFolder, error) {
func (c *Client) GetRoutineFolder(id int) (*RoutineFolder, error) {
var result RoutineFolderResponse
resp, err := c.httpClient.R().
SetResult(&result).
Get("/routine_folders/" + id)
Get(fmt.Sprintf("/routine_folders/%d", id))

if err != nil {
return nil, &APIError{
Expand Down Expand Up @@ -532,12 +546,12 @@ func (c *Client) DeleteRoutine(id string) error {
}

// UpdateRoutineFolder updates an existing routine folder
func (c *Client) UpdateRoutineFolder(id string, req *UpdateRoutineFolderRequest) (*RoutineFolder, error) {
func (c *Client) UpdateRoutineFolder(id int, req *UpdateRoutineFolderRequest) (*RoutineFolder, error) {
var result RoutineFolderResponse
resp, err := c.httpClient.R().
SetBody(req).
SetResult(&result).
Put("/routine_folders/" + id)
Put(fmt.Sprintf("/routine_folders/%d", id))

if err != nil {
return nil, &APIError{
Expand All @@ -554,9 +568,9 @@ func (c *Client) UpdateRoutineFolder(id string, req *UpdateRoutineFolderRequest)
}

// DeleteRoutineFolder deletes a routine folder by ID
func (c *Client) DeleteRoutineFolder(id string) error {
func (c *Client) DeleteRoutineFolder(id int) error {
resp, err := c.httpClient.R().
Delete("/routine_folders/" + id)
Delete(fmt.Sprintf("/routine_folders/%d", id))

if err != nil {
return &APIError{
Expand Down
6 changes: 3 additions & 3 deletions internal/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ const (
type Routine struct {
ID string `json:"id"`
Title string `json:"title"`
FolderID *string `json:"folder_id,omitempty"`
FolderID *int `json:"folder_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Exercises []Exercise `json:"exercises"`
}

// RoutineFolder represents a folder for organizing routines
type RoutineFolder struct {
ID string `json:"id"`
ID int `json:"id"`
Title string `json:"title"`
Index int `json:"index"`
CreatedAt time.Time `json:"created_at"`
Expand Down Expand Up @@ -280,7 +280,7 @@ type WorkoutResponse struct {

// RoutineResponse represents the response from POST/PUT /routines
type RoutineResponse struct {
Routine Routine `json:"routine"`
Routines []Routine `json:"routine"`
}

// RoutineFolderResponse represents the response from POST /routine_folders
Expand Down