feat(agentic): add issue assign and report commands
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
ce3039544e
commit
2df0b73b1e
2 changed files with 147 additions and 0 deletions
|
|
@ -100,6 +100,8 @@ func (s *PrepSubsystem) registerForgeCommands() {
|
|||
c.Command("issue/list", core.Command{Description: "List Forge issues for a repo", Action: s.cmdIssueList})
|
||||
c.Command("issue/comment", core.Command{Description: "Comment on a Forge issue", Action: s.cmdIssueComment})
|
||||
c.Command("issue/create", core.Command{Description: "Create a Forge issue", Action: s.cmdIssueCreate})
|
||||
c.Command("issue/assign", core.Command{Description: "Assign a Forge issue", Action: s.cmdIssueAssign})
|
||||
c.Command("issue/report", core.Command{Description: "Post a structured report to a Forge issue", Action: s.cmdIssueReport})
|
||||
c.Command("issue/update", core.Command{Description: "Update a tracked platform issue", Action: s.cmdIssueUpdate})
|
||||
c.Command("issue/archive", core.Command{Description: "Archive a tracked platform issue", Action: s.cmdIssueArchive})
|
||||
c.Command("pr/get", core.Command{Description: "Get a Forge PR", Action: s.cmdPRGet})
|
||||
|
|
@ -268,6 +270,69 @@ func (s *PrepSubsystem) cmdIssueUpdate(options core.Options) core.Result {
|
|||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdIssueAssign(options core.Options) core.Result {
|
||||
ctx := context.Background()
|
||||
id := optionStringValue(options, "id", "slug", "_arg")
|
||||
if id == "" || optionStringValue(options, "assignee", "agent", "agent_type") == "" {
|
||||
core.Print(nil, "usage: core-agent issue assign <slug> --assignee=codex [--org=core]")
|
||||
return core.Result{Value: core.E("agentic.cmdIssueAssign", "slug or id and assignee are required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleIssueRecordAssign(ctx, core.NewOptions(
|
||||
core.Option{Key: "slug", Value: id},
|
||||
core.Option{Key: "assignee", Value: optionStringValue(options, "assignee", "agent", "agent_type")},
|
||||
))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdIssueAssign", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
output, ok := result.Value.(IssueOutput)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdIssueAssign", "invalid issue assign output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "%s", output.Issue.Slug)
|
||||
core.Print(nil, " assignee: %s", output.Issue.Assignee)
|
||||
core.Print(nil, " status: %s", output.Issue.Status)
|
||||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdIssueReport(options core.Options) core.Result {
|
||||
ctx := context.Background()
|
||||
id := optionStringValue(options, "id", "slug", "_arg")
|
||||
if id == "" {
|
||||
core.Print(nil, "usage: core-agent issue report <slug> --report=\"...\" [--org=core]")
|
||||
return core.Result{Value: core.E("agentic.cmdIssueReport", "slug or id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleIssueRecordReport(ctx, core.NewOptions(
|
||||
core.Option{Key: "slug", Value: id},
|
||||
core.Option{Key: "report", Value: optionAnyValue(options, "report", "body")},
|
||||
core.Option{Key: "author", Value: options.String("author")},
|
||||
))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdIssueReport", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
output, ok := result.Value.(IssueReportOutput)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdIssueReport", "invalid issue report output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "comment: %d", output.Comment.ID)
|
||||
core.Print(nil, " author: %s", output.Comment.Author)
|
||||
core.Print(nil, " body: %s", output.Comment.Body)
|
||||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdIssueArchive(options core.Options) core.Result {
|
||||
ctx := context.Background()
|
||||
id := optionStringValue(options, "id", "slug", "_arg")
|
||||
|
|
|
|||
|
|
@ -188,6 +188,86 @@ func TestCommandsforge_CmdIssueUpdate_Bad_MissingSlug(t *testing.T) {
|
|||
assert.EqualError(t, result.Value.(error), "agentic.cmdIssueUpdate: slug or id is required")
|
||||
}
|
||||
|
||||
func TestCommandsforge_CmdIssueAssign_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/v1/issues/fix-auth", r.URL.Path)
|
||||
require.Equal(t, http.MethodPatch, r.Method)
|
||||
|
||||
bodyResult := core.ReadAll(r.Body)
|
||||
require.True(t, bodyResult.OK)
|
||||
|
||||
var payload map[string]any
|
||||
parseResult := core.JSONUnmarshalString(bodyResult.Value.(string), &payload)
|
||||
require.True(t, parseResult.OK)
|
||||
require.Equal(t, "codex", payload["assignee"])
|
||||
|
||||
_, _ = w.Write([]byte(`{"data":{"issue":{"slug":"fix-auth","title":"Fix auth middleware","status":"open","assignee":"codex"}}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.cmdIssueAssign(core.NewOptions(
|
||||
core.Option{Key: "slug", Value: "fix-auth"},
|
||||
core.Option{Key: "assignee", Value: "codex"},
|
||||
))
|
||||
require.True(t, result.OK)
|
||||
|
||||
output, ok := result.Value.(IssueOutput)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "fix-auth", output.Issue.Slug)
|
||||
assert.Equal(t, "codex", output.Issue.Assignee)
|
||||
}
|
||||
|
||||
func TestCommandsforge_CmdIssueAssign_Bad_MissingAssignee(t *testing.T) {
|
||||
subsystem := testPrepWithPlatformServer(t, nil, "secret-token")
|
||||
result := subsystem.cmdIssueAssign(core.NewOptions(core.Option{Key: "slug", Value: "fix-auth"}))
|
||||
assert.False(t, result.OK)
|
||||
assert.EqualError(t, result.Value.(error), "agentic.cmdIssueAssign: slug or id and assignee are required")
|
||||
}
|
||||
|
||||
func TestCommandsforge_CmdIssueReport_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/v1/issues/fix-auth/comments", r.URL.Path)
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
|
||||
bodyResult := core.ReadAll(r.Body)
|
||||
require.True(t, bodyResult.OK)
|
||||
|
||||
var payload map[string]any
|
||||
parseResult := core.JSONUnmarshalString(bodyResult.Value.(string), &payload)
|
||||
require.True(t, parseResult.OK)
|
||||
|
||||
reportBody := core.JSONMarshalString(map[string]any{
|
||||
"summary": "Build failed",
|
||||
})
|
||||
require.Equal(t, "codex", payload["author"])
|
||||
require.Equal(t, core.Concat("```json\n", reportBody, "\n```"), payload["body"])
|
||||
|
||||
_, _ = w.Write([]byte("{\"data\":{\"comment\":{\"id\":7,\"author\":\"codex\",\"body\":\"report received\"}}}"))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.cmdIssueReport(core.NewOptions(
|
||||
core.Option{Key: "slug", Value: "fix-auth"},
|
||||
core.Option{Key: "report", Value: map[string]any{"summary": "Build failed"}},
|
||||
core.Option{Key: "author", Value: "codex"},
|
||||
))
|
||||
require.True(t, result.OK)
|
||||
|
||||
output, ok := result.Value.(IssueReportOutput)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, 7, output.Comment.ID)
|
||||
assert.Equal(t, "codex", output.Comment.Author)
|
||||
}
|
||||
|
||||
func TestCommandsforge_CmdIssueReport_Bad_MissingSlug(t *testing.T) {
|
||||
subsystem := testPrepWithPlatformServer(t, nil, "secret-token")
|
||||
result := subsystem.cmdIssueReport(core.NewOptions())
|
||||
assert.False(t, result.OK)
|
||||
assert.EqualError(t, result.Value.(error), "agentic.cmdIssueReport: slug or id is required")
|
||||
}
|
||||
|
||||
func TestCommandsforge_CmdIssueArchive_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/v1/issues/fix-auth", r.URL.Path)
|
||||
|
|
@ -321,6 +401,8 @@ func TestCommandsforge_RegisterForgeCommands_Good_RepoSyncRegistered(t *testing.
|
|||
s, c := testPrepWithCore(t, nil)
|
||||
s.registerForgeCommands()
|
||||
assert.Contains(t, c.Commands(), "repo/sync")
|
||||
assert.Contains(t, c.Commands(), "issue/assign")
|
||||
assert.Contains(t, c.Commands(), "issue/report")
|
||||
assert.Contains(t, c.Commands(), "issue/update")
|
||||
assert.Contains(t, c.Commands(), "issue/archive")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue