Adds the *_list partners that the existing *_get tools have been
missing. Same pattern as repo_list — owner allowlisted, capLimit
helper for pagination, next_page surfaced when the page is full.
internal/gitea/issues.go:
- ListIssues(owner, repo, args) hitting
GET /api/v1/repos/{owner}/{repo}/issues with type=issues server-side
so PRs don't leak in (gitea conflates them on this endpoint).
- ListIssuesArgs struct: State, Labels, Since (ISO 8601), Page, Limit.
internal/gitea/workflows.go:
- ListWorkflowRuns(owner, repo, args) hitting
GET /api/v1/repos/{owner}/{repo}/actions/runs.
- Expanded WorkflowRun struct with DisplayTitle, Event, HeadSHA,
HeadBranch, WorkflowID, RunNumber, UpdatedAt, Actor so callers
can pin runs to a commit / branch without a second lookup.
- ListWorkflowRunsArgs: Branch, HeadSHA, Status, Event, Workflow,
Page, Limit. Status/Event 'all' treated as no-filter.
internal/tools/issue_list.go:
- Default state=open, default limit=30 (matches repo_list).
- next_page returned only when len(issues) == limit.
internal/tools/workflow_run_list.go:
- Default limit=10 (most common use is 'what just happened',
not paging).
- Returns runs + total + optional next_page.
Tests: table-driven for both — happy path, empty result, filter
combinations, allowlist rejection. workflow_run_list also asserts
the 'status=all is no-op' behavior (no query param emitted).
Closes #28
Closes #29
This commit is contained in:
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Issue struct {
|
||||
@@ -72,6 +74,50 @@ func (c *Client) CreateIssue(ctx context.Context, owner, repo string, args Creat
|
||||
return &iss, nil
|
||||
}
|
||||
|
||||
// ListIssuesArgs captures the optional query params for ListIssues.
|
||||
type ListIssuesArgs struct {
|
||||
State string // "open" | "closed" | "all"
|
||||
Labels string // comma-separated label names
|
||||
Since string // ISO 8601
|
||||
Page int
|
||||
Limit int
|
||||
}
|
||||
|
||||
// ListIssues fetches issues for a repo. Pulls are excluded server-side
|
||||
// (type=issues) so they don't leak through the same endpoint.
|
||||
func (c *Client) ListIssues(ctx context.Context, owner, repo string, args ListIssuesArgs) ([]Issue, error) {
|
||||
q := url.Values{}
|
||||
q.Set("type", "issues")
|
||||
if args.State != "" {
|
||||
q.Set("state", args.State)
|
||||
}
|
||||
if args.Labels != "" {
|
||||
q.Set("labels", args.Labels)
|
||||
}
|
||||
if args.Since != "" {
|
||||
q.Set("since", args.Since)
|
||||
}
|
||||
if args.Page > 0 {
|
||||
q.Set("page", strconv.Itoa(args.Page))
|
||||
}
|
||||
if args.Limit > 0 {
|
||||
q.Set("limit", strconv.Itoa(args.Limit))
|
||||
}
|
||||
p := fmt.Sprintf("/api/v1/repos/%s/%s/issues?%s", owner, repo, q.Encode())
|
||||
body, status, err := c.GetJSON(ctx, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := MapStatus(status, body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var issues []Issue
|
||||
if err := json.Unmarshal(body, &issues); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return issues, nil
|
||||
}
|
||||
|
||||
// SetIssueState flips an issue between "open" and "closed" via PATCH.
|
||||
// Gitea uses the same endpoint for both transitions.
|
||||
func (c *Client) SetIssueState(ctx context.Context, owner, repo string, number int, state string) (*Issue, error) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -54,11 +55,21 @@ func (c *Client) DispatchWorkflow(ctx context.Context, owner, repo, workflow str
|
||||
|
||||
// WorkflowRun represents a Gitea Actions run.
|
||||
type WorkflowRun struct {
|
||||
ID int64 `json:"id"`
|
||||
Status string `json:"status"` // queued | in_progress | completed
|
||||
Conclusion string `json:"conclusion"` // success | failure | cancelled | skipped (only when completed)
|
||||
StartedAt string `json:"started_at"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
ID int64 `json:"id"`
|
||||
DisplayTitle string `json:"display_title,omitempty"`
|
||||
Status string `json:"status"` // queued | in_progress | completed
|
||||
Conclusion string `json:"conclusion"` // success | failure | cancelled | skipped (only when completed)
|
||||
Event string `json:"event,omitempty"`
|
||||
HeadSHA string `json:"head_sha,omitempty"`
|
||||
HeadBranch string `json:"head_branch,omitempty"`
|
||||
WorkflowID string `json:"workflow_id,omitempty"`
|
||||
RunNumber int64 `json:"run_number,omitempty"`
|
||||
StartedAt string `json:"started_at"`
|
||||
UpdatedAt string `json:"updated_at,omitempty"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
Actor struct {
|
||||
Login string `json:"login"`
|
||||
} `json:"actor,omitempty"`
|
||||
}
|
||||
|
||||
// GetWorkflowRun fetches the status of a specific Actions run.
|
||||
@@ -77,3 +88,59 @@ func (c *Client) GetWorkflowRun(ctx context.Context, owner, repo string, runID i
|
||||
}
|
||||
return &run, nil
|
||||
}
|
||||
|
||||
// ListWorkflowRunsArgs captures the optional query params for ListWorkflowRuns.
|
||||
type ListWorkflowRunsArgs struct {
|
||||
Branch string
|
||||
HeadSHA string
|
||||
Status string // queued | in_progress | completed | all
|
||||
Event string // push | pull_request | schedule | workflow_dispatch | all
|
||||
Workflow string
|
||||
Page int
|
||||
Limit int
|
||||
}
|
||||
|
||||
type workflowRunsResponse struct {
|
||||
TotalCount int64 `json:"total_count"`
|
||||
WorkflowRuns []WorkflowRun `json:"workflow_runs"`
|
||||
}
|
||||
|
||||
// ListWorkflowRuns fetches recent Actions runs for a repo with optional filters.
|
||||
// Status / Event of "all" or "" are treated as no-filter.
|
||||
func (c *Client) ListWorkflowRuns(ctx context.Context, owner, repo string, args ListWorkflowRunsArgs) (*workflowRunsResponse, error) {
|
||||
q := url.Values{}
|
||||
if args.Branch != "" {
|
||||
q.Set("branch", args.Branch)
|
||||
}
|
||||
if args.HeadSHA != "" {
|
||||
q.Set("head_sha", args.HeadSHA)
|
||||
}
|
||||
if args.Status != "" && args.Status != "all" {
|
||||
q.Set("status", args.Status)
|
||||
}
|
||||
if args.Event != "" && args.Event != "all" {
|
||||
q.Set("event", args.Event)
|
||||
}
|
||||
if args.Workflow != "" {
|
||||
q.Set("workflow", args.Workflow)
|
||||
}
|
||||
if args.Page > 0 {
|
||||
q.Set("page", strconv.Itoa(args.Page))
|
||||
}
|
||||
if args.Limit > 0 {
|
||||
q.Set("limit", strconv.Itoa(args.Limit))
|
||||
}
|
||||
p := fmt.Sprintf("/api/v1/repos/%s/%s/actions/runs?%s", owner, repo, q.Encode())
|
||||
body, status, err := c.GetJSON(ctx, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := MapStatus(status, body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resp workflowRunsResponse
|
||||
if err := json.Unmarshal(body, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user