diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b3206dde..a76a10d28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added ask sidebar to homepage. [#721](https://github.com/sourcebot-dev/sourcebot/pull/721) - Added endpoint for searching commit history for a git repository. [#625](https://github.com/sourcebot-dev/sourcebot/pull/625) +- Added `pushedAt` field to the Repo table to track when a repository last was committed to across all branches. [#790](https://github.com/sourcebot-dev/sourcebot/pull/790) ## [4.10.17] - 2026-01-23 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..f95cf5baa --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,19 @@ +# Claude Code Guidelines + +## Database Migrations + +When creating Prisma database migrations, run from the repository root: + +```bash +yarn dev:prisma:migrate:dev --name +``` + +Do NOT use `npx prisma migrate dev` directly from packages/db. + +## Building Packages + +To build a specific package: + +```bash +yarn workspace @sourcebot/ build +``` diff --git a/packages/backend/src/git.ts b/packages/backend/src/git.ts index cc99e2837..4fa43ac8a 100644 --- a/packages/backend/src/git.ts +++ b/packages/backend/src/git.ts @@ -369,3 +369,39 @@ export const getLocalDefaultBranch = async ({ return undefined; } } + +/** + * Gets the timestamp of the most recent commit across all branches. + * + * @returns The Date of the most recent commit, or undefined if the repository + * is empty or if there's an error retrieving the timestamp. + */ +export const getLatestCommitTimestamp = async ({ + path, +}: { + path: string, +}): Promise => { + const git = createGitClientForPath(path); + + try { + // git log --all -1 --format=%aI returns the author date of the most recent commit + // across all branches in ISO 8601 format + const result = await git.raw(['log', '--all', '-1', '--format=%aI']); + const trimmed = result.trim(); + + if (!trimmed) { + return undefined; // Empty repository + } + + const date = new Date(trimmed); + if (isNaN(date.getTime())) { + logger.warn(`Failed to parse commit timestamp: ${trimmed}`); + return undefined; + } + + return date; + } catch (error) { + logger.debug(`Failed to get latest commit timestamp for ${path}:`, error); + return undefined; + } +} diff --git a/packages/backend/src/repoIndexManager.ts b/packages/backend/src/repoIndexManager.ts index 9f03c1d2b..8e499863a 100644 --- a/packages/backend/src/repoIndexManager.ts +++ b/packages/backend/src/repoIndexManager.ts @@ -8,7 +8,7 @@ import { Job, Queue, ReservedJob, Worker } from "groupmq"; import { Redis } from 'ioredis'; import micromatch from 'micromatch'; import { GROUPMQ_WORKER_STOP_GRACEFUL_TIMEOUT_MS, INDEX_CACHE_DIR } from './constants.js'; -import { cloneRepository, fetchRepository, getBranches, getCommitHashForRefName, getLocalDefaultBranch, getTags, isPathAValidGitRepoRoot, unsetGitConfig, upsertGitConfig } from './git.js'; +import { cloneRepository, fetchRepository, getBranches, getCommitHashForRefName, getLatestCommitTimestamp, getLocalDefaultBranch, getTags, isPathAValidGitRepoRoot, unsetGitConfig, upsertGitConfig } from './git.js'; import { captureEvent } from './posthog.js'; import { PromClient } from './promClient.js'; import { RepoWithConnections, Settings } from "./types.js"; @@ -489,6 +489,8 @@ export class RepoIndexManager { refName: 'HEAD', }); + const pushedAt = await getLatestCommitTimestamp({ path: repoPath }); + const jobMetadata = repoIndexingJobMetadataSchema.parse(jobData.metadata); const repo = await this.db.repo.update({ @@ -496,6 +498,7 @@ export class RepoIndexManager { data: { indexedAt: new Date(), indexedCommitHash: commitHash, + pushedAt: pushedAt, metadata: { ...(jobData.repo.metadata as RepoMetadata), indexedRevisions: jobMetadata.indexedRevisions, diff --git a/packages/db/prisma/migrations/20260124232658_add_pushed_at_to_repo/migration.sql b/packages/db/prisma/migrations/20260124232658_add_pushed_at_to_repo/migration.sql new file mode 100644 index 000000000..b9da84355 --- /dev/null +++ b/packages/db/prisma/migrations/20260124232658_add_pushed_at_to_repo/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Repo" ADD COLUMN "pushedAt" TIMESTAMP(3); diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index fc6418eea..6c0affcce 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -68,6 +68,7 @@ model Repo { indexedAt DateTime? /// When the repo was last indexed successfully. indexedCommitHash String? /// The commit hash of the last indexed commit (on HEAD). latestIndexingJobStatus RepoIndexingJobStatus? /// The status of the latest indexing job. + pushedAt DateTime? /// The timestamp of the most recent commit across all branches. external_id String /// The id of the repo in the external service external_codeHostType CodeHostType /// The type of the external service (e.g., github, gitlab, etc.)