diff --git a/backend/branches.go b/backend/branches.go index 19e64eb..0ff0211 100644 --- a/backend/branches.go +++ b/backend/branches.go @@ -6,7 +6,6 @@ import ( "fmt" plugin "github.com/Paca-AI/plugin-sdk-go" - "github.com/google/uuid" ) // ─── DTOs ──────────────────────────────────────────────────────────────────── @@ -86,12 +85,11 @@ func (p *githubPlugin) createBranch(req *plugin.Request, res *plugin.Response) { // Link the branch to the task. now := nowStr() - branchID := uuid.New().String() rowsAffected, dbErr := p.db.Exec(` - INSERT INTO github_task_branches (id, task_id, repo_id, branch_name, created_at) - VALUES ($1,$2,$3,$4,$5) + INSERT INTO github_task_branches (task_id, repo_id, branch_name, created_at) + VALUES ($1,$2,$3,$4) ON CONFLICT (task_id, repo_id, branch_name) DO NOTHING - `, branchID, taskID, b.RepoID, b.BranchName, now) + `, taskID, b.RepoID, b.BranchName, now) if dbErr != nil { p.log.Error("failed to link branch to task: " + dbErr.Error()) } else if rowsAffected == 0 { diff --git a/backend/go.mod b/backend/go.mod index f6b48a2..194b2a9 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -2,7 +2,4 @@ module github.com/Paca-AI/first-party/github go 1.24 -require ( - github.com/Paca-AI/plugin-sdk-go v0.2.0 - github.com/google/uuid v1.6.0 -) +require github.com/Paca-AI/plugin-sdk-go v0.2.0 diff --git a/backend/go.sum b/backend/go.sum index bede9ea..8389b8f 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,4 +1,2 @@ github.com/Paca-AI/plugin-sdk-go v0.2.0 h1:Fur6p+OQoC5imq7qmvaQtJnZ3SRVRskx8KcT/rqFHj4= github.com/Paca-AI/plugin-sdk-go v0.2.0/go.mod h1:5WeC6cSEf2wM1ovICZbDaVky9oi5id/Qpdfc5LDAQnw= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/backend/integration.go b/backend/integration.go index eb7c511..b6d0caa 100644 --- a/backend/integration.go +++ b/backend/integration.go @@ -9,7 +9,6 @@ import ( "strings" plugin "github.com/Paca-AI/plugin-sdk-go" - "github.com/google/uuid" ) // ─── DTOs ──────────────────────────────────────────────────────────────────── @@ -358,17 +357,22 @@ func (p *githubPlugin) linkRepository(req *plugin.Request, res *plugin.Response) } now := nowStr() - repoID := uuid.New().String() - _, dbErr := p.db.Exec(` + inserted, dbErr := p.db.Query(` INSERT INTO github_repositories - (id, project_id, integration_id, owner, repo_name, full_name, webhook_id, webhook_secret_enc, default_branch, created_at, updated_at) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$10) - `, repoID, projectID, integrationID, ghRepo.Owner.Login, ghRepo.Name, ghRepo.FullName, webhookID, encSecret, ghRepo.DefaultBranch, now) - if dbErr != nil { + (project_id, integration_id, owner, repo_name, full_name, webhook_id, webhook_secret_enc, default_branch, created_at, updated_at) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$9) + RETURNING id + `, projectID, integrationID, ghRepo.Owner.Login, ghRepo.Name, ghRepo.FullName, webhookID, encSecret, ghRepo.DefaultBranch, now) + if dbErr != nil || len(inserted.Rows) == 0 { _ = ghc.deleteWebhook(context.Background(), ghRepo.Owner.Login, ghRepo.Name, webhookID) - apiError(res, 500, "INTERNAL_ERROR", dbErr.Error()) + if dbErr != nil { + apiError(res, 500, "INTERNAL_ERROR", dbErr.Error()) + } else { + apiError(res, 500, "INTERNAL_ERROR", "insert returned no rows") + } return } + repoID := newRowScanner(inserted.Columns, inserted.Rows[0]).str("id") created(res, repositoryResponse{ ID: repoID, diff --git a/backend/pull_requests.go b/backend/pull_requests.go index 0a9f801..8aad817 100644 --- a/backend/pull_requests.go +++ b/backend/pull_requests.go @@ -6,7 +6,6 @@ import ( "fmt" plugin "github.com/Paca-AI/plugin-sdk-go" - "github.com/google/uuid" ) // ─── DTOs ──────────────────────────────────────────────────────────────────── @@ -135,50 +134,41 @@ func (p *githubPlugin) linkPRToTask(req *plugin.Request, res *plugin.Response) { now := nowStr() - // Check if PR already cached. - existResult, _ := p.db.Query( - `SELECT id, created_at FROM github_pull_requests WHERE repo_id = $1 AND pr_number = $2`, - b.RepoID, b.PRNumber, - ) - var prID string - var prCreatedAt string - if existResult != nil && len(existResult.Rows) > 0 { - eSc := newRowScanner(existResult.Columns, existResult.Rows[0]) - prID = eSc.str("id") - prCreatedAt = eSc.str("created_at") - } else { - prID = uuid.New().String() - prCreatedAt = now - } - var mergedAtStr *string if ghPR.MergedAt != nil { s := ghPR.MergedAt.UTC().Format("2006-01-02T15:04:05.999999999Z") mergedAtStr = &s } - // Upsert the PR cache. - _, err = p.db.Exec(` + // Upsert the PR cache; let PostgreSQL generate id on insert, RETURNING gives us id+created_at. + upserted, err := p.db.Query(` INSERT INTO github_pull_requests - (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) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) + (project_id, repo_id, pr_number, github_pr_id, title, state, html_url, head_branch, base_branch, author, merged_at, created_at, updated_at) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) ON CONFLICT (repo_id, pr_number) DO UPDATE SET - title=$6, state=$7, html_url=$8, head_branch=$9, base_branch=$10, - author=$11, merged_at=$12, updated_at=$14 - `, prID, projectID, b.RepoID, b.PRNumber, ghPR.ID, ghPR.Title, state, - ghPR.HTMLURL, ghPR.Head.Ref, ghPR.Base.Ref, ghPR.User.Login, mergedAtStr, prCreatedAt, now) - if err != nil { - apiError(res, 500, "INTERNAL_ERROR", err.Error()) + title=$5, state=$6, html_url=$7, head_branch=$8, base_branch=$9, + author=$10, merged_at=$11, updated_at=$13 + RETURNING id, created_at + `, projectID, b.RepoID, b.PRNumber, ghPR.ID, ghPR.Title, state, + ghPR.HTMLURL, ghPR.Head.Ref, ghPR.Base.Ref, ghPR.User.Login, mergedAtStr, now, now) + if err != nil || len(upserted.Rows) == 0 { + if err != nil { + apiError(res, 500, "INTERNAL_ERROR", err.Error()) + } else { + apiError(res, 500, "INTERNAL_ERROR", "upsert returned no rows") + } return } + prSc := newRowScanner(upserted.Columns, upserted.Rows[0]) + prID := prSc.str("id") + prCreatedAt := prSc.str("created_at") // Link the PR to the task. - linkID := uuid.New().String() rowsAffected, lErr := p.db.Exec(` - INSERT INTO github_task_pr_links (id, task_id, pull_request_id, created_at) - VALUES ($1,$2,$3,$4) + INSERT INTO github_task_pr_links (task_id, pull_request_id, created_at) + VALUES ($1,$2,$3) ON CONFLICT (task_id, pull_request_id) DO NOTHING - `, linkID, taskID, prID, now) + `, taskID, prID, now) if lErr != nil { apiError(res, 500, "INTERNAL_ERROR", lErr.Error()) return @@ -279,7 +269,6 @@ func (p *githubPlugin) createPullRequest(req *plugin.Request, res *plugin.Respon } now := nowStr() - prID := uuid.New().String() var mergedAtStr *string if ghPR.MergedAt != nil { @@ -287,26 +276,31 @@ func (p *githubPlugin) createPullRequest(req *plugin.Request, res *plugin.Respon mergedAtStr = &s } - _, err = p.db.Exec(` + upserted, err := p.db.Query(` INSERT INTO github_pull_requests - (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) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$13) + (project_id, repo_id, pr_number, github_pr_id, title, state, html_url, head_branch, base_branch, author, merged_at, created_at, updated_at) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$12) ON CONFLICT (repo_id, pr_number) DO UPDATE SET - title=$6, state=$7, html_url=$8, head_branch=$9, base_branch=$10, - author=$11, merged_at=$12, updated_at=$13 - `, prID, projectID, b.RepoID, ghPR.Number, ghPR.ID, ghPR.Title, state, + title=$5, state=$6, html_url=$7, head_branch=$8, base_branch=$9, + author=$10, merged_at=$11, updated_at=$12 + RETURNING id + `, projectID, b.RepoID, ghPR.Number, ghPR.ID, ghPR.Title, state, ghPR.HTMLURL, ghPR.Head.Ref, ghPR.Base.Ref, ghPR.User.Login, mergedAtStr, now) - if err != nil { - apiError(res, 500, "INTERNAL_ERROR", err.Error()) + if err != nil || len(upserted.Rows) == 0 { + if err != nil { + apiError(res, 500, "INTERNAL_ERROR", err.Error()) + } else { + apiError(res, 500, "INTERNAL_ERROR", "upsert returned no rows") + } return } + prID := newRowScanner(upserted.Columns, upserted.Rows[0]).str("id") - linkID := uuid.New().String() _, lErr := p.db.Exec(` - INSERT INTO github_task_pr_links (id, task_id, pull_request_id, created_at) - VALUES ($1,$2,$3,$4) + INSERT INTO github_task_pr_links (task_id, pull_request_id, created_at) + VALUES ($1,$2,$3) ON CONFLICT (task_id, pull_request_id) DO NOTHING - `, linkID, taskID, prID, now) + `, taskID, prID, now) if lErr != nil { p.log.Error("failed to link PR to task: " + lErr.Error()) } diff --git a/backend/webhook.go b/backend/webhook.go index 18cdc67..8a20e47 100644 --- a/backend/webhook.go +++ b/backend/webhook.go @@ -11,7 +11,6 @@ import ( "time" plugin "github.com/Paca-AI/plugin-sdk-go" - "github.com/google/uuid" ) // branchTaskRefRe matches a task-ID prefix in a branch name (e.g. "PROJ-42"). @@ -114,42 +113,25 @@ func (p *githubPlugin) handlePREvent(repoID, projectID string, payload []byte) e mergedAtStr = &s } - // Check if PR already cached. - existResult, err := p.db.Query( - `SELECT id, created_at FROM github_pull_requests WHERE repo_id = $1 AND pr_number = $2`, - repoID, gh.Number, - ) - if err != nil { - p.log.Error("github: failed to check existing PR: " + err.Error() + ", repo_id=" + repoID + ", pr_number=" + strconv.Itoa(gh.Number)) - return err - } - var prID string - var prCreatedAt string - if existResult != nil && len(existResult.Rows) > 0 { - eSc := newRowScanner(existResult.Columns, existResult.Rows[0]) - prID = eSc.str("id") - prCreatedAt = eSc.str("created_at") - p.log.Info("github: PR already cached, updating, pr_id=" + prID + ", pr_number=" + strconv.Itoa(gh.Number)) - } else { - prID = uuid.New().String() - prCreatedAt = now - p.log.Info("github: PR not cached, inserting, pr_id=" + prID + ", pr_number=" + strconv.Itoa(gh.Number)) - } - - // Upsert the PR cache. - _, err = p.db.Exec(` + // Upsert the PR cache; let PostgreSQL generate id on insert, RETURNING gives us the id. + upserted, err := p.db.Query(` INSERT INTO github_pull_requests - (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) - VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14) + (project_id, repo_id, pr_number, github_pr_id, title, state, html_url, head_branch, base_branch, author, merged_at, created_at, updated_at) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) ON CONFLICT (repo_id, pr_number) DO UPDATE SET - title=$6, state=$7, html_url=$8, head_branch=$9, base_branch=$10, - author=$11, merged_at=$12, updated_at=$14 - `, prID, projectID, repoID, gh.Number, gh.ID, gh.Title, state, - gh.HTMLURL, gh.Head.Ref, gh.Base.Ref, gh.User.Login, mergedAtStr, prCreatedAt, now) + title=$5, state=$6, html_url=$7, head_branch=$8, base_branch=$9, + author=$10, merged_at=$11, updated_at=$13 + RETURNING id + `, projectID, repoID, gh.Number, gh.ID, gh.Title, state, + gh.HTMLURL, gh.Head.Ref, gh.Base.Ref, gh.User.Login, mergedAtStr, now, now) if err != nil { p.log.Error("github: failed to upsert PR: " + err.Error() + ", repo_id=" + repoID + ", pr_number=" + strconv.Itoa(gh.Number)) return err } + var prID string + if len(upserted.Rows) > 0 { + prID = newRowScanner(upserted.Columns, upserted.Rows[0]).str("id") + } p.log.Info("github: PR saved successfully, pr_id=" + prID + ", pr_number=" + strconv.Itoa(gh.Number) + ", action=" + event.Action) @@ -161,12 +143,11 @@ func (p *githubPlugin) handlePREvent(repoID, projectID string, payload []byte) e ) if brResult != nil && len(brResult.Rows) > 0 { taskID := newRowScanner(brResult.Columns, brResult.Rows[0]).str("task_id") - linkID := uuid.New().String() _, _ = p.db.Exec(` - INSERT INTO github_task_pr_links (id, task_id, pull_request_id, created_at) - VALUES ($1,$2,$3,$4) + INSERT INTO github_task_pr_links (task_id, pull_request_id, created_at) + VALUES ($1,$2,$3) ON CONFLICT (task_id, pull_request_id) DO NOTHING - `, linkID, taskID, prID, now) + `, taskID, prID, now) plugin.EmitEvent("github.pr_linked", map[string]any{ "project_id": projectID, @@ -229,12 +210,11 @@ func (p *githubPlugin) handlePushEvent(repoID, projectID string, payload []byte) taskID := newRowScanner(taskResult.Columns, taskResult.Rows[0]).str("id") now := time.Now().UTC().Format(time.RFC3339Nano) - branchID := uuid.New().String() _, _ = p.db.Exec(` - INSERT INTO github_task_branches (id, task_id, repo_id, branch_name, created_at) - VALUES ($1,$2,$3,$4,$5) + INSERT INTO github_task_branches (task_id, repo_id, branch_name, created_at) + VALUES ($1,$2,$3,$4) ON CONFLICT (task_id, repo_id, branch_name) DO NOTHING - `, branchID, taskID, repoID, branchName, now) + `, taskID, repoID, branchName, now) plugin.EmitEvent("github.branch_linked", map[string]any{ "project_id": projectID,