internal/gaby: reduce scope of github webhook action

Instead of running all syncs and changes when a github
webhook issue event is received, sync only the relevant
GitHub project, and post related issues for the issue
in question.

Change-Id: Ic1ec7956116342af46ae2258b72374f42d628102
Reviewed-on: https://go-review.googlesource.com/c/oscar/+/613175
Reviewed-by: Jonathan Amsterdam <jba@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/internal/gaby/github_event.go b/internal/gaby/github_event.go
index 6e74bf8..329b542 100644
--- a/internal/gaby/github_event.go
+++ b/internal/gaby/github_event.go
@@ -6,11 +6,11 @@
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"net/http"
 
 	"golang.org/x/oscar/internal/github"
+	"golang.org/x/oscar/internal/githubdocs"
 )
 
 // handleGitHubEvent handles incoming webhook requests from GitHub.
@@ -43,15 +43,54 @@
 
 // handleGitHubIssueEvent handles incoming GitHub "issue" events.
 //
-// If the event corresponds to a new issue, the function runs the
-// same actions as are peformed by the /cron endpoint.
+// If the event corresponds to a new issue, the function syncs
+// the corresponding GitHub project, posts related issues for the
+// new GitHub issue, and fixes comments in all new issues.
+// TODO(https://github.com/golang/oscar/issues/19): Run commentfix for
+// the single issue instead of all new issues.
 //
 // Otherwise, it logs the event and takes no other action.
 func (g *Gaby) handleGithubIssueEvent(ctx context.Context, event *github.WebhookIssueEvent) error {
 	if event.Action != github.WebhookIssueActionOpened {
 		g.slog.Info("ignoring GitHub issue event (action is not opened)", "event", event, "action", event)
+		return nil
 	}
 
 	g.slog.Info("handling GitHub issue event", "event", event)
-	return errors.Join(g.syncAndRunAll(ctx)...)
+
+	project := event.Repository.Project
+	if flags.enablesync {
+		if err := g.syncGitHubProject(ctx, project); err != nil {
+			return err
+		}
+		if err := g.embedAll(ctx); err != nil {
+			return err
+		}
+	}
+
+	// Do not attempt changes unless sync is enabled and completely succeeded.
+	if flags.enablechanges && flags.enablesync {
+		// No need to lock; [related.Poster.Post] and [related.Poster.Run] can
+		// happen concurrently.
+		if err := g.relatedPoster.Post(ctx, project, event.Issue.Number); err != nil {
+			return err
+		}
+		if err := g.fixAllComments(ctx); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// syncGitHubProject syncs the document database with respect to a single
+// GitHub project.
+func (g *Gaby) syncGitHubProject(ctx context.Context, project string) error {
+	g.db.Lock(gabyGitHubSyncLock)
+	defer g.db.Unlock(gabyGitHubSyncLock)
+
+	if err := g.github.SyncProject(ctx, project); err != nil {
+		return err
+	}
+	return githubdocs.Sync(ctx, g.slog, g.docs, g.github)
 }
diff --git a/internal/github/webhook.go b/internal/github/webhook.go
index ba7bf0f..eec89b0 100644
--- a/internal/github/webhook.go
+++ b/internal/github/webhook.go
@@ -131,6 +131,7 @@
 // https://docs.github.com/en/webhooks/webhook-events-and-payloads#issues
 type WebhookIssueEvent struct {
 	Action     WebhookIssueAction `json:"action"`
+	Issue      Issue              `json:"issue"`
 	Repository Repository         `json:"repository"`
 	// Additional fields omitted.
 }