Skip to content

Commit d49acae

Browse files
lishaduckdkhokhlovaustenstoneEndBugoddstr13
committed
fix: cherry-pick from forks, finally
Co-authored-by: Dmitri Khokhlov <7530150+dkhokhlov@users.noreply.github.com> Co-authored-by: Austen Stone <22425467+austenstone@users.noreply.github.com> Co-authored-by: Federico Grandi <26386270+endbug@users.noreply.github.com> Co-authored-by: Odd Stråbø <638706+oddstr13@users.noreply.github.com> Co-authored-by: Felipe Santos <29582865+felipecrs@users.noreply.github.com> Co-authored-by: Fernando Fernández <10274099+ferferga@users.noreply.github.com>
1 parent c3d0fb2 commit d49acae

File tree

7 files changed

+110
-35
lines changed

7 files changed

+110
-35
lines changed

source/plugins/achievements/list/organizations.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ export default async function({list, login, data, computed, imports, graphql, qu
3939

4040
//Managers
4141
{
42-
const value = organization.projects.totalCount
43-
const unlock = organization.projects.nodes?.shift()
42+
const value = organization.projectsV2.totalCount
43+
const unlock = organization.projectsV2.nodes?.shift()
4444

4545
list.push({
4646
title: "Managers",

source/plugins/achievements/list/users.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ export default async function({list, login, data, computed, imports, graphql, qu
5555

5656
//Manager
5757
{
58-
const value = user.projects.totalCount
59-
const unlock = user.projects.nodes?.shift()
58+
const value = user.projectsV2.totalCount
59+
const unlock = user.projectsV2.nodes?.shift()
6060

6161
list.push({
6262
title: "Manager",

source/plugins/activity/index.mjs

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,43 @@ export default async function({login, data, rest, q, account, imports}, {enabled
3737
}
3838
console.debug(`metrics/compute/${login}/plugins > activity > ${events.length} events loaded`)
3939

40+
const payloadTypesToCustomTypes = {
41+
CommitCommentEvent:"comment",
42+
CreateEvent:"ref/create",
43+
DeleteEvent:"ref/delete",
44+
ForkEvent:"fork",
45+
GollumEvent:"wiki",
46+
IssueCommentEvent:"comment",
47+
IssuesEvent:"issue",
48+
MemberEvent:"member",
49+
PublicEvent:"public",
50+
PullRequestEvent:"pr",
51+
PullRequestReviewEvent:"review",
52+
PullRequestReviewCommentEvent:"comment",
53+
PushEvent:"push",
54+
ReleaseEvent:"release",
55+
WatchEvent:"star",
56+
}
57+
4058
//Extract activity events
4159
const activity = (await Promise.all(
4260
events
4361
.filter(({actor}) => account === "organization" ? true : actor.login?.toLocaleLowerCase() === login.toLocaleLowerCase())
4462
.filter(({created_at}) => Number.isFinite(days) ? new Date(created_at) > new Date(Date.now() - days * 24 * 60 * 60 * 1000) : true)
4563
.filter(event => visibility === "public" ? event.public : true)
46-
.map(async ({type, payload, actor: {login: actor}, repo: {name: repo}, created_at}) => {
47-
//See https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/github-event-types
64+
.map(event => ({event, customType:payloadTypesToCustomTypes[event.type]}))
65+
.filter(({customType}) => !!customType) //Ignore events with an unknown type
66+
.filter(({customType}) => filter.includes("all") || filter.includes(customType)) //Filter events based on user preference
67+
.map(({event}) => event) //Discard customType, it will be re-assigned
68+
.map(async ({type, payload, actor:{login:actor}, repo:{name:repo}, created_at}) => { //See https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/github-event-types
4869
const timestamp = new Date(created_at)
4970
if (!imports.filters.repo(repo, skipped))
5071
return null
72+
73+
//Get custom type from the previously declared mapping, so that it acts as a single source of truth
74+
const customType = payloadTypesToCustomTypes[type]
75+
if (!customType) throw new Error(`Missing event mapping for type: ${type}`)
76+
5177
switch (type) {
5278
//Commented on a commit
5379
case "CommitCommentEvent": {
@@ -56,27 +82,27 @@ export default async function({login, data, rest, q, account, imports}, {enabled
5682
const {comment: {user: {login: user}, commit_id: sha, body: content}} = payload
5783
if (!imports.filters.text(user, ignored))
5884
return null
59-
return {type: "comment", on: "commit", actor, timestamp, repo, content: await imports.markdown(content, {mode: markdown, codelines}), user, mobile: null, number: sha.substring(0, 7), title: ""}
85+
return {type: customType, on: "commit", actor, timestamp, repo, content: await imports.markdown(content, {mode: markdown, codelines}), user, mobile: null, number: sha.substring(0, 7), title: ""}
6086
}
6187
//Created a git branch or tag
6288
case "CreateEvent": {
6389
const {ref: name, ref_type: type} = payload
64-
return {type: "ref/create", actor, timestamp, repo, ref: {name, type}}
90+
return {type: customType, actor, timestamp, repo, ref: {name, type}}
6591
}
6692
//Deleted a git branch or tag
6793
case "DeleteEvent": {
6894
const {ref: name, ref_type: type} = payload
69-
return {type: "ref/delete", actor, timestamp, repo, ref: {name, type}}
95+
return {type: customType, actor, timestamp, repo, ref: {name, type}}
7096
}
7197
//Forked repository
7298
case "ForkEvent": {
7399
const {forkee: {full_name: forked}} = payload
74-
return {type: "fork", actor, timestamp, repo, forked}
100+
return {type: customType, actor, timestamp, repo, forked}
75101
}
76102
//Wiki changes
77103
case "GollumEvent": {
78104
const {pages} = payload
79-
return {type: "wiki", actor, timestamp, repo, pages: pages.map(({title}) => title)}
105+
return {type: customType, actor, timestamp, repo, pages: pages.map(({title}) => title)}
80106
}
81107
//Commented on an issue
82108
case "IssueCommentEvent": {
@@ -85,7 +111,7 @@ export default async function({login, data, rest, q, account, imports}, {enabled
85111
const {issue: {user: {login: user}, title, number}, comment: {body: content, performed_via_github_app: mobile}} = payload
86112
if (!imports.filters.text(user, ignored))
87113
return null
88-
return {type: "comment", on: "issue", actor, timestamp, repo, content: await imports.markdown(content, {mode: markdown, codelines}), user, mobile, number, title}
114+
return {type: customType, on: "issue", actor, timestamp, repo, content: await imports.markdown(content, {mode: markdown, codelines}), user, mobile, number, title}
89115
}
90116
//Issue event
91117
case "IssuesEvent": {
@@ -94,7 +120,7 @@ export default async function({login, data, rest, q, account, imports}, {enabled
94120
const {action, issue: {user: {login: user}, title, number, body: content}} = payload
95121
if (!imports.filters.text(user, ignored))
96122
return null
97-
return {type: "issue", actor, timestamp, repo, action, user, number, title, content: await imports.markdown(content, {mode: markdown, codelines})}
123+
return {type: customType, actor, timestamp, repo, action, user, number, title, content: await imports.markdown(content, {mode: markdown, codelines})}
98124
}
99125
//Activity from repository collaborators
100126
case "MemberEvent": {
@@ -103,11 +129,11 @@ export default async function({login, data, rest, q, account, imports}, {enabled
103129
const {member: {login: user}} = payload
104130
if (!imports.filters.text(user, ignored))
105131
return null
106-
return {type: "member", actor, timestamp, repo, user}
132+
return {type: customType, actor, timestamp, repo, user}
107133
}
108134
//Made repository public
109135
case "PublicEvent": {
110-
return {type: "public", actor, timestamp, repo}
136+
return {type: customType, actor, timestamp, repo}
111137
}
112138
//Pull requests events
113139
case "PullRequestEvent": {
@@ -116,14 +142,14 @@ export default async function({login, data, rest, q, account, imports}, {enabled
116142
const {action, pull_request: {user: {login: user}, title, number, body: content, additions: added, deletions: deleted, changed_files: changed, merged}} = payload
117143
if (!imports.filters.text(user, ignored))
118144
return null
119-
return {type: "pr", actor, timestamp, repo, action: (action === "closed") && (merged) ? "merged" : action, user, title, number, content: await imports.markdown(content, {mode: markdown, codelines}), lines: {added, deleted}, files: {changed}}
145+
return {type: customType, actor, timestamp, repo, action: (action === "closed") && (merged) ? "merged" : action, user, title, number, content: await imports.markdown(content, {mode: markdown, codelines}), lines: {added, deleted}, files: {changed}}
120146
}
121147
//Reviewed a pull request
122148
case "PullRequestReviewEvent": {
123149
const {review: {state: review}, pull_request: {user: {login: user}, number, title}} = payload
124150
if (!imports.filters.text(user, ignored))
125151
return null
126-
return {type: "review", actor, timestamp, repo, review, user, number, title}
152+
return {type: customType, actor, timestamp, repo, review, user, number, title}
127153
}
128154
//Commented on a pull request
129155
case "PullRequestReviewCommentEvent": {
@@ -132,31 +158,36 @@ export default async function({login, data, rest, q, account, imports}, {enabled
132158
const {pull_request: {user: {login: user}, title, number}, comment: {body: content, performed_via_github_app: mobile}} = payload
133159
if (!imports.filters.text(user, ignored))
134160
return null
135-
return {type: "comment", on: "pr", actor, timestamp, repo, content: await imports.markdown(content, {mode: markdown, codelines}), user, mobile, number, title}
161+
return {type: customType, on: "pr", actor, timestamp, repo, content: await imports.markdown(content, {mode: markdown, codelines}), user, mobile, number, title}
136162
}
137163
//Pushed commits
138164
case "PushEvent": {
139-
let {size, commits, ref} = payload
140-
commits = commits.filter(({author: {email}}) => imports.filters.text(email, ignored))
165+
let {size, ref, head, before} = payload
166+
const [owner, repoName] = repo.split("/")
167+
168+
const res = await rest.repos.compareCommitsWithBasehead({owner, repo:repoName, basehead:`${before}...${head}`})
169+
let {commits} = res.data
170+
171+
commits = commits.filter(({author:{email}}) => imports.filters.text(email, ignored))
141172
if (!commits.length)
142173
return null
143-
if (commits.slice(-1).pop()?.message.startsWith("Merge branch "))
174+
if (commits.slice(-1).pop()?.commit.message.startsWith("Merge branch "))
144175
commits = commits.slice(-1)
145-
return {type: "push", actor, timestamp, repo, size, branch: ref.match(/refs.heads.(?<branch>.*)/)?.groups?.branch ?? null, commits: commits.reverse().map(({sha, message}) => ({sha: sha.substring(0, 7), message}))}
176+
return {type:customType, actor, timestamp, repo, size, branch: ref.match(/refs.heads.(?<branch>.*)/)?.groups?.branch ?? null, commits: commits.reverse().map(({sha, message}) => ({sha: sha.substring(0, 7), message}))}
146177
}
147178
//Released
148179
case "ReleaseEvent": {
149180
if (!["published"].includes(payload.action))
150181
return null
151182
const {action, release: {name, tag_name, prerelease, draft, body: content}} = payload
152-
return {type: "release", actor, timestamp, repo, action, name: name || tag_name, prerelease, draft, content: await imports.markdown(content, {mode: markdown, codelines})}
183+
return {type: customType, actor, timestamp, repo, action, name: name || tag_name, prerelease, draft, content: await imports.markdown(content, {mode: markdown, codelines})}
153184
}
154185
//Starred a repository
155186
case "WatchEvent": {
156187
if (!["started"].includes(payload.action))
157188
return null
158189
const {action} = payload
159-
return {type: "star", actor, timestamp, repo, action}
190+
return {type: customType, actor, timestamp, repo, action}
160191
}
161192
//Unknown event
162193
default: {
@@ -166,7 +197,6 @@ export default async function({login, data, rest, q, account, imports}, {enabled
166197
}),
167198
))
168199
.filter(event => event)
169-
.filter(event => filter.includes("all") || filter.includes(event.type))
170200
.slice(0, limit)
171201

172202
//Results

source/plugins/habits/index.mjs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,14 @@ export default async function({login, data, rest, imports, q, account}, {enabled
4747
const patches = [
4848
...await Promise.allSettled(
4949
commits
50-
.flatMap(({payload}) => payload.commits)
51-
.filter(({author}) => data.shared["commits.authoring"].filter(authoring => author?.login?.toLocaleLowerCase().includes(authoring) || author?.email?.toLocaleLowerCase().includes(authoring) || author?.name?.toLocaleLowerCase().includes(authoring)).length)
50+
.flatMap(({payload}) => payload?.commits ?? [])
51+
.filter(commit => {
52+
if (commit == null || typeof commit !== "object") return false
53+
// Safely check author property
54+
const author = commit?.author
55+
if (!author) return false
56+
return data.shared["commits.authoring"].filter(authoring => author?.login?.toLocaleLowerCase().includes(authoring) || author?.email?.toLocaleLowerCase().includes(authoring) || author?.name?.toLocaleLowerCase().includes(authoring)).length
57+
})
5258
.map(async commit => (await rest.request(commit)).data.files),
5359
),
5460
]

source/plugins/languages/analyzer/recent.mjs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export class RecentAnalyzer extends Analyzer {
3030
async patches() {
3131
//Fetch commits from recent activity
3232
this.debug(`fetching patches from last ${this.days || ""} days up to ${this.load || "∞"} events`)
33-
const commits = [], pages = Math.ceil((this.load || Infinity) / 100)
33+
const pages = Math.ceil((this.load || Infinity) / 100)
3434
if (this.context.mode === "repository") {
3535
try {
3636
const {data: {default_branch: branch}} = await this.rest.repos.get(this.context)
@@ -42,10 +42,11 @@ export class RecentAnalyzer extends Analyzer {
4242
this.debug(`failed to get default branch for ${this.context.owner}/${this.context.repo} (${error})`)
4343
}
4444
}
45+
const events = []
4546
try {
4647
for (let page = 1; page <= pages; page++) {
4748
this.debug(`fetching events page ${page}`)
48-
commits.push(
49+
events.push(
4950
...(await (this.context.mode === "repository" ? this.rest.activity.listRepoEvents(this.context) : this.rest.activity.listEventsForAuthenticatedUser({username: this.login, per_page: 100, page}))).data
5051
.filter(({type, payload}) => (type === "PushEvent") && ((this.context.mode !== "repository") || ((this.context.mode === "repository") && (payload?.ref?.includes?.(`refs/heads/${this.context.branch}`)))))
5152
.filter(({actor}) => (this.account === "organization") || (this.context.mode === "repository") ? true : !filters.text(actor.login, [this.login], {debug: false}))
@@ -57,16 +58,54 @@ export class RecentAnalyzer extends Analyzer {
5758
catch {
5859
this.debug("no more page to load")
5960
}
61+
this.debug(`fetched ${events.length} events`)
62+
63+
const wanted = new Map()
64+
events.forEach(event => {
65+
let key = `${event.repo.name}@${event.payload.ref}`
66+
let item = wanted.get(key) ?? { commits: [] }
67+
item.repo = event.repo.name
68+
item.ref = event.payload.ref
69+
item.commits.push(event.payload.before)
70+
item.commits.push(event.payload.head)
71+
wanted.set(key, item)
72+
})
73+
74+
const commits = []
75+
for (const item of wanted.values()) {
76+
try {
77+
for (let page = 1; page <= pages; page++) {
78+
this.debug(`fetching commits page ${page}`)
79+
this.debug(`https://api.github.com/repos/${item.repo}/commits?sha=${item.ref}&per_page=20&page=${page}`)
80+
commits.push(
81+
...(await this.rest.request(`https://api.github.com/repos/${item.repo}/commits?sha=${item.ref}&per_page=20&page=${page}`)).data
82+
.map(x => {
83+
item.commits = item.commits.filter(c => c !== x.sha)
84+
return x
85+
})
86+
.filter(({ committer }) => (this.account === "organization") || (this.context.mode === "repository") ? true : !filters.text(committer.login, [this.login], { debug: false }))
87+
.filter(({ commit }) => ((!this.days) || (new Date(commit.committer.date) > new Date(Date.now() - this.days * 24 * 60 * 60 * 1000)))),
88+
)
89+
if (item.commits < 1) {
90+
this.debug("found expected commits")
91+
break
92+
}
93+
}
94+
}
95+
catch {
96+
this.debug("no more page to load")
97+
}
98+
}
99+
60100
this.debug(`fetched ${commits.length} commits`)
61-
this.results.latest = Math.round((new Date().getTime() - new Date(commits.slice(-1).shift()?.created_at).getTime()) / (1000 * 60 * 60 * 24))
101+
this.results.latest = Math.round((new Date().getTime() - new Date(events.slice(-1).shift()?.created_at).getTime()) / (1000 * 60 * 60 * 24))
62102
this.results.commits = commits.length
63103

64104
//Retrieve edited files and filter edited lines (those starting with +/-) from patches
65105
this.debug("fetching patches")
66106
const patches = [
67107
...await Promise.allSettled(
68108
commits
69-
.flatMap(({payload}) => payload.commits)
70109
.filter(({committer}) => filters.text(committer?.email, this.authoring, {debug: false}))
71110
.map(commit => commit.url)
72111
.map(async commit => (await this.rest.request(commit)).data),
@@ -75,9 +114,9 @@ export class RecentAnalyzer extends Analyzer {
75114
.filter(({status}) => status === "fulfilled")
76115
.map(({value}) => value)
77116
.filter(({parents}) => parents.length <= 1)
78-
.map(({sha, commit: {message, committer}, verification, files}) => ({
117+
.map(({sha, commit: {message, author}, verification, files}) => ({
79118
sha,
80-
name: `${message} (authored by ${committer.name} on ${committer.date})`,
119+
name: `${message} (authored by ${author.name} on ${author.date})`,
81120
verified: verification?.verified ?? null,
82121
editions: files.map(({filename, patch = ""}) => {
83122
const edition = {

source/plugins/lines/index.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export default async function({login, data, imports, rest, q, account}, {enabled
4444
return
4545
//Compute changes
4646
repos[handle] = {added: 0, deleted: 0, changed: 0}
47-
const contributors = stats.filter(({author}) => (context.mode === "repository") || (context.mode === "organization") ? true : author?.login?.toLocaleLowerCase() === login.toLocaleLowerCase())
47+
const contributors = stats.filter(({author} = {}) => (context.mode === "repository") || (context.mode === "organization") ? true : author?.login?.toLocaleLowerCase() === login.toLocaleLowerCase())
4848
for (const contributor of contributors) {
4949
let added = 0, changed = 0, deleted = 0
5050
contributor.weeks.forEach(({a = 0, d = 0, c = 0, w}) => {

source/plugins/notable/index.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export default async function({login, q, imports, rest, graphql, data, account,
109109
console.debug(`metrics/compute/${login}/plugins > notable > aggregating results`)
110110
const aggregated = new Map()
111111
for (const {name, handle, avatar, organization = handle.split("/").shift() ?? "", stars, ..._extras} of contributions) {
112-
const key = repositories ? handle : name
112+
const key = !organization || repositories ? handle : name;
113113
if (aggregated.has(key)) {
114114
const aggregate = aggregated.get(key)
115115
aggregate.aggregated++

0 commit comments

Comments
 (0)