Commit 354fa99
Changed files (39)
badges
most-reactions
my-badges-contributor
old-issue
pr-collaboration
the-ultimate-question
this-is-fine
src
collect
badges/most-reactions/most-reactions.ts
@@ -34,10 +34,10 @@ export default define({
}
for (const discussion of data.discussionComments) {
- if (discussion.reactions.totalCount > 0) {
+ if (discussion.reactions.totalCount > 0 && discussion.discussion) {
reactions[discussion.discussion.repository.nameWithOwner] = {
count: discussion.reactions.totalCount,
- repository: discussion.discussion.repository.nameWithOwner,
+ repository: discussion.discussion?.repository.nameWithOwner,
}
}
}
badges/my-badges-contributor/my-badges-contributor.ts
@@ -1,10 +1,10 @@
-import { define, Pull } from '#src'
+import { define, PullRequest } from '#src'
export default define({
url: import.meta.url,
badges: ['my-badges-contributor'] as const,
present(data, grant) {
- const pulls: Pull[] = []
+ const pulls: PullRequest[] = []
for (const pull of data.pulls) {
if (
pull.repository.name === 'my-badges' &&
badges/old-issue/old-issue.ts
@@ -21,7 +21,7 @@ export default define({
for (const issue of data.issues.sort(age)) {
if (!issue.closed) continue
const createdAt = new Date(issue.createdAt)
- const closedAt = new Date(issue.closedAt)
+ const closedAt = new Date(issue.closedAt!)
let years = Math.floor(
(closedAt.getTime() - createdAt.getTime()) / 1000 / 60 / 60 / 24 / 365,
)
@@ -47,5 +47,5 @@ export default define({
})
function age(a: Issue, b: Issue) {
- return new Date(a.closedAt).getTime() - new Date(b.closedAt).getTime()
+ return new Date(a.closedAt!).getTime() - new Date(b.closedAt!).getTime()
}
badges/pr-collaboration/pr-collaboration.ts
@@ -1,4 +1,4 @@
-import { define, Pull } from '#src'
+import { define, PullRequest } from '#src'
export default define({
url: import.meta.url,
@@ -56,6 +56,6 @@ export default define({
},
})
-function byParticipantsCount(a: Pull, b: Pull) {
+function byParticipantsCount(a: PullRequest, b: PullRequest) {
return a.participants.totalCount - b.participants.totalCount
}
badges/the-ultimate-question/the-ultimate-question.ts
@@ -1,10 +1,10 @@
-import { define, Issue, Pull } from '#src'
+import { define, Issue, PullRequest } from '#src'
export default define({
url: import.meta.url,
badges: ['the-ultimate-question'] as const,
present(data, grant) {
- const list: (Issue | Pull)[] = []
+ const list: (Issue | PullRequest)[] = []
for (const issue of data.issues) {
if (issue.number == 42) list.push(issue)
@@ -22,6 +22,6 @@ export default define({
},
})
-function link(x: Issue | Pull): string {
+function link(x: Issue | PullRequest): string {
return `<a href="https://github.com/${x.repository.owner.login}/${x.repository.name}/issues/${x.number}">#${x.number}</a>`
}
badges/this-is-fine/this-is-fine.ts
@@ -1,27 +1,27 @@
-import { define, Pull } from '#src'
+import { define, PullRequest } from '#src'
export default define({
url: import.meta.url,
badges: ['this-is-fine'] as const,
present(data, grant) {
- const pulls: Pull[] = []
+ const pulls: PullRequest[] = []
for (const pull of data.pulls) {
if (!pull.merged) continue
if (pull.mergedBy?.login != data.user.login) continue
- const commit = pull.lastCommit.nodes[0]?.commit
+ const commit = pull.lastCommit.nodes?.[0]?.commit
if (!commit) continue
- const checkRuns = commit.checkSuites.nodes.flatMap(
- (x) => x.lastCheckRun.nodes,
+ const checkRuns = commit.checkSuites?.nodes?.flatMap(
+ (x) => x.lastCheckRun?.nodes,
)
- if (checkRuns.length == 0) continue
+ if (!checkRuns || checkRuns?.length == 0) continue
const successCount = checkRuns.filter(
- (x) => x.conclusion == 'SUCCESS',
+ (x) => x?.conclusion == 'SUCCESS',
).length
const failureCount = checkRuns.filter(
- (x) => x.conclusion == 'FAILURE',
+ (x) => x?.conclusion == 'FAILURE',
).length
if (successCount <= failureCount) {
src/collect/comments.graphql
@@ -0,0 +1,99 @@
+fragment DiscussionComment on DiscussionComment {
+ url
+ author {
+ login
+ }
+ discussion {
+ number
+ repository {
+ nameWithOwner
+ }
+ author {
+ login
+ }
+ }
+ body
+ createdAt
+ updatedAt
+ editor {
+ login
+ }
+ ...Reactions
+}
+
+fragment IssueComment on IssueComment {
+ url
+ author {
+ login
+ }
+ repository {
+ nameWithOwner
+ }
+ issue {
+ number
+ author {
+ login
+ }
+ }
+ body
+ createdAt
+ updatedAt
+ editor {
+ login
+ }
+ ...Reactions
+}
+
+fragment Reactions on Reactable {
+ reactions(first: 100) {
+ totalCount
+ nodes {
+ content
+ user {
+ login
+ }
+ }
+ }
+}
+
+query DiscussionCommentsQuery($login: String!, $num: Int = 100, $cursor: String) {
+ user(login: $login) {
+ repositoryDiscussionComments(first: $num, after: $cursor) {
+ totalCount
+ nodes {
+ ...DiscussionComment
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}
+
+query IssueCommentsQuery($login: String!, $num: Int = 100, $cursor: String) {
+ user(login: $login) {
+ issueComments(first: $num, after: $cursor) {
+ totalCount
+ nodes {
+ ...IssueComment
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}
src/collect/comments.graphql.ts
@@ -0,0 +1,210 @@
+// DO NOT EDIT. This file was generated by megaera.
+
+const DiscussionComment = `#graphql
+fragment DiscussionComment on DiscussionComment {
+ url
+ author {
+ login
+ }
+ discussion {
+ number
+ repository {
+ nameWithOwner
+ }
+ author {
+ login
+ }
+ }
+ body
+ createdAt
+ updatedAt
+ editor {
+ login
+ }
+ ...Reactions
+}`
+
+export type DiscussionComment = {
+ url: string
+ author: {
+ login: string
+ } | null
+ discussion: {
+ number: number
+ repository: {
+ nameWithOwner: string
+ }
+ author: {
+ login: string
+ } | null
+ } | null
+ body: string
+ createdAt: string
+ updatedAt: string
+ editor: {
+ login: string
+ } | null
+} & Reactions
+
+
+const IssueComment = `#graphql
+fragment IssueComment on IssueComment {
+ url
+ author {
+ login
+ }
+ repository {
+ nameWithOwner
+ }
+ issue {
+ number
+ author {
+ login
+ }
+ }
+ body
+ createdAt
+ updatedAt
+ editor {
+ login
+ }
+ ...Reactions
+}`
+
+export type IssueComment = {
+ url: string
+ author: {
+ login: string
+ } | null
+ repository: {
+ nameWithOwner: string
+ }
+ issue: {
+ number: number
+ author: {
+ login: string
+ } | null
+ }
+ body: string
+ createdAt: string
+ updatedAt: string
+ editor: {
+ login: string
+ } | null
+} & Reactions
+
+
+const Reactions = `#graphql
+fragment Reactions on Reactable {
+ reactions(first: 100) {
+ totalCount
+ nodes {
+ content
+ user {
+ login
+ }
+ }
+ }
+}`
+
+export type Reactions = {
+ reactions: {
+ totalCount: number
+ nodes: Array<{
+ content: 'CONFUSED' | 'EYES' | 'HEART' | 'HOORAY' | 'LAUGH' | 'ROCKET' | 'THUMBS_DOWN' | 'THUMBS_UP'
+ user: {
+ login: string
+ } | null
+ }> | null
+ }
+}
+
+
+export const DiscussionCommentsQuery = `#graphql
+${Reactions}
+${IssueComment}
+${DiscussionComment}
+query DiscussionCommentsQuery($login: String!, $num: Int = 100, $cursor: String) {
+ user(login: $login) {
+ repositoryDiscussionComments(first: $num, after: $cursor) {
+ totalCount
+ nodes {
+ ...DiscussionComment
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}` as string & DiscussionCommentsQuery
+
+export type DiscussionCommentsQuery = (vars: { login: string, num?: number | null, cursor?: string | null }) => {
+ user: {
+ repositoryDiscussionComments: {
+ totalCount: number
+ nodes: Array<{} & DiscussionComment> | null
+ pageInfo: {
+ hasNextPage: boolean
+ endCursor: string | null
+ }
+ }
+ } | null
+ rateLimit: {
+ limit: number
+ cost: number
+ remaining: number
+ resetAt: string
+ } | null
+}
+
+
+export const IssueCommentsQuery = `#graphql
+${Reactions}
+${IssueComment}
+${DiscussionComment}
+query IssueCommentsQuery($login: String!, $num: Int = 100, $cursor: String) {
+ user(login: $login) {
+ issueComments(first: $num, after: $cursor) {
+ totalCount
+ nodes {
+ ...IssueComment
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}` as string & IssueCommentsQuery
+
+export type IssueCommentsQuery = (vars: { login: string, num?: number | null, cursor?: string | null }) => {
+ user: {
+ issueComments: {
+ totalCount: number
+ nodes: Array<{} & IssueComment> | null
+ pageInfo: {
+ hasNextPage: boolean
+ endCursor: string | null
+ }
+ }
+ } | null
+ rateLimit: {
+ limit: number
+ cost: number
+ remaining: number
+ resetAt: string
+ } | null
+}
src/collect/commits.graphql
@@ -0,0 +1,58 @@
+fragment Commit on Commit {
+ sha: oid
+ committedDate
+ message
+ messageBody
+ additions
+ deletions
+ author {
+ user {
+ login
+ }
+ }
+ committer {
+ user {
+ login
+ }
+ }
+ repository {
+ owner {
+ login
+ }
+ name
+ }
+}
+
+query CommitsQuery(
+ $owner: String!
+ $name: String!
+ $author: ID!
+ $num: Int = 100
+ $cursor: String
+) {
+ repository(owner: $owner, name: $name) {
+ defaultBranchRef {
+ target {
+ ... on Commit {
+ history(first: $num, after: $cursor, author: { id: $author }) {
+ totalCount
+ nodes {
+ ...Commit
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}
+
src/collect/commits.graphql.ts
@@ -0,0 +1,105 @@
+// DO NOT EDIT. This file was generated by megaera.
+
+const Commit = `#graphql
+fragment Commit on Commit {
+ sha: oid
+ committedDate
+ message
+ messageBody
+ additions
+ deletions
+ author {
+ user {
+ login
+ }
+ }
+ committer {
+ user {
+ login
+ }
+ }
+ repository {
+ owner {
+ login
+ }
+ name
+ }
+}`
+
+export type Commit = {
+ sha: string
+ committedDate: string
+ message: string
+ messageBody: string
+ additions: number
+ deletions: number
+ author: {
+ user: {
+ login: string
+ } | null
+ } | null
+ committer: {
+ user: {
+ login: string
+ } | null
+ } | null
+ repository: {
+ owner: {
+ login: string
+ }
+ name: string
+ }
+}
+
+
+export const CommitsQuery = `#graphql
+${Commit}
+query CommitsQuery($owner: String!, $name: String!, $author: ID!, $num: Int = 100, $cursor: String) {
+ repository(owner: $owner, name: $name) {
+ defaultBranchRef {
+ target {
+ ... on Commit {
+ history(first: $num, after: $cursor, author: {id: $author}) {
+ totalCount
+ nodes {
+ ...Commit
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}` as string & CommitsQuery
+
+export type CommitsQuery = (vars: { owner: string, name: string, author: string, num?: number | null, cursor?: string | null }) => {
+ repository: {
+ defaultBranchRef: {
+ target: {} & {
+ history: {
+ totalCount: number
+ nodes: Array<{} & Commit> | null
+ pageInfo: {
+ hasNextPage: boolean
+ endCursor: string | null
+ }
+ }
+ } | null | null
+ } | null
+ } | null
+ rateLimit: {
+ limit: number
+ cost: number
+ remaining: number
+ resetAt: string
+ } | null
+}
src/collect/commits.ts
@@ -1,101 +0,0 @@
-export const commitsQuery = `#graphql
-query CommitsQuery(
- $owner: String!
- $name: String!
- $author: ID!
- $num: Int = 100
- $cursor: String
-) {
- repository(owner: $owner, name: $name) {
- defaultBranchRef {
- target {
- ... on Commit {
- history(first: $num, after: $cursor, author: { id: $author }) {
- totalCount
- nodes {
- sha: oid
- committedDate
- message
- messageBody
- additions
- deletions
- author {
- user {
- login
- }
- }
- committer {
- user {
- login
- }
- }
- repository {
- owner {
- login
- }
- name
- }
- }
- pageInfo {
- hasNextPage
- endCursor
- }
- }
- }
- }
- }
- }
- rateLimit {
- limit
- cost
- remaining
- resetAt
- }
-}
-`
-
-export type CommitsQuery = {
- repository: {
- defaultBranchRef: {
- target: {
- history: {
- totalCount: number
- nodes: Array<{
- sha: string
- committedDate: string
- message: string
- messageBody: string
- additions: number
- deletions: number
- author: {
- user: {
- login: string
- }
- }
- committer: {
- user: {
- login: string
- }
- }
- repository: {
- owner: {
- login: string
- }
- name: string
- }
- }>
- pageInfo: {
- hasNextPage: boolean
- endCursor: string
- }
- }
- }
- }
- }
- rateLimit: {
- limit: number
- cost: number
- remaining: number
- resetAt: string
- }
-}
src/collect/discussion-comments.ts
@@ -1,91 +0,0 @@
-import { Reactions } from './types.js'
-
-export const discussionCommentsQuery = `#graphql
-query DiscussionCommentsQuery($login: String!, $num: Int = 100, $cursor: String) {
- user(login: $login) {
- repositoryDiscussionComments(first: $num, after: $cursor) {
- totalCount
- nodes {
- url
- author {
- login
- }
- discussion {
- number
- repository {
- nameWithOwner
- }
- author {
- login
- }
- }
- body
- createdAt
- updatedAt
- editor {
- login
- }
- reactions(first: 100) {
- totalCount
- nodes {
- content
- user {
- login
- }
- }
- }
- }
- pageInfo {
- hasNextPage
- endCursor
- }
- }
- }
- rateLimit {
- limit
- cost
- remaining
- resetAt
- }
-}
-`
-
-export type DiscussionCommentsQuery = {
- user: {
- repositoryDiscussionComments: {
- totalCount: number
- nodes: Array<{
- url: string
- author: {
- login: string
- }
- discussion: {
- number: number
- repository: {
- nameWithOwner: string
- }
- author: {
- login: string
- }
- }
- body: string
- createdAt: string
- updatedAt: string
- editor: {
- login: string
- } | null
- reactions: Reactions
- }>
- pageInfo: {
- hasNextPage: boolean
- endCursor: string
- }
- }
- }
- rateLimit: {
- limit: number
- cost: number
- remaining: number
- resetAt: string
- }
-}
src/collect/index.ts
@@ -0,0 +1,22 @@
+import { Endpoints } from '@octokit/types'
+import { User } from './user.graphql.js'
+import { PullRequest } from './pulls.graphql.js'
+import { Issue } from './issues.graphql.js'
+import { DiscussionComment, IssueComment } from './comments.graphql.js'
+import { StarredRepo } from './stars.graphql.js'
+import { Commit } from './commits.graphql.js'
+
+export type Data = {
+ user: User
+ starredRepositories: StarredRepo[]
+ repos: Repo[]
+ pulls: PullRequest[]
+ issues: Issue[]
+ issueComments: IssueComment[]
+ discussionComments: DiscussionComment[]
+}
+
+export type Repo =
+ Endpoints['GET /users/{username}/repos']['response']['data'][0] & {
+ commits: Commit[]
+ }
src/collect/issue-comments.ts
@@ -1,91 +0,0 @@
-import { Reactions } from './types.js'
-
-export const issueCommentsQuery = `#graphql
-query IssueCommentsQuery($login: String!, $num: Int = 100, $cursor: String) {
- user(login: $login) {
- issueComments(first: $num, after: $cursor) {
- totalCount
- nodes {
- url
- author {
- login
- }
- repository {
- nameWithOwner
- }
- issue {
- number
- author {
- login
- }
- }
- body
- createdAt
- updatedAt
- editor {
- login
- }
- reactions(first: 100) {
- totalCount
- nodes {
- content
- user {
- login
- }
- }
- }
- }
- pageInfo {
- hasNextPage
- endCursor
- }
- }
- }
- rateLimit {
- limit
- cost
- remaining
- resetAt
- }
-}
-`
-
-export type IssueCommentsQuery = {
- user: {
- issueComments: {
- totalCount: number
- nodes: Array<{
- url: string
- author: {
- login: string
- }
- repository: {
- nameWithOwner: string
- }
- issue: {
- number: number
- author: {
- login: string
- }
- }
- body: string
- createdAt: string
- updatedAt: string
- editor: {
- login: string
- } | null
- reactions: Reactions
- }>
- pageInfo: {
- hasNextPage: boolean
- endCursor: string
- }
- }
- }
- rateLimit: {
- limit: number
- cost: number
- remaining: number
- resetAt: string
- }
-}
src/collect/issue-timeline.graphql
@@ -0,0 +1,28 @@
+query IssueTimelineQuery($owner: String!, $name: String!, $number: Int!, $num: Int = 100, $cursor: String) {
+ repository(owner: $owner, name: $name) {
+ issue(number: $number) {
+ timelineItems(first: $num, after: $cursor) {
+ totalCount
+ nodes {
+ __typename
+ ... on ClosedEvent {
+ createdAt
+ actor {
+ login
+ }
+ }
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}
src/collect/issue-timeline.ts → src/collect/issue-timeline.graphql.ts
@@ -1,4 +1,6 @@
-export const issueTimelineQuery = `#graphql
+// DO NOT EDIT. This file was generated by megaera.
+
+export const IssueTimelineQuery = `#graphql
query IssueTimelineQuery($owner: String!, $name: String!, $number: Int!, $num: Int = 100, $cursor: String) {
repository(owner: $owner, name: $name) {
issue(number: $number) {
@@ -26,32 +28,32 @@ query IssueTimelineQuery($owner: String!, $name: String!, $number: Int!, $num: I
remaining
resetAt
}
-}
-`
+}` as string & IssueTimelineQuery
-export type IssueTimelineQuery = {
+export type IssueTimelineQuery = (vars: { owner: string, name: string, number: number, num?: number | null, cursor?: string | null }) => {
repository: {
issue: {
timelineItems: {
totalCount: number
nodes: Array<{
__typename: string
+ } & {
createdAt: string
actor: {
login: string
- }
- }>
+ } | null
+ } | null> | null
pageInfo: {
hasNextPage: boolean
- endCursor: string
+ endCursor: string | null
}
}
- }
- }
+ } | null
+ } | null
rateLimit: {
limit: number
cost: number
remaining: number
resetAt: string
- }
+ } | null
}
src/collect/issues.graphql
@@ -0,0 +1,61 @@
+fragment Issue on Issue {
+ createdAt
+ closedAt
+ closed
+ author {
+ login
+ }
+ url
+ number
+ title
+ labels(first: 10) {
+ totalCount
+ nodes {
+ name
+ }
+ }
+ body
+ comments(first: 1) {
+ totalCount
+ }
+ reactions(first: 100) {
+ totalCount
+ nodes {
+ content
+ user {
+ login
+ }
+ }
+ }
+ assignees(first: 3) {
+ totalCount
+ }
+ repository {
+ nameWithOwner
+ owner {
+ login
+ }
+ name
+ }
+}
+
+query IssuesQuery($username: String!, $num: Int = 100, $cursor: String) {
+ user(login: $username) {
+ issues(first: $num, after: $cursor, filterBy: { createdBy: $username }) {
+ totalCount
+ nodes {
+ ...Issue
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}
src/collect/issues.graphql.ts
@@ -0,0 +1,127 @@
+// DO NOT EDIT. This file was generated by megaera.
+
+const Issue = `#graphql
+fragment Issue on Issue {
+ createdAt
+ closedAt
+ closed
+ author {
+ login
+ }
+ url
+ number
+ title
+ labels(first: 10) {
+ totalCount
+ nodes {
+ name
+ }
+ }
+ body
+ comments(first: 1) {
+ totalCount
+ }
+ reactions(first: 100) {
+ totalCount
+ nodes {
+ content
+ user {
+ login
+ }
+ }
+ }
+ assignees(first: 3) {
+ totalCount
+ }
+ repository {
+ nameWithOwner
+ owner {
+ login
+ }
+ name
+ }
+}`
+
+export type Issue = {
+ createdAt: string
+ closedAt: string | null
+ closed: boolean
+ author: {
+ login: string
+ } | null
+ url: string
+ number: number
+ title: string
+ labels: {
+ totalCount: number
+ nodes: Array<{
+ name: string
+ }> | null
+ } | null
+ body: string
+ comments: {
+ totalCount: number
+ }
+ reactions: {
+ totalCount: number
+ nodes: Array<{
+ content: 'CONFUSED' | 'EYES' | 'HEART' | 'HOORAY' | 'LAUGH' | 'ROCKET' | 'THUMBS_DOWN' | 'THUMBS_UP'
+ user: {
+ login: string
+ } | null
+ }> | null
+ }
+ assignees: {
+ totalCount: number
+ }
+ repository: {
+ nameWithOwner: string
+ owner: {
+ login: string
+ }
+ name: string
+ }
+}
+
+
+export const IssuesQuery = `#graphql
+${Issue}
+query IssuesQuery($username: String!, $num: Int = 100, $cursor: String) {
+ user(login: $username) {
+ issues(first: $num, after: $cursor, filterBy: {createdBy: $username}) {
+ totalCount
+ nodes {
+ ...Issue
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}` as string & IssuesQuery
+
+export type IssuesQuery = (vars: { username: string, num?: number | null, cursor?: string | null }) => {
+ user: {
+ issues: {
+ totalCount: number
+ nodes: Array<{} & Issue> | null
+ pageInfo: {
+ hasNextPage: boolean
+ endCursor: string | null
+ }
+ }
+ } | null
+ rateLimit: {
+ limit: number
+ cost: number
+ remaining: number
+ resetAt: string
+ } | null
+}
src/collect/issues.ts
@@ -1,112 +0,0 @@
-import { Extra, Reactions } from './types.js'
-
-export const issuesQuery = `#graphql
-query IssuesQuery($username: String!, $num: Int = 100, $cursor: String) {
- user(login: $username) {
- issues(first: $num, after: $cursor, filterBy: { createdBy: $username }) {
- totalCount
- nodes {
- createdAt
- closedAt
- closed
- author {
- login
- }
- url
- number
- title
- labels(first: 10) {
- totalCount
- nodes {
- name
- }
- }
- body
- comments(first: 1) {
- totalCount
- }
- reactions(first: 100) {
- totalCount
- nodes {
- content
- user {
- login
- }
- }
- }
- assignees(first: 3) {
- totalCount
- }
- repository {
- nameWithOwner
- owner {
- login
- }
- name
- }
- }
- pageInfo {
- hasNextPage
- endCursor
- }
- }
- }
- rateLimit {
- limit
- cost
- remaining
- resetAt
- }
-}
-`
-
-export type IssuesQuery = {
- user: {
- issues: {
- totalCount: number
- nodes: Array<{
- createdAt: string
- closedAt: string
- closed: boolean
- closedBy: Extra<string>
- author: {
- login: string
- }
- url: string
- number: number
- title: string
- labels: {
- totalCount: number
- nodes: Array<{
- name: string
- }>
- }
- body: string
- comments: {
- totalCount: number
- }
- reactions: Reactions
- assignees: {
- totalCount: number
- }
- repository: {
- nameWithOwner: string
- owner: {
- login: string
- }
- name: string
- }
- }>
- pageInfo: {
- hasNextPage: boolean
- endCursor: string
- }
- }
- }
- rateLimit: {
- limit: number
- cost: number
- remaining: number
- resetAt: string
- }
-}
src/collect/pulls.graphql
@@ -0,0 +1,91 @@
+fragment PullRequest on PullRequest {
+ createdAt
+ url
+ number
+ title
+ body
+ closed
+ merged
+ mergedAt
+ mergedBy {
+ login
+ }
+ repository {
+ nameWithOwner
+ owner {
+ login
+ }
+ name
+ languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
+ totalCount
+ nodes {
+ name
+ }
+ }
+ }
+ participants(first: 20) {
+ totalCount
+ nodes {
+ login
+ }
+ }
+ lastCommit: commits(last: 1) {
+ nodes {
+ commit {
+ checkSuites(first: 20) {
+ totalCount
+ nodes {
+ app {
+ name
+ }
+ workflowRun {
+ workflow {
+ name
+ }
+ }
+ lastCheckRun: checkRuns(last: 1) {
+ totalCount
+ nodes {
+ name
+ conclusion
+ status
+ startedAt
+ completedAt
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ reactions(first: 100) {
+ totalCount
+ nodes {
+ content
+ user {
+ login
+ }
+ }
+ }
+}
+
+query PullsQuery($username: String!, $num: Int = 100, $cursor: String) {
+ user(login: $username) {
+ pullRequests(first: $num, after: $cursor) {
+ totalCount
+ nodes {
+ ...PullRequest
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}
src/collect/pulls.graphql.ts
@@ -0,0 +1,187 @@
+// DO NOT EDIT. This file was generated by megaera.
+
+const PullRequest = `#graphql
+fragment PullRequest on PullRequest {
+ createdAt
+ url
+ number
+ title
+ body
+ closed
+ merged
+ mergedAt
+ mergedBy {
+ login
+ }
+ repository {
+ nameWithOwner
+ owner {
+ login
+ }
+ name
+ languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
+ totalCount
+ nodes {
+ name
+ }
+ }
+ }
+ participants(first: 20) {
+ totalCount
+ nodes {
+ login
+ }
+ }
+ lastCommit: commits(last: 1) {
+ nodes {
+ commit {
+ checkSuites(first: 20) {
+ totalCount
+ nodes {
+ app {
+ name
+ }
+ workflowRun {
+ workflow {
+ name
+ }
+ }
+ lastCheckRun: checkRuns(last: 1) {
+ totalCount
+ nodes {
+ name
+ conclusion
+ status
+ startedAt
+ completedAt
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ reactions(first: 100) {
+ totalCount
+ nodes {
+ content
+ user {
+ login
+ }
+ }
+ }
+}`
+
+export type PullRequest = {
+ createdAt: string
+ url: string
+ number: number
+ title: string
+ body: string
+ closed: boolean
+ merged: boolean
+ mergedAt: string | null
+ mergedBy: {
+ login: string
+ } | null
+ repository: {
+ nameWithOwner: string
+ owner: {
+ login: string
+ }
+ name: string
+ languages: {
+ totalCount: number
+ nodes: Array<{
+ name: string
+ }> | null
+ } | null
+ }
+ participants: {
+ totalCount: number
+ nodes: Array<{
+ login: string
+ }> | null
+ }
+ lastCommit: {
+ nodes: Array<{
+ commit: {
+ checkSuites: {
+ totalCount: number
+ nodes: Array<{
+ app: {
+ name: string
+ } | null
+ workflowRun: {
+ workflow: {
+ name: string
+ }
+ } | null
+ lastCheckRun: {
+ totalCount: number
+ nodes: Array<{
+ name: string
+ conclusion: 'ACTION_REQUIRED' | 'CANCELLED' | 'FAILURE' | 'NEUTRAL' | 'SKIPPED' | 'STALE' | 'STARTUP_FAILURE' | 'SUCCESS' | 'TIMED_OUT'
+ status: 'COMPLETED' | 'IN_PROGRESS' | 'PENDING' | 'QUEUED' | 'REQUESTED' | 'WAITING'
+ startedAt: string | null
+ completedAt: string | null
+ }> | null
+ } | null
+ }> | null
+ } | null
+ }
+ }> | null
+ }
+ reactions: {
+ totalCount: number
+ nodes: Array<{
+ content: 'CONFUSED' | 'EYES' | 'HEART' | 'HOORAY' | 'LAUGH' | 'ROCKET' | 'THUMBS_DOWN' | 'THUMBS_UP'
+ user: {
+ login: string
+ } | null
+ }> | null
+ }
+}
+
+
+export const PullsQuery = `#graphql
+${PullRequest}
+query PullsQuery($username: String!, $num: Int = 100, $cursor: String) {
+ user(login: $username) {
+ pullRequests(first: $num, after: $cursor) {
+ totalCount
+ nodes {
+ ...PullRequest
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}` as string & PullsQuery
+
+export type PullsQuery = (vars: { username: string, num?: number | null, cursor?: string | null }) => {
+ user: {
+ pullRequests: {
+ totalCount: number
+ nodes: Array<{} & PullRequest> | null
+ pageInfo: {
+ hasNextPage: boolean
+ endCursor: string | null
+ }
+ }
+ } | null
+ rateLimit: {
+ limit: number
+ cost: number
+ remaining: number
+ resetAt: string
+ } | null
+}
src/collect/pulls.ts
@@ -1,186 +0,0 @@
-import { Reactions } from './types.js'
-
-export const pullsQuery = `#graphql
-query PullsQuery($username: String!, $num: Int = 100, $cursor: String) {
- user(login: $username) {
- pullRequests(first: $num, after: $cursor) {
- totalCount
- nodes {
- createdAt
- url
- number
- title
- body
- closed
- merged
- mergedAt
- mergedBy {
- login
- }
- repository {
- nameWithOwner
- owner {
- login
- }
- name
- languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
- totalCount
- nodes {
- name
- }
- }
- }
- participants(first: 20) {
- totalCount
- nodes {
- login
- }
- }
- lastCommit: commits(last: 1) {
- nodes {
- commit {
- checkSuites(first: 20) {
- totalCount
- nodes {
- app {
- name
- }
- workflowRun {
- workflow {
- name
- }
- }
- lastCheckRun: checkRuns(last: 1) {
- totalCount
- nodes {
- name
- conclusion
- status
- startedAt
- completedAt
- }
- }
- }
- }
- }
- }
- }
- reactions(first: 100) {
- totalCount
- nodes {
- content
- user {
- login
- }
- }
- }
- }
- pageInfo {
- hasNextPage
- endCursor
- }
- }
- }
- rateLimit {
- limit
- cost
- remaining
- resetAt
- }
-}
-`
-
-export type PullsQuery = {
- user: {
- pullRequests: {
- totalCount: number
- nodes: Array<{
- createdAt: string
- url: string
- number: number
- title: string
- body: string
- closed: boolean
- merged: boolean
- mergedAt: string
- mergedBy?: {
- login: string
- }
- repository: {
- nameWithOwner: string
- owner: {
- login: string
- }
- name: string
- languages: {
- totalCount: number
- nodes: Array<{
- name: string
- }>
- }
- }
- participants: {
- totalCount: number
- nodes: Array<{
- login: string
- }>
- }
- lastCommit: {
- nodes: Array<{
- commit: {
- checkSuites: {
- totalCount: number
- nodes: Array<{
- app: {
- name: string
- }
- workflowRun: {
- workflow: {
- name: string
- }
- }
- lastCheckRun: {
- totalCount: number
- nodes: Array<{
- name: string
- conclusion:
- | 'ACTION_REQUIRED'
- | 'TIMED_OUT'
- | 'CANCELLED'
- | 'FAILURE'
- | 'SUCCESS'
- | 'NEUTRAL'
- | 'SKIPPED'
- | 'STARTUP_FAILURE'
- | 'STALE'
- status:
- | 'COMPLETED'
- | 'IN_PROGRESS'
- | 'PENDING'
- | 'QUEUED'
- | 'REQUESTED'
- | 'WAITING'
- startedAt: string
- completedAt: string
- }>
- }
- }>
- }
- }
- }>
- }
- reactions: Reactions
- }>
- }
- pageInfo: {
- hasNextPage: boolean
- endCursor: string
- }
- }
- rateLimit: {
- limit: number
- cost: number
- remaining: number
- resetAt: string
- }
-}
src/collect/stars.graphql
@@ -0,0 +1,43 @@
+fragment StarredRepo on Repository {
+ nameWithOwner
+ description
+ stargazers {
+ totalCount
+ }
+ languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
+ totalCount
+ edges {
+ size
+ node {
+ name
+ }
+ }
+ }
+ licenseInfo {
+ name
+ nickname
+ }
+}
+
+query StarsQuery($login: String!, $num: Int = 100, $cursor: String) {
+ user(login: $login) {
+ starredRepositories(first: $num, after: $cursor) {
+ totalCount
+ isOverLimit
+ nodes {
+ ...StarredRepo
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}
+
src/collect/stars.graphql.ts
@@ -0,0 +1,89 @@
+// DO NOT EDIT. This file was generated by megaera.
+
+const StarredRepo = `#graphql
+fragment StarredRepo on Repository {
+ nameWithOwner
+ description
+ stargazers {
+ totalCount
+ }
+ languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
+ totalCount
+ edges {
+ size
+ node {
+ name
+ }
+ }
+ }
+ licenseInfo {
+ name
+ nickname
+ }
+}`
+
+export type StarredRepo = {
+ nameWithOwner: string
+ description: string | null
+ stargazers: {
+ totalCount: number
+ }
+ languages: {
+ totalCount: number
+ edges: Array<{
+ size: number
+ node: {
+ name: string
+ }
+ }> | null
+ } | null
+ licenseInfo: {
+ name: string
+ nickname: string | null
+ } | null
+}
+
+
+export const StarsQuery = `#graphql
+${StarredRepo}
+query StarsQuery($login: String!, $num: Int = 100, $cursor: String) {
+ user(login: $login) {
+ starredRepositories(first: $num, after: $cursor) {
+ totalCount
+ isOverLimit
+ nodes {
+ ...StarredRepo
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}` as string & StarsQuery
+
+export type StarsQuery = (vars: { login: string, num?: number | null, cursor?: string | null }) => {
+ user: {
+ starredRepositories: {
+ totalCount: number
+ isOverLimit: boolean
+ nodes: Array<{} & StarredRepo> | null
+ pageInfo: {
+ hasNextPage: boolean
+ endCursor: string | null
+ }
+ }
+ } | null
+ rateLimit: {
+ limit: number
+ cost: number
+ remaining: number
+ resetAt: string
+ } | null
+}
src/collect/stars.ts
@@ -1,79 +0,0 @@
-export const starsQuery = `#graphql
-query StarsQuery($login: String!, $num: Int = 100, $cursor: String) {
- user(login: $login) {
- starredRepositories(first: $num, after: $cursor) {
- totalCount
- isOverLimit
- nodes {
- nameWithOwner
- description
- stargazers {
- totalCount
- }
- languages(first: 10, orderBy: {field: SIZE, direction: DESC}) {
- totalCount
- edges {
- size
- node {
- name
- }
- }
- }
- licenseInfo {
- name
- nickname
- }
- }
- pageInfo {
- hasNextPage
- endCursor
- }
- }
- }
- rateLimit {
- limit
- cost
- remaining
- resetAt
- }
-}
-`
-
-export type StarsQuery = {
- user: {
- starredRepositories: {
- totalCount: number
- isOverLimit: boolean
- nodes: Array<{
- nameWithOwner: string
- description: string
- stargazers: {
- totalCount: number
- }
- languages: {
- totalCount: number
- edges: Array<{
- size: number
- node: {
- name: string
- }
- }>
- }
- licenseInfo: {
- name: string
- nickname: string
- }
- }>
- pageInfo: {
- hasNextPage: boolean
- endCursor: string
- }
- }
- }
- rateLimit: {
- limit: number
- cost: number
- remaining: number
- resetAt: string
- }
-}
src/collect/types.ts
@@ -1,62 +0,0 @@
-import { Endpoints } from '@octokit/types'
-import { CommitsQuery } from './commits.js'
-import { IssuesQuery } from './issues.js'
-import { UserQuery } from './user.js'
-import { PullsQuery } from './pulls.js'
-import { IssueCommentsQuery } from './issue-comments.js'
-import { DiscussionCommentsQuery } from './discussion-comments.js'
-import { StarsQuery } from './stars.js'
-
-// Extra<T> represents additional data that is not returned by the GraphQL API,
-// but enriched by some other means (e.g., separate queries).
-export type Extra<T> = T | undefined
-
-export type Data = {
- user: User
- starredRepositories: StarredRepo[]
- repos: Repo[]
- pulls: Pull[]
- issues: Issue[]
- issueComments: IssueComment[]
- discussionComments: DiscussionComment[]
-}
-
-export type User = UserQuery['user']
-
-export type Repo =
- Endpoints['GET /users/{username}/repos']['response']['data'][0] & {
- commits: Commit[]
- }
-
-export type Commit =
- CommitsQuery['repository']['defaultBranchRef']['target']['history']['nodes'][0]
-
-export type Pull = PullsQuery['user']['pullRequests']['nodes'][0]
-
-export type Issue = IssuesQuery['user']['issues']['nodes'][0]
-
-export type IssueComment =
- IssueCommentsQuery['user']['issueComments']['nodes'][0]
-
-export type DiscussionComment =
- DiscussionCommentsQuery['user']['repositoryDiscussionComments']['nodes'][0]
-
-export type StarredRepo = StarsQuery['user']['starredRepositories']['nodes'][0]
-
-export type Reactions = {
- totalCount: number
- nodes: Array<{
- content:
- | 'CONFUSED'
- | 'EYES'
- | 'HEART'
- | 'HOORAY'
- | 'LAUGH'
- | 'ROCKET'
- | 'THUMBS_DOWN'
- | 'THUMBS_UP'
- user: {
- login: string
- }
- }>
-}
src/collect/user.graphql
@@ -0,0 +1,64 @@
+fragment User on User {
+ id
+ login
+ name
+ avatarUrl
+ bio
+ company
+ location
+ email
+ twitterUsername
+ websiteUrl
+ status {
+ createdAt
+ emoji
+ message
+ }
+ createdAt
+ followers {
+ totalCount
+ }
+ following {
+ totalCount
+ }
+ anyPinnableItems
+ pinnedItems(first: 6) {
+ totalCount
+ nodes {
+ ... on Gist {
+ name
+ }
+ ... on Repository {
+ name
+ }
+ }
+ }
+ sponsoring {
+ totalCount
+ }
+ sponsors {
+ totalCount
+ }
+ starredRepositories {
+ totalCount
+ }
+ publicKeys(first: 5) {
+ totalCount
+ nodes {
+ key
+ }
+ }
+}
+
+query UserQuery($login: String!) {
+ user(login: $login) {
+ ...User
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}
+
src/collect/user.graphql.ts
@@ -0,0 +1,128 @@
+// DO NOT EDIT. This file was generated by megaera.
+
+const User = `#graphql
+fragment User on User {
+ id
+ login
+ name
+ avatarUrl
+ bio
+ company
+ location
+ email
+ twitterUsername
+ websiteUrl
+ status {
+ createdAt
+ emoji
+ message
+ }
+ createdAt
+ followers {
+ totalCount
+ }
+ following {
+ totalCount
+ }
+ anyPinnableItems
+ pinnedItems(first: 6) {
+ totalCount
+ nodes {
+ ... on Gist {
+ name
+ }
+ ... on Repository {
+ name
+ }
+ }
+ }
+ sponsoring {
+ totalCount
+ }
+ sponsors {
+ totalCount
+ }
+ starredRepositories {
+ totalCount
+ }
+ publicKeys(first: 5) {
+ totalCount
+ nodes {
+ key
+ }
+ }
+}`
+
+export type User = {
+ id: string
+ login: string
+ name: string | null
+ avatarUrl: string
+ bio: string | null
+ company: string | null
+ location: string | null
+ email: string
+ twitterUsername: string | null
+ websiteUrl: string | null
+ status: {
+ createdAt: string
+ emoji: string | null
+ message: string | null
+ } | null
+ createdAt: string
+ followers: {
+ totalCount: number
+ }
+ following: {
+ totalCount: number
+ }
+ anyPinnableItems: boolean
+ pinnedItems: {
+ totalCount: number
+ nodes: Array<{} & {
+ name: string
+ } & {
+ name: string
+ } | null> | null
+ }
+ sponsoring: {
+ totalCount: number
+ }
+ sponsors: {
+ totalCount: number
+ }
+ starredRepositories: {
+ totalCount: number
+ }
+ publicKeys: {
+ totalCount: number
+ nodes: Array<{
+ key: string
+ }> | null
+ }
+}
+
+
+export const UserQuery = `#graphql
+${User}
+query UserQuery($login: String!) {
+ user(login: $login) {
+ ...User
+ }
+ rateLimit {
+ limit
+ cost
+ remaining
+ resetAt
+ }
+}` as string & UserQuery
+
+export type UserQuery = (vars: { login: string }) => {
+ user: {} & User | null
+ rateLimit: {
+ limit: number
+ cost: number
+ remaining: number
+ resetAt: string
+ } | null
+}
src/collect/user.ts
@@ -1,116 +0,0 @@
-export const userQuery = `#graphql
-query UserQuery($login: String!) {
- user(login: $login) {
- id
- login
- name
- avatarUrl
- bio
- company
- location
- email
- twitterUsername
- websiteUrl
- status {
- createdAt
- emoji
- message
- }
- createdAt
- followers {
- totalCount
- }
- following {
- totalCount
- }
- anyPinnableItems
- pinnedItems(first: 6) {
- totalCount
- nodes {
- ... on Gist {
- name
- }
- ... on Repository {
- name
- }
- }
- }
- sponsoring {
- totalCount
- }
- sponsors {
- totalCount
- }
- starredRepositories {
- totalCount
- }
- publicKeys(first: 5) {
- totalCount
- nodes {
- key
- }
- }
- }
- rateLimit {
- limit
- cost
- remaining
- resetAt
- }
-}
-`
-
-export type UserQuery = {
- user: {
- id: string
- login: string
- name: string
- avatarUrl: string
- bio: string | null
- company: string | null
- location: string | null
- email: string
- twitterUsername: string | null
- websiteUrl: string | null
- status: {
- createdAt: string
- emoji: string
- message: string
- } | null
- createdAt: string
- followers: {
- totalCount: number
- }
- following: {
- totalCount: number
- }
- anyPinnableItems: boolean
- pinnedItems: {
- totalCount: number
- nodes: Array<{
- name: string
- }>
- }
- sponsoring: {
- totalCount: number
- }
- sponsors: {
- totalCount: number
- }
- starredRepositories: {
- totalCount: number
- }
- publicKeys: {
- totalCount: number
- nodes: Array<{
- key: string
- }>
- }
- }
- rateLimit: {
- limit: number
- cost: number
- remaining: number
- resetAt: string
- }
-}
src/badges.ts
@@ -1,6 +1,9 @@
import allBadges from '#badges'
import { linkCommit, linkIssue, linkPull } from './utils.js'
-import { Commit, Data, Issue, Pull } from './collect/types.js'
+import { Data } from './collect/index.js'
+import { Commit } from './collect/commits.graphql.js'
+import { PullRequest } from './collect/pulls.graphql.js'
+import { Issue } from './collect/issues.graphql.js'
export type Presenters = (typeof allBadges)[number]['default']
@@ -58,7 +61,7 @@ export class Evidence {
return this
}
- evidencePRs(...pulls: Pull[]) {
+ evidencePRs(...pulls: PullRequest[]) {
this.evidence(
'Pull requests:\n\n' +
pulls
@@ -69,7 +72,7 @@ export class Evidence {
return this
}
- evidencePRsWithTitle(...pulls: Pull[]) {
+ evidencePRsWithTitle(...pulls: PullRequest[]) {
this.evidence(
'Pull requests:\n\n' +
pulls.map((x) => `- ${linkPull(x)}: ${x.title}`).join('\n'),
src/collect/collect.ts → src/collect.ts
@@ -1,24 +1,36 @@
import { Octokit } from 'octokit'
-import { pullsQuery, PullsQuery } from './pulls.js'
-import { commitsQuery, CommitsQuery } from './commits.js'
-import { issuesQuery, IssuesQuery } from './issues.js'
-import { userQuery, UserQuery } from './user.js'
-import { IssueTimelineQuery, issueTimelineQuery } from './issue-timeline.js'
-import { Data } from './types.js'
-import { issueCommentsQuery, IssueCommentsQuery } from './issue-comments.js'
+import { Data } from './collect/index.js'
+import { Query, Variables } from 'megaera'
+import { UserQuery } from './collect/user.graphql.js'
+import { CommitsQuery } from './collect/commits.graphql.js'
+import { PullsQuery } from './collect/pulls.graphql.js'
+import { IssuesQuery } from './collect/issues.graphql.js'
+import { IssueTimelineQuery } from './collect/issue-timeline.graphql.js'
import {
- discussionCommentsQuery,
DiscussionCommentsQuery,
-} from './discussion-comments.js'
-import { starsQuery, StarsQuery } from './stars.js'
+ IssueCommentsQuery,
+} from './collect/comments.graphql.js'
+import { StarsQuery } from './collect/stars.graphql.js'
export async function collect(
octokit: Octokit,
username: string,
): Promise<Data> {
- const { user } = await octokit.graphql<UserQuery>(userQuery, {
+ function query<T extends Query>(query: T, variables: Variables<T>) {
+ return octokit.graphql<ReturnType<T>>(query, variables)
+ }
+
+ function paginate<T extends Query>(query: T, variables: Variables<T>) {
+ return octokit.graphql.paginate.iterator<ReturnType<T>>(query, variables)
+ }
+
+ const { user } = await query(UserQuery, {
login: username,
- })
+ })!
+
+ if (!user) {
+ throw new Error('Failed to load user')
+ }
const data: Data = {
user: user,
@@ -51,18 +63,19 @@ export async function collect(
for (const repo of data.repos) {
console.log(`Loading commits for ${repo.owner.login}/${repo.name}`)
try {
- const commits = octokit.graphql.paginate.iterator<CommitsQuery>(
- commitsQuery,
- {
- owner: repo.owner.login,
- name: repo.name,
- author: user.id,
- },
- )
+ const commits = paginate(CommitsQuery, {
+ owner: repo.owner.login,
+ name: repo.name,
+ author: user.id,
+ })
for await (const resp of commits) {
const { totalCount, nodes } =
- resp.repository.defaultBranchRef.target.history
+ resp.repository?.defaultBranchRef?.target?.history!
+
+ if (!nodes) {
+ throw new Error('Failed to load commits')
+ }
if (totalCount >= 10_000) {
console.error(
@@ -75,7 +88,7 @@ export async function collect(
repo.commits.push(commit)
}
console.log(
- `| commits ${repo.commits.length}/${totalCount} (cost: ${resp.rateLimit.cost}, remaining: ${resp.rateLimit.remaining})`,
+ `| commits ${repo.commits.length}/${totalCount} (cost: ${resp.rateLimit?.cost}, remaining: ${resp.rateLimit?.remaining})`,
)
}
} catch (err) {
@@ -86,17 +99,21 @@ export async function collect(
}
}
- const pulls = octokit.graphql.paginate.iterator<PullsQuery>(pullsQuery, {
+ const pulls = paginate(PullsQuery, {
username,
})
try {
for await (const resp of pulls) {
+ if (!resp.user?.pullRequests.nodes) {
+ throw new Error('Failed to load pull requests')
+ }
+
console.log(
`Loading pull requests ${
data.pulls.length + resp.user.pullRequests.nodes.length
}/${resp.user.pullRequests.totalCount} (cost: ${
- resp.rateLimit.cost
- }, remaining: ${resp.rateLimit.remaining})`,
+ resp.rateLimit?.cost
+ }, remaining: ${resp.rateLimit?.remaining})`,
)
for (const pull of resp.user.pullRequests.nodes) {
data.pulls.push(pull)
@@ -107,16 +124,20 @@ export async function collect(
console.error(err)
}
- const issues = octokit.graphql.paginate.iterator<IssuesQuery>(issuesQuery, {
+ const issues = paginate(IssuesQuery, {
username,
})
try {
for await (const resp of issues) {
+ if (!resp.user?.issues.nodes) {
+ throw new Error('Failed to load issues')
+ }
+
console.log(
`Loading issues ${data.issues.length + resp.user.issues.nodes.length}/${
resp.user.issues.totalCount
- } (cost: ${resp.rateLimit.cost}, remaining: ${
- resp.rateLimit.remaining
+ } (cost: ${resp.rateLimit?.cost}, remaining: ${
+ resp.rateLimit?.remaining
})`,
)
for (const issue of resp.user.issues.nodes) {
@@ -133,22 +154,22 @@ export async function collect(
`Loading issue timeline for ${issue.repository.name}#${issue.number}`,
)
try {
- const timeline = octokit.graphql.paginate.iterator<IssueTimelineQuery>(
- issueTimelineQuery,
- {
- owner: issue.repository.owner.login,
- name: issue.repository.name,
- number: issue.number,
- },
- )
+ const timeline = paginate(IssueTimelineQuery, {
+ owner: issue.repository.owner.login,
+ name: issue.repository.name,
+ number: issue.number,
+ })
for await (const resp of timeline) {
+ if (!resp.repository?.issue?.timelineItems.nodes) {
+ throw new Error('Failed to load issue timeline')
+ }
+
console.log(
- `| timeline ${resp.repository.issue.timelineItems.nodes.length}/${resp.repository.issue.timelineItems.totalCount} (cost: ${resp.rateLimit.cost}, remaining: ${resp.rateLimit.remaining})`,
+ `| timeline ${resp.repository.issue.timelineItems.nodes.length}/${resp.repository.issue.timelineItems.totalCount} (cost: ${resp.rateLimit?.cost}, remaining: ${resp.rateLimit?.remaining})`,
)
for (const event of resp.repository.issue.timelineItems.nodes) {
- if (event.__typename == 'ClosedEvent') {
+ if (event?.__typename == 'ClosedEvent') {
issue.closedAt = event.createdAt
- issue.closedBy = event.actor.login
}
}
}
@@ -160,19 +181,20 @@ export async function collect(
}
}
- const issueComments = octokit.graphql.paginate.iterator<IssueCommentsQuery>(
- issueCommentsQuery,
- {
- login: username,
- },
- )
+ const issueComments = paginate(IssueCommentsQuery, {
+ login: username,
+ })
try {
for await (const resp of issueComments) {
+ if (!resp.user?.issueComments.nodes) {
+ throw new Error('Failed to load issue comments')
+ }
+
for (const comment of resp.user.issueComments.nodes) {
data.issueComments.push(comment)
}
console.log(
- `| issue comments ${data.issueComments.length}/${resp.user.issueComments.totalCount} (cost: ${resp.rateLimit.cost}, remaining: ${resp.rateLimit.remaining})`,
+ `| issue comments ${data.issueComments.length}/${resp.user.issueComments.totalCount} (cost: ${resp.rateLimit?.cost}, remaining: ${resp.rateLimit?.remaining})`,
)
}
} catch (err) {
@@ -180,20 +202,20 @@ export async function collect(
console.error(err)
}
- const discussionComments =
- octokit.graphql.paginate.iterator<DiscussionCommentsQuery>(
- discussionCommentsQuery,
- {
- login: username,
- },
- )
+ const discussionComments = paginate(DiscussionCommentsQuery, {
+ login: username,
+ })
try {
for await (const resp of discussionComments) {
+ if (!resp.user?.repositoryDiscussionComments.nodes) {
+ throw new Error('Failed to load discussion comments')
+ }
+
for (const comment of resp.user.repositoryDiscussionComments.nodes) {
data.discussionComments.push(comment)
}
console.log(
- `| discussion comments ${data.discussionComments.length}/${resp.user.repositoryDiscussionComments.totalCount} (cost: ${resp.rateLimit.cost}, remaining: ${resp.rateLimit.remaining})`,
+ `| discussion comments ${data.discussionComments.length}/${resp.user.repositoryDiscussionComments.totalCount} (cost: ${resp.rateLimit?.cost}, remaining: ${resp.rateLimit?.remaining})`,
)
}
} catch (err) {
@@ -201,16 +223,20 @@ export async function collect(
console.error(err)
}
- const stars = octokit.graphql.paginate.iterator<StarsQuery>(starsQuery, {
+ const stars = paginate(StarsQuery, {
login: username,
})
try {
for await (const resp of stars) {
+ if (!resp.user?.starredRepositories.nodes) {
+ throw new Error('Failed to load stars')
+ }
+
for (const repo of resp.user.starredRepositories.nodes) {
data.starredRepositories.push(repo)
}
console.log(
- `| stars ${data.starredRepositories.length}/${resp.user.starredRepositories.totalCount} (cost: ${resp.rateLimit.cost}, remaining: ${resp.rateLimit.remaining})`,
+ `| stars ${data.starredRepositories.length}/${resp.user.starredRepositories.totalCount} (cost: ${resp.rateLimit?.cost}, remaining: ${resp.rateLimit?.remaining})`,
)
}
} catch (err) {
src/get-data.ts
@@ -1,7 +1,7 @@
-import { collect } from './collect/collect.js'
+import { collect } from './collect.js'
import fs from 'node:fs'
import { Octokit } from 'octokit'
-import { Data } from './collect/types.js'
+import { Data } from './collect/index.js'
export async function getData(
octokit: Octokit,
src/index.ts
@@ -1,3 +1,8 @@
export { define } from './badges.js'
-export { Repo, User, Issue, Pull, Commit } from './collect/types.js'
+export { Repo } from './collect/index.js'
+export { User } from './collect/user.graphql.js'
+export { Issue } from './collect/issues.graphql.js'
+export { PullRequest } from './collect/pulls.graphql.js'
+export { Commit } from './collect/commits.graphql.js'
+
export { linkCommit, linkIssue, linkPull, latest, plural } from './utils.js'
src/present-badges.ts
@@ -2,7 +2,7 @@ import { Badge, Evidence, ID, List, Presenter } from './badges.js'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import { parseMask } from './utils.js'
-import { Data } from './collect/types.js'
+import { Data } from './collect/index.js'
export const presentBadges = <P extends Presenter<List>>(
presenters: P[],
src/utils.ts
@@ -1,5 +1,7 @@
import { spawnSync } from 'node:child_process'
-import { Commit, Issue, Pull } from './collect/types.js'
+import { Commit } from './collect/commits.graphql.js'
+import { PullRequest } from './collect/pulls.graphql.js'
+import { Issue } from './collect/issues.graphql.js'
export function linkCommit(commit: Commit): string {
return `<a href="https://github.com/${commit.repository.owner.login}/${
@@ -7,7 +9,7 @@ export function linkCommit(commit: Commit): string {
}/commit/${commit.sha}">${commit.sha.slice(0, 7)}</a>`
}
-export function linkPull(pull: Pull): string {
+export function linkPull(pull: PullRequest): string {
return `<a href="https://github.com/${pull.repository.owner.login}/${pull.repository.name}/pull/${pull.number}">#${pull.number}</a>`
}
test/present-badges.test.ts
@@ -1,8 +1,8 @@
import * as assert from 'node:assert'
import { describe, it } from 'node:test'
import { presentBadges } from '../src/present-badges.js'
-import { Badge, define, List, Presenter } from '../src/badges.js'
-import { Data } from '../src/collect/types.js'
+import { Badge, define } from '../src/badges.js'
+import { Data } from '../src/collect/index.js'
describe('present-badges', () => {
const data: Data = {
@@ -31,7 +31,7 @@ describe('present-badges', () => {
commits: [] as any[],
},
] as Data['repos'],
- }
+ } as Data
it('presentBadges() applies `pick`', async () => {
const userBadges = presentBadges(
test/stars.test.ts
@@ -2,7 +2,7 @@ import * as assert from 'node:assert'
import { describe, it } from 'node:test'
import starsPresenter from '#badges/stars/stars.js'
import { badgeCollection } from '../src/present-badges.js'
-import { Data } from '../src/collect/types.js'
+import { Data } from '../src/collect/index.js'
import { Badge } from '../src/badges.js'
describe('stars', () => {
@@ -31,7 +31,7 @@ describe('stars', () => {
commits: [] as any[],
},
] as Data['repos'],
- }
+ } as Data
starsPresenter.present(data, grant)
package-lock.json
@@ -11,6 +11,7 @@
"dependencies": {
"@octokit/plugin-retry": "^7.1.1",
"@octokit/plugin-throttling": "^9.3.0",
+ "megaera": "^0.0.2",
"minimist": "^1.2.8",
"octokit": "^4.0.2"
},
@@ -1041,7 +1042,6 @@
"version": "16.8.1",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz",
"integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==",
- "dev": true,
"engines": {
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
}
@@ -1250,6 +1250,18 @@
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
+ "node_modules/megaera": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/megaera/-/megaera-0.0.2.tgz",
+ "integrity": "sha512-VXzm1d9Qoi+jY3H4kyi87YZojQ3fs73T/FUKo37WfJ+74nId0nOM0fREJUc3V7m2pZ3i+w7IVK9XDm2V9bE/iQ==",
+ "license": "MIT",
+ "dependencies": {
+ "graphql": "^16.0.0"
+ },
+ "bin": {
+ "megaera": "dist/cli.js"
+ }
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
package.json
@@ -25,6 +25,7 @@
"dependencies": {
"@octokit/plugin-retry": "^7.1.1",
"@octokit/plugin-throttling": "^9.3.0",
+ "megaera": "^0.0.2",
"minimist": "^1.2.8",
"octokit": "^4.0.2"
},