Skip to content

Commit 4b44bc3

Browse files
authored
Merge pull request #10 from PinataCloud/fix/templates-ref-path
fix: support ref and path for template submission (branch/subfolder templates)
2 parents 2c27cb7 + 97350de commit 4b44bc3

5 files changed

Lines changed: 211 additions & 38 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
### 🚀 Features
8+
9+
- Add `agents templates refs` and `agents templates search-refs` to list/search branches and tags for a repo
10+
- Support submitting/updating templates from a subdirectory via `--path` (monorepos)
11+
- Support `--name`/`--slug` overrides when submitting templates
12+
713
### 🐛 Bug Fixes
814

915
- Allow flags to be passed after positional arguments (e.g. `files get <id> --network public`); previously such flags were silently ignored
16+
- Fix `agents templates update`/`submit`/`validate` for templates from a branch or subfolder: send the API's `ref` (with `path` for monorepos) instead of the removed `branch` field; `--branch`/`-b` remain as aliases for `--ref`
17+
- Surface server error messages (including validation errors) for the templates API instead of a generic "server returned status N"
1018

1119
### 🚜 Refactor
1220

internal/agents/client.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,37 @@ func doJSON(method, path string, body interface{}, result interface{}) error {
7575
return nil
7676
}
7777

78+
// apiErrorMessage extracts a human-readable error from an API error response
79+
// body. The API returns "error" either as a plain string or as an object
80+
// ({"name","message"} — e.g. ZodError), and may also place a message at the
81+
// top level. Falls back to the status code when nothing usable is found.
82+
func apiErrorMessage(status int, raw []byte) error {
83+
var probe struct {
84+
Error json.RawMessage `json:"error"`
85+
Message string `json:"message"`
86+
}
87+
if err := json.Unmarshal(raw, &probe); err == nil {
88+
var asString string
89+
if len(probe.Error) > 0 && json.Unmarshal(probe.Error, &asString) == nil && asString != "" {
90+
return fmt.Errorf("server error: %s", asString)
91+
}
92+
var asObject struct {
93+
Name string `json:"name"`
94+
Message string `json:"message"`
95+
}
96+
if len(probe.Error) > 0 && json.Unmarshal(probe.Error, &asObject) == nil && asObject.Message != "" {
97+
if asObject.Name != "" {
98+
return fmt.Errorf("server error (%s): %s", asObject.Name, asObject.Message)
99+
}
100+
return fmt.Errorf("server error: %s", asObject.Message)
101+
}
102+
if probe.Message != "" {
103+
return fmt.Errorf("server error: %s", probe.Message)
104+
}
105+
}
106+
return fmt.Errorf("server returned status %d", status)
107+
}
108+
78109
// doRequestURL makes an authenticated HTTP request to a full URL
79110
func doRequestURL(method, url string, body interface{}) (*http.Response, error) {
80111
jwt, err := common.FindToken()

internal/agents/templates.go

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7+
"io"
78
"net/http"
89

910
"pinata/internal/config"
@@ -21,11 +22,8 @@ func doTemplatesJSON(method, path string, body interface{}, result interface{})
2122
defer resp.Body.Close()
2223

2324
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
24-
var errResp ErrorResponse
25-
if decodeErr := json.NewDecoder(resp.Body).Decode(&errResp); decodeErr == nil && errResp.Error != "" {
26-
return fmt.Errorf("server error: %s", errResp.Error)
27-
}
28-
return fmt.Errorf("server returned status %d", resp.StatusCode)
25+
raw, _ := io.ReadAll(resp.Body)
26+
return apiErrorMessage(resp.StatusCode, raw)
2927
}
3028

3129
if result != nil {
@@ -103,11 +101,8 @@ func ListTemplatesBySubmitter() (*TemplateListResponse, error) {
103101
}
104102

105103
// ValidateTemplate validates a git repo for template submission.
106-
func ValidateTemplate(gitURL, branch string) (*ValidateTemplateResponse, error) {
107-
body := SubmitTemplateBody{GitURL: gitURL}
108-
if branch != "" {
109-
body.Branch = branch
110-
}
104+
func ValidateTemplate(gitURL, ref, path string) (*ValidateTemplateResponse, error) {
105+
body := SubmitTemplateBody{GitURL: gitURL, Ref: ref, Path: path}
111106

112107
var response ValidateTemplateResponse
113108
err := doTemplatesJSON(http.MethodPost, "/validate", body, &response)
@@ -126,10 +121,13 @@ func ValidateTemplate(gitURL, branch string) (*ValidateTemplateResponse, error)
126121
}
127122

128123
// SubmitTemplate submits a new template from a git repo URL.
129-
func SubmitTemplate(gitURL, branch string) (*SubmitTemplateResponse, error) {
130-
body := SubmitTemplateBody{GitURL: gitURL}
131-
if branch != "" {
132-
body.Branch = branch
124+
func SubmitTemplate(gitURL, ref, path, nameOverride, slugOverride string) (*SubmitTemplateResponse, error) {
125+
body := SubmitTemplateBody{
126+
GitURL: gitURL,
127+
Ref: ref,
128+
Path: path,
129+
NameOverride: nameOverride,
130+
SlugOverride: slugOverride,
133131
}
134132

135133
var response SubmitTemplateResponse
@@ -149,13 +147,14 @@ func SubmitTemplate(gitURL, branch string) (*SubmitTemplateResponse, error) {
149147
}
150148

151149
// UpdateTemplate updates an existing template submission by re-pulling from the repo.
152-
func UpdateTemplate(templateID, gitURL, branch string) (*SubmitTemplateResponse, error) {
153-
body := SubmitTemplateBody{}
154-
if gitURL != "" {
155-
body.GitURL = gitURL
156-
}
157-
if branch != "" {
158-
body.Branch = branch
150+
// ref is required by the API; gitUrl falls back to the existing repo when omitted.
151+
func UpdateTemplate(templateID, gitURL, ref, path, nameOverride, slugOverride string) (*SubmitTemplateResponse, error) {
152+
body := SubmitTemplateBody{
153+
GitURL: gitURL,
154+
Ref: ref,
155+
Path: path,
156+
NameOverride: nameOverride,
157+
SlugOverride: slugOverride,
159158
}
160159

161160
var response SubmitTemplateResponse
@@ -211,3 +210,43 @@ func ListBranches(gitURL string) (*BranchesResponse, error) {
211210

212211
return &response, nil
213212
}
213+
214+
// ListRefs lists branches and tags (with the default branch) for a public git repository.
215+
func ListRefs(gitURL string) (*RefsResponse, error) {
216+
body := RefsBody{GitURL: gitURL}
217+
218+
var response RefsResponse
219+
err := doTemplatesJSON(http.MethodPost, "/refs", body, &response)
220+
if err != nil {
221+
return nil, err
222+
}
223+
224+
formattedJSON, err := json.MarshalIndent(response, "", " ")
225+
if err != nil {
226+
return nil, errors.New("failed to format JSON")
227+
}
228+
229+
fmt.Println(string(formattedJSON))
230+
231+
return &response, nil
232+
}
233+
234+
// SearchRefs searches branches and tags by name for a public git repository.
235+
func SearchRefs(gitURL, search string) (*SearchRefsResponse, error) {
236+
body := SearchRefsBody{GitURL: gitURL, Search: search}
237+
238+
var response SearchRefsResponse
239+
err := doTemplatesJSON(http.MethodPost, "/refs/search", body, &response)
240+
if err != nil {
241+
return nil, err
242+
}
243+
244+
formattedJSON, err := json.MarshalIndent(response, "", " ")
245+
if err != nil {
246+
return nil, errors.New("failed to format JSON")
247+
}
248+
249+
fmt.Println(string(formattedJSON))
250+
251+
return &response, nil
252+
}

internal/agents/types.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -592,8 +592,11 @@ type TemplateDetailResponse struct {
592592

593593
// SubmitTemplateBody is the request body for validating, submitting, or updating a template.
594594
type SubmitTemplateBody struct {
595-
GitURL string `json:"gitUrl,omitempty"`
596-
Branch string `json:"branch,omitempty"`
595+
GitURL string `json:"gitUrl,omitempty"`
596+
Ref string `json:"ref,omitempty"`
597+
Path string `json:"path,omitempty"`
598+
NameOverride string `json:"nameOverride,omitempty"`
599+
SlugOverride string `json:"slugOverride,omitempty"`
597600
}
598601

599602
// ValidateTemplateResponse is the response from validating a git repo for template submission.
@@ -630,6 +633,30 @@ type BranchesResponse struct {
630633
Branches []string `json:"branches"`
631634
}
632635

636+
// RefsBody is the request body for listing repo branches and tags.
637+
type RefsBody struct {
638+
GitURL string `json:"gitUrl"`
639+
}
640+
641+
// RefsResponse is the response from listing repo branches and tags.
642+
type RefsResponse struct {
643+
Branches []string `json:"branches"`
644+
Tags []string `json:"tags"`
645+
DefaultBranch *string `json:"defaultBranch"`
646+
}
647+
648+
// SearchRefsBody is the request body for searching repo branches and tags.
649+
type SearchRefsBody struct {
650+
GitURL string `json:"gitUrl"`
651+
Search string `json:"search"`
652+
}
653+
654+
// SearchRefsResponse is the response from searching repo branches and tags.
655+
type SearchRefsResponse struct {
656+
Branches []string `json:"branches"`
657+
Tags []string `json:"tags"`
658+
}
659+
633660
// --- Config ---
634661

635662
// ConfigResponse is the response from getting agent config.

main.go

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,18 +2069,24 @@ Examples:
20692069
ArgsUsage: "[git URL]",
20702070
Flags: []cli.Flag{
20712071
&cli.StringFlag{
2072-
Name: "branch",
2073-
Aliases: []string{"b"},
2074-
Usage: "Branch to validate (default: main)",
2072+
Name: "ref",
2073+
Aliases: []string{"r", "branch", "b"},
2074+
Usage: "Git ref to validate (e.g. refs/heads/main, refs/tags/v1.0.0, or a bare branch name; default: main)",
2075+
},
2076+
&cli.StringFlag{
2077+
Name: "path",
2078+
Aliases: []string{"p"},
2079+
Usage: "Subdirectory within the repo to use as the template root (for monorepos)",
20752080
},
20762081
},
20772082
Action: func(ctx context.Context, cmd *cli.Command) error {
20782083
gitURL := cmd.Args().First()
20792084
if gitURL == "" {
20802085
return errors.New("no git URL provided")
20812086
}
2082-
branch := cmd.String("branch")
2083-
_, err := agents.ValidateTemplate(gitURL, branch)
2087+
ref := cmd.String("ref")
2088+
path := cmd.String("path")
2089+
_, err := agents.ValidateTemplate(gitURL, ref, path)
20842090
return err
20852091
},
20862092
},
@@ -2091,18 +2097,34 @@ Examples:
20912097
ArgsUsage: "[git URL]",
20922098
Flags: []cli.Flag{
20932099
&cli.StringFlag{
2094-
Name: "branch",
2095-
Aliases: []string{"b"},
2096-
Usage: "Branch to submit from (default: main)",
2100+
Name: "ref",
2101+
Aliases: []string{"r", "branch", "b"},
2102+
Usage: "Git ref to submit from (e.g. refs/heads/main, refs/tags/v1.0.0, or a bare branch name; default: main)",
2103+
},
2104+
&cli.StringFlag{
2105+
Name: "path",
2106+
Aliases: []string{"p"},
2107+
Usage: "Subdirectory within the repo to use as the template root (for monorepos)",
2108+
},
2109+
&cli.StringFlag{
2110+
Name: "name",
2111+
Usage: "Override the template name from manifest.json",
2112+
},
2113+
&cli.StringFlag{
2114+
Name: "slug",
2115+
Usage: "Override the template slug from manifest.json (lowercase, hyphens only)",
20972116
},
20982117
},
20992118
Action: func(ctx context.Context, cmd *cli.Command) error {
21002119
gitURL := cmd.Args().First()
21012120
if gitURL == "" {
21022121
return errors.New("no git URL provided")
21032122
}
2104-
branch := cmd.String("branch")
2105-
_, err := agents.SubmitTemplate(gitURL, branch)
2123+
ref := cmd.String("ref")
2124+
path := cmd.String("path")
2125+
nameOverride := cmd.String("name")
2126+
slugOverride := cmd.String("slug")
2127+
_, err := agents.SubmitTemplate(gitURL, ref, path, nameOverride, slugOverride)
21062128
return err
21072129
},
21082130
},
@@ -2117,9 +2139,22 @@ Examples:
21172139
Usage: "New git URL (optional, uses existing if omitted)",
21182140
},
21192141
&cli.StringFlag{
2120-
Name: "branch",
2121-
Aliases: []string{"b"},
2122-
Usage: "Branch to pull from (default: main)",
2142+
Name: "ref",
2143+
Aliases: []string{"r", "branch", "b"},
2144+
Usage: "Git ref to pull from (e.g. refs/heads/main, refs/tags/v1.0.0, or a bare branch name; default: main)",
2145+
},
2146+
&cli.StringFlag{
2147+
Name: "path",
2148+
Aliases: []string{"p"},
2149+
Usage: "Subdirectory within the repo to use as the template root (for monorepos)",
2150+
},
2151+
&cli.StringFlag{
2152+
Name: "name",
2153+
Usage: "Override the template name from manifest.json",
2154+
},
2155+
&cli.StringFlag{
2156+
Name: "slug",
2157+
Usage: "Override the template slug from manifest.json (lowercase, hyphens only)",
21232158
},
21242159
},
21252160
Action: func(ctx context.Context, cmd *cli.Command) error {
@@ -2128,8 +2163,11 @@ Examples:
21282163
return errors.New("no template ID provided")
21292164
}
21302165
gitURL := cmd.String("git-url")
2131-
branch := cmd.String("branch")
2132-
_, err := agents.UpdateTemplate(templateID, gitURL, branch)
2166+
ref := cmd.String("ref")
2167+
path := cmd.String("path")
2168+
nameOverride := cmd.String("name")
2169+
slugOverride := cmd.String("slug")
2170+
_, err := agents.UpdateTemplate(templateID, gitURL, ref, path, nameOverride, slugOverride)
21332171
return err
21342172
},
21352173
},
@@ -2160,6 +2198,36 @@ Examples:
21602198
return err
21612199
},
21622200
},
2201+
{
2202+
Name: "refs",
2203+
Usage: "List branches and tags (with the default branch) for a git repository",
2204+
ArgsUsage: "[git URL]",
2205+
Action: func(ctx context.Context, cmd *cli.Command) error {
2206+
gitURL := cmd.Args().First()
2207+
if gitURL == "" {
2208+
return errors.New("no git URL provided")
2209+
}
2210+
_, err := agents.ListRefs(gitURL)
2211+
return err
2212+
},
2213+
},
2214+
{
2215+
Name: "search-refs",
2216+
Usage: "Search branches and tags by name for a git repository",
2217+
ArgsUsage: "[git URL] [search query]",
2218+
Action: func(ctx context.Context, cmd *cli.Command) error {
2219+
gitURL := cmd.Args().Get(0)
2220+
search := cmd.Args().Get(1)
2221+
if gitURL == "" {
2222+
return errors.New("no git URL provided")
2223+
}
2224+
if search == "" {
2225+
return errors.New("no search query provided")
2226+
}
2227+
_, err := agents.SearchRefs(gitURL, search)
2228+
return err
2229+
},
2230+
},
21632231
},
21642232
},
21652233
{

0 commit comments

Comments
 (0)