Stop the Gitea source ingesting Orchestra's own pull requests
The issues endpoint returns pull requests alongside issues, and nothing filtered them. The first submission this deployment ever made, kami/test-e2e#8, came straight back as task 06G4E83E4KRXM8DS90M2648MGM with the submission packet as its description. That task would have implemented, reviewed and submitted again, opening a pull request per cycle. The webhook had the same hole from the other side: a pull_request delivery leaves the issue key empty, so it would have appended a task numbered 0 with no title. Both routes now refuse a pull request, and the poll count reports what was ingested rather than what was listed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVbaKucEYBjMqVeUgJUsc1
This commit is contained in:
@@ -283,10 +283,26 @@ type giteaIssue struct {
|
||||
Labels []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"labels"`
|
||||
// PullRequest is set by Gitea on a listing entry that is a pull request.
|
||||
// The issues endpoint returns both, so without this every submission
|
||||
// Orchestra makes is ingested back as a new task whose description is the
|
||||
// submission packet, and that task submits again.
|
||||
PullRequest *struct {
|
||||
Merged bool `json:"merged"`
|
||||
} `json:"pull_request"`
|
||||
}
|
||||
|
||||
// isPullRequest reports whether this listing entry is a pull request rather
|
||||
// than an issue. Orchestra opens pull requests itself; a source that accepts
|
||||
// them as work is a loop.
|
||||
func (i giteaIssue) isPullRequest() bool { return i.PullRequest != nil }
|
||||
type giteaWebhook struct {
|
||||
Action string `json:"action"`
|
||||
Issue giteaIssue `json:"issue"`
|
||||
Action string `json:"action"`
|
||||
Issue giteaIssue `json:"issue"`
|
||||
// A pull_request delivery carries its payload here and leaves issue
|
||||
// empty, so without this the hook would append a task numbered 0 with no
|
||||
// title. Orchestra opens pull requests itself and never takes one as work.
|
||||
PullRequest *giteaIssue `json:"pull_request"`
|
||||
Repository struct {
|
||||
FullName string `json:"full_name"`
|
||||
} `json:"repository"`
|
||||
@@ -377,6 +393,9 @@ func (g Gitea) IngestWebhook(body []byte, signature string, sink Sink) error {
|
||||
if h.Action == "closed" || h.Action == "deleted" {
|
||||
return nil
|
||||
}
|
||||
if h.PullRequest != nil || h.Issue.isPullRequest() || h.Issue.Number == 0 {
|
||||
return nil
|
||||
}
|
||||
project := g.Project
|
||||
if project == "" {
|
||||
project = g.Repo
|
||||
@@ -444,12 +463,17 @@ func (g Gitea) Poll(ctx context.Context, sink Sink) (int, error) {
|
||||
if project == "" {
|
||||
project = g.Repo
|
||||
}
|
||||
ingested := 0
|
||||
for _, i := range issues {
|
||||
if i.isPullRequest() {
|
||||
continue
|
||||
}
|
||||
ingested++
|
||||
if err := sink.Append(g.event(i, g.sourceName(), project)); err != nil && !errors.Is(err, domain.ErrDuplicate) {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return len(issues), nil
|
||||
return ingested, nil
|
||||
}
|
||||
func (g Gitea) Reflect(e domain.Event) error {
|
||||
if e.Type != "TaskCompleted" && e.Type != "TaskBlocked" && e.Type != "TaskFailed" {
|
||||
|
||||
Reference in New Issue
Block a user