diff --git a/metrics-collector/src/index.ts b/metrics-collector/src/index.ts index f806323..0c8a2c0 100644 --- a/metrics-collector/src/index.ts +++ b/metrics-collector/src/index.ts @@ -10,7 +10,7 @@ import { collectSonatypeMetrics, saveSonatypeMetrics, } from "./sonatype-metrics"; -import { getYesterdayDate, readJsonFile } from "./utils"; +import { getRelativeDate, getYesterdayDate, readJsonFile } from "./utils"; import { readFile, writeFile } from "fs/promises"; import { existsSync, mkdirSync } from "fs"; import { addDays, addMonths, startOfDay } from "date-fns"; @@ -27,6 +27,7 @@ interface Arguments { "collect-gh": boolean; "collect-npm": boolean; "collect-sonatype": boolean; + "relative-date": string; "initial-load-from": string; "initial-load-to": string; "initial-load-state": string; @@ -48,6 +49,12 @@ const argv = yargs(hideBin(process.argv)).options({ description: "Collect Sonatype metrics", default: false, }, + "relative-date": { + type: "string", + description: + "Collect metrics from this relative date (e.g., 7d, 1mo, 2w). Accept durations: y, mo, w, d, h, min, s", + default: "1d", + }, "initial-load-from": { type: "string", description: @@ -86,18 +93,16 @@ async function main() { // by default the metric date is yesterday, because stats services // usually provide data for everything until the previous day - const metricDateStr = getYesterdayDate(); + const relativeDateArg = argv["relative-date"]; + const relativeMetricDate = getRelativeDate(relativeDateArg); - const metricDate = new Date( - `${initialLoadTo ?? metricDateStr}T12:00:00.000Z` - ); + const metricDate = initialLoadTo + ? new Date(`${initialLoadTo}T12:00:00.000Z`) + : relativeMetricDate; const initialLoadFromDate = initialLoadFrom ? new Date(`${initialLoadFrom}T12:00:00.000Z`) : undefined; - const initialLoadToDate = initialLoadTo - ? new Date(`${initialLoadTo}T12:00:00.000Z`) - : undefined; const initialLoadState = argv["initial-load-state"]; diff --git a/metrics-collector/src/npm-metrics.ts b/metrics-collector/src/npm-metrics.ts index 7dd1efd..88413cf 100644 --- a/metrics-collector/src/npm-metrics.ts +++ b/metrics-collector/src/npm-metrics.ts @@ -46,7 +46,7 @@ export const collectNpmMetrics = async (metricDate: Date) => { await postNpmMetrics({ pkg, - metricDate: new Date(metricDate), + metricDate: new Date(`${metricDateStr}T00:00:00.000Z`), totalDownloads: totalDownloads, dailyDownloads: dailyDownloads, }); diff --git a/metrics-collector/src/utils.ts b/metrics-collector/src/utils.ts index d8ded79..81eb10a 100644 --- a/metrics-collector/src/utils.ts +++ b/metrics-collector/src/utils.ts @@ -1,5 +1,6 @@ import * as fs from "fs"; -import { subDays, format } from "date-fns"; +import { subDays, format, sub } from "date-fns"; +import type { Duration } from "date-fns"; // Read JSON data from the file export function readJsonFile(filePath: string): any { @@ -73,3 +74,51 @@ export async function fetchWithRetry( } throw new Error("Max retries reached"); } + +export function getRelativeDate(durationStr: string): Date { + const duration = createDuration(durationStr); + return sub(new Date(), duration); +} + +export function createDuration(input: string): Duration { + const regex = /^-?(\d+)(y|mo|w|d|h|min|s)$/; + const match = input.match(regex); + + if (!match) { + throw new Error( + "Invalid duration format. Use formats like 7d, -1mo, 5y, 2w, 3h, 30min, 45s" + ); + } + + const [, amount, unit] = match; + const value = parseInt(amount, 10); + const duration: Duration = {}; + + switch (unit) { + case "y": + duration.years = value; + break; + case "mo": + duration.months = value; + break; + case "w": + duration.weeks = value; + break; + case "d": + duration.days = value; + break; + case "h": + duration.hours = value; + break; + case "min": + duration.minutes = value; + break; + case "s": + duration.seconds = value; + break; + default: + throw new Error("Invalid duration unit"); + } + + return duration; +}