feat: add head_branch to pull request diff status (#23076)
Adds the `head_branch` field (the source/feature branch name of a PR) to the diff status pipeline. Previously only `base_branch` (target branch) and the head commit SHA were captured from the GitHub API, but not the head branch name itself. ## Changes - **Migration 438**: Add `head_branch` nullable TEXT column to `chat_diff_statuses` - **gitprovider**: Parse `head.ref` from the GitHub API response (alongside `head.sha`) and add `HeadBranch` to `PRStatus` - **gitsync**: Wire `HeadBranch` through `refreshOne()` into the DB upsert params - **worker**: Map `HeadBranch` in `chatDiffStatusFromRow()` - **coderd**: Convert `HeadBranch` in `convertChatDiffStatus()` - **codersdk**: Expose as `head_branch` (`*string`, omitempty) in `ChatDiffStatus` API response - **Tests**: Updated `github_test.go` pull JSON fixtures and assertions
This commit is contained in:
@@ -2629,6 +2629,9 @@ func convertChatDiffStatus(chatID uuid.UUID, status *database.ChatDiffStatus) co
|
||||
if status.BaseBranch.Valid {
|
||||
result.BaseBranch = &status.BaseBranch.String
|
||||
}
|
||||
if status.HeadBranch.Valid {
|
||||
result.HeadBranch = &status.HeadBranch.String
|
||||
}
|
||||
if status.PrNumber.Valid {
|
||||
result.PRNumber = &status.PrNumber.Int32
|
||||
}
|
||||
|
||||
Generated
+2
-1
@@ -1207,7 +1207,8 @@ CREATE TABLE chat_diff_statuses (
|
||||
pr_number integer,
|
||||
commits integer,
|
||||
approved boolean,
|
||||
reviewer_count integer
|
||||
reviewer_count integer,
|
||||
head_branch text
|
||||
);
|
||||
|
||||
CREATE TABLE chat_files (
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE chat_diff_statuses DROP COLUMN head_branch;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE chat_diff_statuses ADD COLUMN head_branch TEXT;
|
||||
@@ -4053,6 +4053,7 @@ type ChatDiffStatus struct {
|
||||
Commits sql.NullInt32 `db:"commits" json:"commits"`
|
||||
Approved sql.NullBool `db:"approved" json:"approved"`
|
||||
ReviewerCount sql.NullInt32 `db:"reviewer_count" json:"reviewer_count"`
|
||||
HeadBranch sql.NullString `db:"head_branch" json:"head_branch"`
|
||||
}
|
||||
|
||||
type ChatFile struct {
|
||||
|
||||
@@ -3030,10 +3030,10 @@ WITH acquired AS (
|
||||
LIMIT
|
||||
$1::int
|
||||
)
|
||||
RETURNING chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count
|
||||
RETURNING chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count, head_branch
|
||||
)
|
||||
SELECT
|
||||
acquired.chat_id, acquired.url, acquired.pull_request_state, acquired.changes_requested, acquired.additions, acquired.deletions, acquired.changed_files, acquired.refreshed_at, acquired.stale_at, acquired.created_at, acquired.updated_at, acquired.git_branch, acquired.git_remote_origin, acquired.pull_request_title, acquired.pull_request_draft, acquired.author_login, acquired.author_avatar_url, acquired.base_branch, acquired.pr_number, acquired.commits, acquired.approved, acquired.reviewer_count,
|
||||
acquired.chat_id, acquired.url, acquired.pull_request_state, acquired.changes_requested, acquired.additions, acquired.deletions, acquired.changed_files, acquired.refreshed_at, acquired.stale_at, acquired.created_at, acquired.updated_at, acquired.git_branch, acquired.git_remote_origin, acquired.pull_request_title, acquired.pull_request_draft, acquired.author_login, acquired.author_avatar_url, acquired.base_branch, acquired.pr_number, acquired.commits, acquired.approved, acquired.reviewer_count, acquired.head_branch,
|
||||
c.owner_id
|
||||
FROM
|
||||
acquired
|
||||
@@ -3064,6 +3064,7 @@ type AcquireStaleChatDiffStatusesRow struct {
|
||||
Commits sql.NullInt32 `db:"commits" json:"commits"`
|
||||
Approved sql.NullBool `db:"approved" json:"approved"`
|
||||
ReviewerCount sql.NullInt32 `db:"reviewer_count" json:"reviewer_count"`
|
||||
HeadBranch sql.NullString `db:"head_branch" json:"head_branch"`
|
||||
OwnerID uuid.UUID `db:"owner_id" json:"owner_id"`
|
||||
}
|
||||
|
||||
@@ -3099,6 +3100,7 @@ func (q *sqlQuerier) AcquireStaleChatDiffStatuses(ctx context.Context, limitVal
|
||||
&i.Commits,
|
||||
&i.Approved,
|
||||
&i.ReviewerCount,
|
||||
&i.HeadBranch,
|
||||
&i.OwnerID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
@@ -3623,7 +3625,7 @@ func (q *sqlQuerier) GetChatCostSummary(ctx context.Context, arg GetChatCostSumm
|
||||
|
||||
const getChatDiffStatusByChatID = `-- name: GetChatDiffStatusByChatID :one
|
||||
SELECT
|
||||
chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count
|
||||
chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count, head_branch
|
||||
FROM
|
||||
chat_diff_statuses
|
||||
WHERE
|
||||
@@ -3656,13 +3658,14 @@ func (q *sqlQuerier) GetChatDiffStatusByChatID(ctx context.Context, chatID uuid.
|
||||
&i.Commits,
|
||||
&i.Approved,
|
||||
&i.ReviewerCount,
|
||||
&i.HeadBranch,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getChatDiffStatusesByChatIDs = `-- name: GetChatDiffStatusesByChatIDs :many
|
||||
SELECT
|
||||
chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count
|
||||
chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count, head_branch
|
||||
FROM
|
||||
chat_diff_statuses
|
||||
WHERE
|
||||
@@ -3701,6 +3704,7 @@ func (q *sqlQuerier) GetChatDiffStatusesByChatIDs(ctx context.Context, chatIds [
|
||||
&i.Commits,
|
||||
&i.Approved,
|
||||
&i.ReviewerCount,
|
||||
&i.HeadBranch,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -4586,6 +4590,7 @@ INSERT INTO chat_diff_statuses (
|
||||
author_login,
|
||||
author_avatar_url,
|
||||
base_branch,
|
||||
head_branch,
|
||||
pr_number,
|
||||
commits,
|
||||
approved,
|
||||
@@ -4605,12 +4610,13 @@ INSERT INTO chat_diff_statuses (
|
||||
$10::text,
|
||||
$11::text,
|
||||
$12::text,
|
||||
$13::integer,
|
||||
$13::text,
|
||||
$14::integer,
|
||||
$15::boolean,
|
||||
$16::integer,
|
||||
$17::timestamptz,
|
||||
$18::timestamptz
|
||||
$15::integer,
|
||||
$16::boolean,
|
||||
$17::integer,
|
||||
$18::timestamptz,
|
||||
$19::timestamptz
|
||||
)
|
||||
ON CONFLICT (chat_id) DO UPDATE
|
||||
SET
|
||||
@@ -4625,6 +4631,7 @@ SET
|
||||
author_login = EXCLUDED.author_login,
|
||||
author_avatar_url = EXCLUDED.author_avatar_url,
|
||||
base_branch = EXCLUDED.base_branch,
|
||||
head_branch = EXCLUDED.head_branch,
|
||||
pr_number = EXCLUDED.pr_number,
|
||||
commits = EXCLUDED.commits,
|
||||
approved = EXCLUDED.approved,
|
||||
@@ -4633,7 +4640,7 @@ SET
|
||||
stale_at = EXCLUDED.stale_at,
|
||||
updated_at = NOW()
|
||||
RETURNING
|
||||
chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count
|
||||
chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count, head_branch
|
||||
`
|
||||
|
||||
type UpsertChatDiffStatusParams struct {
|
||||
@@ -4649,6 +4656,7 @@ type UpsertChatDiffStatusParams struct {
|
||||
AuthorLogin sql.NullString `db:"author_login" json:"author_login"`
|
||||
AuthorAvatarUrl sql.NullString `db:"author_avatar_url" json:"author_avatar_url"`
|
||||
BaseBranch sql.NullString `db:"base_branch" json:"base_branch"`
|
||||
HeadBranch sql.NullString `db:"head_branch" json:"head_branch"`
|
||||
PrNumber sql.NullInt32 `db:"pr_number" json:"pr_number"`
|
||||
Commits sql.NullInt32 `db:"commits" json:"commits"`
|
||||
Approved sql.NullBool `db:"approved" json:"approved"`
|
||||
@@ -4671,6 +4679,7 @@ func (q *sqlQuerier) UpsertChatDiffStatus(ctx context.Context, arg UpsertChatDif
|
||||
arg.AuthorLogin,
|
||||
arg.AuthorAvatarUrl,
|
||||
arg.BaseBranch,
|
||||
arg.HeadBranch,
|
||||
arg.PrNumber,
|
||||
arg.Commits,
|
||||
arg.Approved,
|
||||
@@ -4702,6 +4711,7 @@ func (q *sqlQuerier) UpsertChatDiffStatus(ctx context.Context, arg UpsertChatDif
|
||||
&i.Commits,
|
||||
&i.Approved,
|
||||
&i.ReviewerCount,
|
||||
&i.HeadBranch,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@@ -4737,7 +4747,7 @@ SET
|
||||
stale_at = EXCLUDED.stale_at,
|
||||
updated_at = NOW()
|
||||
RETURNING
|
||||
chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count
|
||||
chat_id, url, pull_request_state, changes_requested, additions, deletions, changed_files, refreshed_at, stale_at, created_at, updated_at, git_branch, git_remote_origin, pull_request_title, pull_request_draft, author_login, author_avatar_url, base_branch, pr_number, commits, approved, reviewer_count, head_branch
|
||||
`
|
||||
|
||||
type UpsertChatDiffStatusReferenceParams struct {
|
||||
@@ -4780,6 +4790,7 @@ func (q *sqlQuerier) UpsertChatDiffStatusReference(ctx context.Context, arg Upse
|
||||
&i.Commits,
|
||||
&i.Approved,
|
||||
&i.ReviewerCount,
|
||||
&i.HeadBranch,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
@@ -367,6 +367,7 @@ INSERT INTO chat_diff_statuses (
|
||||
author_login,
|
||||
author_avatar_url,
|
||||
base_branch,
|
||||
head_branch,
|
||||
pr_number,
|
||||
commits,
|
||||
approved,
|
||||
@@ -386,6 +387,7 @@ INSERT INTO chat_diff_statuses (
|
||||
sqlc.narg('author_login')::text,
|
||||
sqlc.narg('author_avatar_url')::text,
|
||||
sqlc.narg('base_branch')::text,
|
||||
sqlc.narg('head_branch')::text,
|
||||
sqlc.narg('pr_number')::integer,
|
||||
sqlc.narg('commits')::integer,
|
||||
sqlc.narg('approved')::boolean,
|
||||
@@ -406,6 +408,7 @@ SET
|
||||
author_login = EXCLUDED.author_login,
|
||||
author_avatar_url = EXCLUDED.author_avatar_url,
|
||||
base_branch = EXCLUDED.base_branch,
|
||||
head_branch = EXCLUDED.head_branch,
|
||||
pr_number = EXCLUDED.pr_number,
|
||||
commits = EXCLUDED.commits,
|
||||
approved = EXCLUDED.approved,
|
||||
|
||||
@@ -269,6 +269,7 @@ func (g *githubProvider) FetchPullRequestStatus(
|
||||
Commits int32 `json:"commits"`
|
||||
Head struct {
|
||||
SHA string `json:"sha"`
|
||||
Ref string `json:"ref"`
|
||||
} `json:"head"`
|
||||
User struct {
|
||||
Login string `json:"login"`
|
||||
@@ -310,10 +311,11 @@ func (g *githubProvider) FetchPullRequestStatus(
|
||||
reviewInfo := summarizeReviews(reviews)
|
||||
|
||||
return &PRStatus{
|
||||
Title: pull.Title,
|
||||
State: state,
|
||||
Draft: pull.Draft,
|
||||
HeadSHA: pull.Head.SHA,
|
||||
Title: pull.Title,
|
||||
State: state,
|
||||
Draft: pull.Draft,
|
||||
HeadSHA: pull.Head.SHA,
|
||||
HeadBranch: pull.Head.Ref,
|
||||
DiffStats: DiffStats{
|
||||
Additions: pull.Additions,
|
||||
Deletions: pull.Deletions,
|
||||
|
||||
@@ -657,7 +657,7 @@ func TestFetchPullRequestStatus(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "OpenPR/NoReviews",
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123"}}`,
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123","ref":"feature-branch"}}`,
|
||||
reviews: []review{},
|
||||
expectedState: gitprovider.PRStateOpen,
|
||||
expectedDraft: false,
|
||||
@@ -665,14 +665,14 @@ func TestFetchPullRequestStatus(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "OpenPR/SingleChangesRequested",
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123"}}`,
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123","ref":"feature-branch"}}`,
|
||||
reviews: []review{makeReview(1, "CHANGES_REQUESTED", "alice")},
|
||||
expectedState: gitprovider.PRStateOpen,
|
||||
changesRequested: true,
|
||||
},
|
||||
{
|
||||
name: "OpenPR/ChangesRequestedThenApproved",
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123"}}`,
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123","ref":"feature-branch"}}`,
|
||||
reviews: []review{
|
||||
makeReview(1, "CHANGES_REQUESTED", "alice"),
|
||||
makeReview(2, "APPROVED", "alice"),
|
||||
@@ -682,7 +682,7 @@ func TestFetchPullRequestStatus(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "OpenPR/ChangesRequestedThenDismissed",
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123"}}`,
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123","ref":"feature-branch"}}`,
|
||||
reviews: []review{
|
||||
makeReview(1, "CHANGES_REQUESTED", "alice"),
|
||||
makeReview(2, "DISMISSED", "alice"),
|
||||
@@ -692,7 +692,7 @@ func TestFetchPullRequestStatus(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "OpenPR/MultipleReviewersMixed",
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123"}}`,
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123","ref":"feature-branch"}}`,
|
||||
reviews: []review{
|
||||
makeReview(1, "APPROVED", "alice"),
|
||||
makeReview(2, "CHANGES_REQUESTED", "bob"),
|
||||
@@ -702,7 +702,7 @@ func TestFetchPullRequestStatus(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "OpenPR/CommentedDoesNotAffect",
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123"}}`,
|
||||
pullJSON: `{"state":"open","merged":false,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123","ref":"feature-branch"}}`,
|
||||
reviews: []review{
|
||||
makeReview(1, "COMMENTED", "alice"),
|
||||
},
|
||||
@@ -711,14 +711,14 @@ func TestFetchPullRequestStatus(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "MergedPR",
|
||||
pullJSON: `{"state":"closed","merged":true,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123"}}`,
|
||||
pullJSON: `{"state":"closed","merged":true,"draft":false,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123","ref":"feature-branch"}}`,
|
||||
reviews: []review{},
|
||||
expectedState: gitprovider.PRStateMerged,
|
||||
changesRequested: false,
|
||||
},
|
||||
{
|
||||
name: "DraftPR",
|
||||
pullJSON: `{"state":"open","merged":false,"draft":true,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123"}}`,
|
||||
pullJSON: `{"state":"open","merged":false,"draft":true,"additions":10,"deletions":5,"changed_files":3,"head":{"sha":"abc123","ref":"feature-branch"}}`,
|
||||
reviews: []review{},
|
||||
expectedState: gitprovider.PRStateOpen,
|
||||
expectedDraft: true,
|
||||
@@ -762,6 +762,7 @@ func TestFetchPullRequestStatus(t *testing.T) {
|
||||
assert.Equal(t, tc.expectedDraft, status.Draft)
|
||||
assert.Equal(t, tc.changesRequested, status.ChangesRequested)
|
||||
assert.Equal(t, "abc123", status.HeadSHA)
|
||||
assert.Equal(t, "feature-branch", status.HeadBranch)
|
||||
assert.Equal(t, int32(10), status.DiffStats.Additions)
|
||||
assert.Equal(t, int32(5), status.DiffStats.Deletions)
|
||||
assert.Equal(t, int32(3), status.DiffStats.ChangedFiles)
|
||||
|
||||
@@ -74,6 +74,8 @@ type PRStatus struct {
|
||||
Draft bool
|
||||
// HeadSHA is the SHA of the head commit.
|
||||
HeadSHA string
|
||||
// HeadBranch is the name of the branch containing the PR changes.
|
||||
HeadBranch string
|
||||
// DiffStats summarizes additions/deletions/files changed.
|
||||
DiffStats DiffStats
|
||||
// ChangesRequested is a convenience boolean: true if any
|
||||
|
||||
@@ -319,6 +319,7 @@ func (r *Refresher) refreshOne(
|
||||
AuthorLogin: sql.NullString{String: status.AuthorLogin, Valid: status.AuthorLogin != ""},
|
||||
AuthorAvatarUrl: sql.NullString{String: status.AuthorAvatarURL, Valid: status.AuthorAvatarURL != ""},
|
||||
BaseBranch: sql.NullString{String: status.BaseBranch, Valid: status.BaseBranch != ""},
|
||||
HeadBranch: sql.NullString{String: status.HeadBranch, Valid: status.HeadBranch != ""},
|
||||
PrNumber: sql.NullInt32{Int32: int32(status.PRNumber), Valid: true},
|
||||
Commits: sql.NullInt32{Int32: status.Commits, Valid: true},
|
||||
Approved: sql.NullBool{Bool: status.Approved, Valid: true},
|
||||
|
||||
@@ -143,6 +143,7 @@ func chatDiffStatusFromRow(row database.AcquireStaleChatDiffStatusesRow) databas
|
||||
AuthorLogin: row.AuthorLogin,
|
||||
AuthorAvatarUrl: row.AuthorAvatarUrl,
|
||||
BaseBranch: row.BaseBranch,
|
||||
HeadBranch: row.HeadBranch,
|
||||
PrNumber: row.PrNumber,
|
||||
Commits: row.Commits,
|
||||
Approved: row.Approved,
|
||||
|
||||
@@ -633,6 +633,7 @@ type ChatDiffStatus struct {
|
||||
AuthorLogin *string `json:"author_login,omitempty"`
|
||||
AuthorAvatarURL *string `json:"author_avatar_url,omitempty"`
|
||||
BaseBranch *string `json:"base_branch,omitempty"`
|
||||
HeadBranch *string `json:"head_branch,omitempty"`
|
||||
PRNumber *int32 `json:"pr_number,omitempty"`
|
||||
Commits *int32 `json:"commits,omitempty"`
|
||||
Approved *bool `json:"approved,omitempty"`
|
||||
|
||||
Generated
+1
@@ -1201,6 +1201,7 @@ export interface ChatDiffStatus {
|
||||
readonly author_login?: string;
|
||||
readonly author_avatar_url?: string;
|
||||
readonly base_branch?: string;
|
||||
readonly head_branch?: string;
|
||||
readonly pr_number?: number;
|
||||
readonly commits?: number;
|
||||
readonly approved?: boolean;
|
||||
|
||||
Reference in New Issue
Block a user