Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Projects: when each was last pushed, and how active it is lately | 1 | /** |
| 2 | * How active a project is lately, for sorting a workspace's projects: each | |
| 3 | * push, issue or pull request opened or closed, review, comment and | |
| 4 | * deployment adds one, and what came before counts for half as much every | |
| 5 | * week. Kept as a score and the time it was last raised, so raising it is | |
| 6 | * one row's update. Pure, so it is tested apart from the service. | |
| 7 | */ | |
| 8 | ||
| 9 | import type { EventType } from "@g1t/contracts"; | |
| 10 | ||
| 11 | /** What happens to a project's code and work that counts as activity. */ | |
| 12 | export const ACTIVE: ReadonlySet<EventType> = new Set<EventType>([ | |
| 13 | "git.push", | |
| 14 | "issue.opened", | |
| 15 | "issue.closed", | |
| 16 | "issue.reopened", | |
| 17 | "pull.opened", | |
| 18 | "pull.updated", | |
| 19 | "pull.merged", | |
| 20 | "pull.closed", | |
| 21 | "review.completed", | |
| 22 | "comment.created", | |
| 23 | "deployment.succeeded", | |
| 24 | "deployment.failed", | |
| 25 | ]); | |
| 26 | ||
| 27 | /** How long until activity counts for half. */ | |
| 28 | export const HALF_LIFE_MS = 7 * 24 * 60 * 60 * 1000; | |
| 29 | ||
| 30 | /** The score `score` raised at `lastAt` is worth at `at` (RFC 3339 times). */ | |
| 31 | export function decayed(score: number, lastAt: string | null, at: string): number { | |
| 32 | if (!lastAt || !(score > 0)) return 0; | |
| 33 | const elapsed = Date.parse(at) - Date.parse(lastAt); | |
| 34 | if (!Number.isFinite(elapsed)) return 0; | |
| 35 | // Events delivered out of order count in full: never worth more than they were. | |
| 36 | return score * Math.pow(0.5, Math.max(0, elapsed) / HALF_LIFE_MS); | |
| 37 | } | |
| 38 | ||
| 39 | /** The score and its time after one more piece of activity at `at`. */ | |
| 40 | export function raised(score: number, lastAt: string | null, at: string): { score: number; at: string } { | |
| 41 | const later = !lastAt || Date.parse(at) >= Date.parse(lastAt) ? at : lastAt; | |
| 42 | return { score: decayed(score, lastAt, later) + 1, at: later }; | |
| 43 | } |