Skip to content

Commit 756516c

Browse files
committed
fix: improve error handling and logging in webhook and pull request processing
1 parent ff22db4 commit 756516c

2 files changed

Lines changed: 49 additions & 12 deletions

File tree

backend/pull_requests.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,15 @@ func (p *githubPlugin) linkPRToTask(req *plugin.Request, res *plugin.Response) {
140140
`SELECT id, created_at FROM github_pull_requests WHERE repo_id = $1 AND pr_number = $2`,
141141
b.RepoID, b.PRNumber,
142142
)
143-
prID := uuid.New().String()
144-
prCreatedAt := now
143+
var prID string
144+
var prCreatedAt string
145145
if existResult != nil && len(existResult.Rows) > 0 {
146146
eSc := newRowScanner(existResult.Columns, existResult.Rows[0])
147147
prID = eSc.str("id")
148148
prCreatedAt = eSc.str("created_at")
149+
} else {
150+
prID = uuid.New().String()
151+
prCreatedAt = now
149152
}
150153

151154
var mergedAtStr *string

backend/webhook.go

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ var branchTaskRefRe = regexp.MustCompile(`(?i)\b([A-Z][A-Z0-9]{1,19})-(\d{1,6})\
2020
// ─── POST /webhook ────────────────────────────────────────────────────────────
2121

2222
func (p *githubPlugin) receiveWebhook(req *plugin.Request, res *plugin.Response) {
23-
event := req.Headers["x-github-event"]
24-
signature := req.Headers["x-hub-signature-256"]
23+
event := req.Headers["X-Github-Event"]
24+
signature := req.Headers["X-Hub-Signature-256"]
2525

2626
body := req.Body
2727
if len(body) == 0 {
@@ -36,17 +36,26 @@ func (p *githubPlugin) receiveWebhook(req *plugin.Request, res *plugin.Response)
3636
}
3737

3838
// Always 204 so GitHub does not retry on application errors.
39-
_ = p.handleWebhookEvent(repoFullName, event, signature, body)
39+
if err := p.handleWebhookEvent(repoFullName, event, signature, body); err != nil {
40+
p.log.Error("github: webhook handler error: " + err.Error())
41+
}
4042
res.NoContent()
4143
}
4244

4345
func (p *githubPlugin) handleWebhookEvent(repoFullName, event, signature string, payload []byte) error {
46+
p.log.Info("github: webhook received, repo=" + repoFullName + ", event=" + event)
47+
4448
// Look up the repository by full name.
4549
result, err := p.db.Query(`
4650
SELECT id, project_id, integration_id, owner, repo_name, full_name, default_branch, webhook_secret_enc
4751
FROM github_repositories WHERE full_name = $1
4852
`, repoFullName)
49-
if err != nil || len(result.Rows) == 0 {
53+
if err != nil {
54+
p.log.Error("github: failed to query repository: " + err.Error() + ", repo=" + repoFullName)
55+
return err
56+
}
57+
if len(result.Rows) == 0 {
58+
p.log.Info("github: repository not found, repo=" + repoFullName)
5059
return nil
5160
}
5261
sc := newRowScanner(result.Columns, result.Rows[0])
@@ -57,16 +66,24 @@ func (p *githubPlugin) handleWebhookEvent(repoFullName, event, signature string,
5766
// Verify HMAC signature.
5867
if webhookSecretEnc != "" {
5968
secret, dErr := p.decrypt(webhookSecretEnc)
60-
if dErr == nil && !verifyHMAC(payload, secret, signature) {
69+
if dErr != nil {
70+
p.log.Error("github: failed to decrypt webhook secret: " + dErr.Error() + ", repo=" + repoFullName)
71+
return dErr
72+
}
73+
if !verifyHMAC(payload, secret, signature) {
74+
p.log.Info("github: invalid webhook signature, repo=" + repoFullName)
6175
return nil // silently drop invalid signatures
6276
}
6377
}
6478

6579
switch event {
6680
case "pull_request":
81+
p.log.Info("github: handling pull_request event, repo=" + repoFullName)
6782
return p.handlePREvent(repoID, projectID, payload)
6883
case "push":
6984
return p.handlePushEvent(repoID, projectID, payload)
85+
default:
86+
p.log.Info("github: unhandled event type, event=" + event)
7087
}
7188
return nil
7289
}
@@ -77,9 +94,13 @@ func (p *githubPlugin) handlePREvent(repoID, projectID string, payload []byte) e
7794
PullRequest ghPullRequest `json:"pull_request"`
7895
}
7996
if err := json.Unmarshal(payload, &event); err != nil {
80-
return nil
97+
p.log.Error("github: failed to parse pull_request event: " + err.Error())
98+
return err
8199
}
82100
gh := &event.PullRequest
101+
102+
p.log.Info("github: processing pull_request, action=" + event.Action + ", pr_number=" + strconv.Itoa(gh.Number) + ", title=" + gh.Title + ", repo_id=" + repoID)
103+
83104
state := gh.State
84105
if gh.Merged {
85106
state = "merged"
@@ -94,20 +115,29 @@ func (p *githubPlugin) handlePREvent(repoID, projectID string, payload []byte) e
94115
}
95116

96117
// Check if PR already cached.
97-
existResult, _ := p.db.Query(
118+
existResult, err := p.db.Query(
98119
`SELECT id, created_at FROM github_pull_requests WHERE repo_id = $1 AND pr_number = $2`,
99120
repoID, gh.Number,
100121
)
101-
prID := uuid.New().String()
102-
prCreatedAt := now
122+
if err != nil {
123+
p.log.Error("github: failed to check existing PR: " + err.Error() + ", repo_id=" + repoID + ", pr_number=" + strconv.Itoa(gh.Number))
124+
return err
125+
}
126+
var prID string
127+
var prCreatedAt string
103128
if existResult != nil && len(existResult.Rows) > 0 {
104129
eSc := newRowScanner(existResult.Columns, existResult.Rows[0])
105130
prID = eSc.str("id")
106131
prCreatedAt = eSc.str("created_at")
132+
p.log.Info("github: PR already cached, updating, pr_id=" + prID + ", pr_number=" + strconv.Itoa(gh.Number))
133+
} else {
134+
prID = uuid.New().String()
135+
prCreatedAt = now
136+
p.log.Info("github: PR not cached, inserting, pr_id=" + prID + ", pr_number=" + strconv.Itoa(gh.Number))
107137
}
108138

109139
// Upsert the PR cache.
110-
_, err := p.db.Exec(`
140+
_, err = p.db.Exec(`
111141
INSERT INTO github_pull_requests
112142
(id, project_id, repo_id, pr_number, github_pr_id, title, state, html_url, head_branch, base_branch, author, merged_at, created_at, updated_at)
113143
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)
@@ -117,9 +147,12 @@ func (p *githubPlugin) handlePREvent(repoID, projectID string, payload []byte) e
117147
`, prID, projectID, repoID, gh.Number, gh.ID, gh.Title, state,
118148
gh.HTMLURL, gh.Head.Ref, gh.Base.Ref, gh.User.Login, mergedAtStr, prCreatedAt, now)
119149
if err != nil {
150+
p.log.Error("github: failed to upsert PR: " + err.Error() + ", repo_id=" + repoID + ", pr_number=" + strconv.Itoa(gh.Number))
120151
return err
121152
}
122153

154+
p.log.Info("github: PR saved successfully, pr_id=" + prID + ", pr_number=" + strconv.Itoa(gh.Number) + ", action=" + event.Action)
155+
123156
// On "opened"/"reopened": auto-link to task if head branch is already linked.
124157
if event.Action == "opened" || event.Action == "reopened" {
125158
brResult, _ := p.db.Query(
@@ -141,6 +174,7 @@ func (p *githubPlugin) handlePREvent(repoID, projectID string, payload []byte) e
141174
"repo_id": repoID,
142175
"pr_number": gh.Number,
143176
})
177+
p.log.Info("github: PR auto-linked to task, task_id=" + taskID + ", pr_number=" + strconv.Itoa(gh.Number))
144178
}
145179
}
146180

0 commit comments

Comments
 (0)