Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions pkg/github/issues.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,15 @@ func getCloseStateReason(stateReason string) IssueClosedStateReason {

// IssueFragment represents a fragment of an issue node in the GraphQL API.
type IssueFragment struct {
Number githubv4.Int
Title githubv4.String
Body githubv4.String
State githubv4.String
DatabaseID int64
Number githubv4.Int
Title githubv4.String
Body githubv4.String
State githubv4.String
DatabaseID int64
AuthorAssociation githubv4.String

Author struct {
Login githubv4.String
Association githubv4.String
Login githubv4.String
}
CreatedAt githubv4.DateTime
UpdatedAt githubv4.DateTime
Expand Down
64 changes: 38 additions & 26 deletions pkg/github/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1130,14 +1130,15 @@ func Test_ListIssues(t *testing.T) {
// Mock issues data
mockIssuesAll := []map[string]any{
{
"number": 123,
"title": "First Issue",
"body": "This is the first test issue",
"state": "OPEN",
"databaseId": 1001,
"createdAt": "2023-01-01T00:00:00Z",
"updatedAt": "2023-01-01T00:00:00Z",
"author": map[string]any{"login": "user1"},
"number": 123,
"title": "First Issue",
"body": "This is the first test issue",
"state": "OPEN",
"databaseId": 1001,
"authorAssociation": "MEMBER",
"createdAt": "2023-01-01T00:00:00Z",
"updatedAt": "2023-01-01T00:00:00Z",
"author": map[string]any{"login": "user1"},
"labels": map[string]any{
"nodes": []map[string]any{
{"name": "bug", "id": "label1", "description": "Bug label"},
Expand All @@ -1148,14 +1149,15 @@ func Test_ListIssues(t *testing.T) {
},
},
{
"number": 456,
"title": "Second Issue",
"body": "This is the second test issue",
"state": "OPEN",
"databaseId": 1002,
"createdAt": "2023-02-01T00:00:00Z",
"updatedAt": "2023-02-01T00:00:00Z",
"author": map[string]any{"login": "user2"},
"number": 456,
"title": "Second Issue",
"body": "This is the second test issue",
"state": "OPEN",
"databaseId": 1002,
"authorAssociation": "CONTRIBUTOR",
"createdAt": "2023-02-01T00:00:00Z",
"updatedAt": "2023-02-01T00:00:00Z",
"author": map[string]any{"login": "user2"},
"labels": map[string]any{
"nodes": []map[string]any{
{"name": "enhancement", "id": "label2", "description": "Enhancement label"},
Expand All @@ -1170,14 +1172,15 @@ func Test_ListIssues(t *testing.T) {
mockIssuesOpen := []map[string]any{mockIssuesAll[0], mockIssuesAll[1]}
mockIssuesClosed := []map[string]any{
{
"number": 789,
"title": "Closed Issue",
"body": "This is a closed issue",
"state": "CLOSED",
"databaseId": 1003,
"createdAt": "2023-03-01T00:00:00Z",
"updatedAt": "2023-03-01T00:00:00Z",
"author": map[string]any{"login": "user3"},
"number": 789,
"title": "Closed Issue",
"body": "This is a closed issue",
"state": "CLOSED",
"databaseId": 1003,
"authorAssociation": "NONE",
"createdAt": "2023-03-01T00:00:00Z",
"updatedAt": "2023-03-01T00:00:00Z",
"author": map[string]any{"login": "user3"},
"labels": map[string]any{
"nodes": []map[string]any{},
},
Expand Down Expand Up @@ -1355,8 +1358,8 @@ func Test_ListIssues(t *testing.T) {
}

// Define the actual query strings that match the implementation
qBasicNoLabels := "query($after:String$direction:OrderDirection!$first:Int!$orderBy:IssueOrderField!$owner:String!$repo:String!$states:[IssueState!]!){repository(owner: $owner, name: $repo){issues(first: $first, after: $after, states: $states, orderBy: {field: $orderBy, direction: $direction}){nodes{number,title,body,state,databaseId,author{login},createdAt,updatedAt,labels(first: 100){nodes{name,id,description}},comments{totalCount}},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount}}}"
qWithLabels := "query($after:String$direction:OrderDirection!$first:Int!$labels:[String!]!$orderBy:IssueOrderField!$owner:String!$repo:String!$states:[IssueState!]!){repository(owner: $owner, name: $repo){issues(first: $first, after: $after, labels: $labels, states: $states, orderBy: {field: $orderBy, direction: $direction}){nodes{number,title,body,state,databaseId,author{login},createdAt,updatedAt,labels(first: 100){nodes{name,id,description}},comments{totalCount}},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount}}}"
qBasicNoLabels := "query($after:String$direction:OrderDirection!$first:Int!$orderBy:IssueOrderField!$owner:String!$repo:String!$states:[IssueState!]!){repository(owner: $owner, name: $repo){issues(first: $first, after: $after, states: $states, orderBy: {field: $orderBy, direction: $direction}){nodes{number,title,body,state,databaseId,authorAssociation,author{login},createdAt,updatedAt,labels(first: 100){nodes{name,id,description}},comments{totalCount}},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount}}}"
qWithLabels := "query($after:String$direction:OrderDirection!$first:Int!$labels:[String!]!$orderBy:IssueOrderField!$owner:String!$repo:String!$states:[IssueState!]!){repository(owner: $owner, name: $repo){issues(first: $first, after: $after, labels: $labels, states: $states, orderBy: {field: $orderBy, direction: $direction}){nodes{number,title,body,state,databaseId,authorAssociation,author{login},createdAt,updatedAt,labels(first: 100){nodes{name,id,description}},comments{totalCount}},pageInfo{hasNextPage,hasPreviousPage,startCursor,endCursor},totalCount}}}"

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
Expand Down Expand Up @@ -1423,6 +1426,15 @@ func Test_ListIssues(t *testing.T) {
assert.NotEmpty(t, issue.User.Login, "Issue user should have login")
assert.Empty(t, issue.HTMLURL, "html_url should be empty (not populated by GraphQL fragment)")

switch issue.Number {
case 123:
assert.Equal(t, "MEMBER", issue.AuthorAssociation)
case 456:
assert.Equal(t, "CONTRIBUTOR", issue.AuthorAssociation)
case 789:
assert.Equal(t, "NONE", issue.AuthorAssociation)
}

// Labels should be flattened to name strings
for _, label := range issue.Labels {
assert.NotEmpty(t, label, "Label should be a non-empty string")
Expand Down
10 changes: 6 additions & 4 deletions pkg/github/minimal_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ type MinimalPullRequest struct {
MergeableState string `json:"mergeable_state,omitempty"`
HTMLURL string `json:"html_url"`
User *MinimalUser `json:"user,omitempty"`
AuthorAssociation string `json:"author_association,omitempty"`
Labels []string `json:"labels,omitempty"`
Assignees []string `json:"assignees,omitempty"`
RequestedReviewers []string `json:"requested_reviewers,omitempty"`
Expand Down Expand Up @@ -397,7 +398,7 @@ func fragmentToMinimalIssue(fragment IssueFragment) MinimalIssue {
User: &MinimalUser{
Login: string(fragment.Author.Login),
},
AuthorAssociation: string(fragment.Author.Association),
AuthorAssociation: string(fragment.AuthorAssociation),
}

for _, label := range fragment.Labels.Nodes {
Expand Down Expand Up @@ -503,9 +504,10 @@ func convertToMinimalPullRequest(pr *github.PullRequest) MinimalPullRequest {
Draft: pr.GetDraft(),
Merged: pr.GetMerged(),
MergeableState: pr.GetMergeableState(),
HTMLURL: pr.GetHTMLURL(),
User: convertToMinimalUser(pr.GetUser()),
Additions: pr.GetAdditions(),
HTMLURL: pr.GetHTMLURL(),
User: convertToMinimalUser(pr.GetUser()),
AuthorAssociation: pr.GetAuthorAssociation(),
Additions: pr.GetAdditions(),
Deletions: pr.GetDeletions(),
ChangedFiles: pr.GetChangedFiles(),
Commits: pr.GetCommits(),
Expand Down
22 changes: 14 additions & 8 deletions pkg/github/pullrequests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func Test_GetPullRequest(t *testing.T) {
User: &github.User{
Login: github.Ptr("testuser"),
},
AuthorAssociation: github.Ptr("MEMBER"),
}

tests := []struct {
Expand Down Expand Up @@ -135,6 +136,7 @@ func Test_GetPullRequest(t *testing.T) {
assert.Equal(t, tc.expectedPR.GetTitle(), returnedPR.Title)
assert.Equal(t, tc.expectedPR.GetState(), returnedPR.State)
assert.Equal(t, tc.expectedPR.GetHTMLURL(), returnedPR.HTMLURL)
assert.Equal(t, tc.expectedPR.GetAuthorAssociation(), returnedPR.AuthorAssociation)
})
}
}
Expand Down Expand Up @@ -575,16 +577,18 @@ func Test_ListPullRequests(t *testing.T) {
// Setup mock PRs for success case
mockPRs := []*github.PullRequest{
{
Number: github.Ptr(42),
Title: github.Ptr("First PR"),
State: github.Ptr("open"),
HTMLURL: github.Ptr("https://github.com/owner/repo/pull/42"),
Number: github.Ptr(42),
Title: github.Ptr("First PR"),
State: github.Ptr("open"),
HTMLURL: github.Ptr("https://github.com/owner/repo/pull/42"),
AuthorAssociation: github.Ptr("OWNER"),
},
{
Number: github.Ptr(43),
Title: github.Ptr("Second PR"),
State: github.Ptr("closed"),
HTMLURL: github.Ptr("https://github.com/owner/repo/pull/43"),
Number: github.Ptr(43),
Title: github.Ptr("Second PR"),
State: github.Ptr("closed"),
HTMLURL: github.Ptr("https://github.com/owner/repo/pull/43"),
AuthorAssociation: github.Ptr("CONTRIBUTOR"),
},
}

Expand Down Expand Up @@ -678,9 +682,11 @@ func Test_ListPullRequests(t *testing.T) {
assert.Equal(t, *tc.expectedPRs[0].Number, returnedPRs[0].Number)
assert.Equal(t, *tc.expectedPRs[0].Title, returnedPRs[0].Title)
assert.Equal(t, *tc.expectedPRs[0].State, returnedPRs[0].State)
assert.Equal(t, tc.expectedPRs[0].GetAuthorAssociation(), returnedPRs[0].AuthorAssociation)
assert.Equal(t, *tc.expectedPRs[1].Number, returnedPRs[1].Number)
assert.Equal(t, *tc.expectedPRs[1].Title, returnedPRs[1].Title)
assert.Equal(t, *tc.expectedPRs[1].State, returnedPRs[1].State)
assert.Equal(t, tc.expectedPRs[1].GetAuthorAssociation(), returnedPRs[1].AuthorAssociation)
})
}
}
Expand Down