From e7a102ee45ab9bd75a2a884f9c85d9c7c376a4d0 Mon Sep 17 00:00:00 2001 From: Arunavo Ray Date: Fri, 24 Oct 2025 08:42:14 +0530 Subject: [PATCH] mirror: show github timestamps in metadata --- src/lib/gitea.ts | 19 +++++++++++++++---- src/lib/utils.test.ts | 14 +++++++++++++- src/lib/utils.ts | 9 +++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/lib/gitea.ts b/src/lib/gitea.ts index a7e64e3..e246c1c 100644 --- a/src/lib/gitea.ts +++ b/src/lib/gitea.ts @@ -12,6 +12,7 @@ import { createMirrorJob } from "./helpers"; import { db, organizations, repositories } from "./db"; import { eq, and } from "drizzle-orm"; import { decryptConfigTokens } from "./utils/config-encryption"; +import { formatDateShort } from "./utils"; /** * Helper function to get organization configuration including destination override @@ -1646,11 +1647,15 @@ export const mirrorGitRepoIssuesToGitea = async ({ .join(", ")} on GitHub.` : ""; + const issueAuthor = issue.user?.login ?? "unknown"; + const issueCreatedOn = formatDateShort(issue.created_at); + const issueOriginHeader = `Originally created by @${issueAuthor} on GitHub${ + issueCreatedOn ? ` (${issueCreatedOn})` : "" + }.`; + const issuePayload: any = { title: issue.title, - body: `Originally created by @${ - issue.user?.login - } on GitHub.${originalAssignees}\n\n${issue.body || ""}`, + body: `${issueOriginHeader}${originalAssignees}\n\n${issue.body ?? ""}`, closed: issue.state === "closed", labels: giteaLabelIds, }; @@ -1690,10 +1695,16 @@ export const mirrorGitRepoIssuesToGitea = async ({ await processWithRetry( sortedComments, async (comment) => { + const commenter = comment.user?.login ?? "unknown"; + const commentDate = formatDateShort(comment.created_at); + const commentHeader = `@${commenter} commented on GitHub${ + commentDate ? ` (${commentDate})` : "" + }:`; + await httpPost( `${config.giteaConfig!.url}/api/v1/repos/${giteaOwner}/${repoName}/issues/${createdIssue.data.number}/comments`, { - body: `@${comment.user?.login} commented on GitHub:\n\n${comment.body}`, + body: `${commentHeader}\n\n${comment.body ?? ""}`, }, { Authorization: `token ${decryptedConfig.giteaConfig!.token}`, diff --git a/src/lib/utils.test.ts b/src/lib/utils.test.ts index a71ed85..7d7ac5a 100644 --- a/src/lib/utils.test.ts +++ b/src/lib/utils.test.ts @@ -1,5 +1,5 @@ import { describe, test, expect } from "bun:test"; -import { jsonResponse, formatDate, truncate, safeParse, parseErrorMessage, showErrorToast } from "./utils"; +import { jsonResponse, formatDate, formatDateShort, truncate, safeParse, parseErrorMessage, showErrorToast } from "./utils"; describe("jsonResponse", () => { test("creates a Response with JSON content", () => { @@ -65,6 +65,18 @@ describe("formatDate", () => { }); }); +describe("formatDateShort", () => { + test("returns formatted date when input is provided", () => { + const formatted = formatDateShort("2014-10-20T15:32:10Z"); + expect(formatted).toBe("Oct 20, 2014"); + }); + + test("returns undefined when date is missing", () => { + expect(formatDateShort(null)).toBeUndefined(); + expect(formatDateShort(undefined)).toBeUndefined(); + }); +}); + describe("truncate", () => { test("truncates a string that exceeds the length", () => { const str = "This is a long string that needs truncation"; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index e674517..810edee 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -29,6 +29,15 @@ export function formatDate(date?: Date | string | null): string { }).format(new Date(date)); } +export function formatDateShort(date?: Date | string | null): string | undefined { + if (!date) return undefined; + return new Intl.DateTimeFormat("en-US", { + year: "numeric", + month: "short", + day: "numeric", + }).format(new Date(date)); +} + export function formatLastSyncTime(date: Date | string | null): string { if (!date) return "Never";