Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,20 +91,21 @@ Each column is responsive as its row is stretched vertically or horizontally.

The array of `GitLogEntry` objects is the source of data used by the `GitLog` component. It has the following properties:

| Property | Type | Description |
|-----------------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| `hash` | `string` | The unique hash identifier of the commit. |
| `branch` | `string` | The name of the branch this commit belongs to. |
| `parents` | `string[]` | An array of parent commit hashes. If this is a merge commit, it will have multiple parents. If it's an initial commit, it will have none. |
| `message` | `string` | The commit message describing the changes made in this commit. |
| `committerDate` | `string` | The date and time when the commit was applied by the committer. Typically the timestamp when the commit was finalized. |
| `authorDate` | `string?` | *(Optional)* The date and time when the commit was originally authored. May differ from `committerDate` if the commit was rebased or amended. |
| Property | Type | Description |
|-----------------|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| `hash` | `string` | The unique hash identifier of the commit. |
| `branch` | `string` | The name of the branch this commit belongs to. |
| `parents` | `string[]` | An array of parent commit hashes. If this is a merge commit, it will have multiple parents. If it's an initial commit, it will have none. |
| `message` | `string` | The commit message describing the changes made in this commit. |
| `author` | `CommitAuthor?` | Details of the user who authored the commit. |
| `committerDate` | `string` | The date and time when the commit was applied by the committer. Typically the timestamp when the commit was finalized. |
| `authorDate` | `string?` | *(Optional)* The date and time when the commit was originally authored. May differ from `committerDate` if the commit was rebased or amended. |

> [!TIP]
> Usually you'd be sourcing this data from a backend service like a web-api, but you can extract it from the command line with the following command.

```bash
git log --all --pretty=format:'hash:%h,parents:%p,branch:%S,msg:%s,cdate:%cd,adate:%ad' --date=iso >> git-log.txt
git log --all --pretty=format:'hash:%h,parents:%p,branch:%S,msg:%s,cdate:%cd,adate:%ad,author:%an,email:%ae' --date=iso >> git-log.txt
```

This will write `git-log.txt` in the directory where you ran the command. It can be passed to the `parseGitLog.ts` function from the library to produce an array of `GitLogEntry`.
Expand Down
1,234 changes: 617 additions & 617 deletions packages/demo/public/advent-of-code-2019.txt

Large diffs are not rendered by default.

4,120 changes: 2,060 additions & 2,060 deletions packages/demo/public/learn-japanese.txt

Large diffs are not rendered by default.

945 changes: 473 additions & 472 deletions packages/demo/public/sleep.txt

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion packages/demo/src/utils/gitLogParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { GitLogEntry } from '@tomplum/react-git-log'
export const parseGitLogOutput = (output: string): GitLogEntry[] => {
const commits = output.trim().split('\n')
const logRegex =
/^hash:(?<hash>\S+),parents:(?<parents>.*?),branch:(?<branch>\S*),msg:(?<message>.+),cdate:(?<committerDate>[\d\- :+]+),adate:(?<authorDate>[\d\- :+]+)/
/^hash:(?<hash>\S+),parents:(?<parents>.*?),branch:(?<branch>\S*),msg:(?<message>.+),cdate:(?<committerDate>[\d\- :+]+),adate:(?<authorDate>[\d\- :+]+),author:(?<author>.+),email:(?<email>.+)/

return commits
.map(commit => {
Expand All @@ -17,6 +17,13 @@ export const parseGitLogOutput = (output: string): GitLogEntry[] => {
message: match.groups.message,
committerDate: match.groups.committerDate.trim(),
authorDate: match.groups.authorDate.trim(),
author:
match.groups.author || match.groups.email
? {
name: match.groups.author?.trim() || undefined,
email: match.groups.email?.trim() || undefined,
}
: undefined
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/library/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@tomplum/react-git-log",
"repository": "https://github.com/TomPlum/react-git-log",
"description": "A flexible, themable, React component for visualising Git commit history, branch and tag metadata.",
"version": "1.0.1",
"version": "1.1.0",
"type": "module",
"main": "dist/react-git-log.umd.js",
"module": "dist/react-git-log.es.js",
Expand Down
20 changes: 18 additions & 2 deletions packages/library/src/GitLog.integration.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { parseGitLogOutput } from 'test/data/gitLogParser'
import { sleepRepositoryRowColumnState } from 'test/data/sleepState'
import { GraphColumnState } from 'modules/Graph/components/GraphColumn'
import { graphColumn } from 'test/elements/GraphColumn'
import { describe } from 'vitest'
import { afterEach, beforeEach, describe } from 'vitest'
import { render, within } from '@testing-library/react'
import { GitLog } from './GitLog'
import { sleepCommits } from 'test/data/sleepCommits'
Expand All @@ -15,6 +15,17 @@ import { table } from 'test/elements/Table'
import dayjs from 'dayjs'

describe('Integration', () => {
const today = new Date(2025, 2, 24, 18, 0, 0)

beforeEach(() => {
vi.useFakeTimers()
vi.setSystemTime(today)
})

afterEach(() => {
vi.useRealTimers()
})

const prepareCommits = (commits: Commit[]) => {
const tagsSeen = new Map<string, boolean>()

Expand Down Expand Up @@ -83,6 +94,7 @@ describe('Integration', () => {
expect(indexTableRow).toBeInTheDocument()
expect(table.commitMessageData({ row: 0 })).toHaveTextContent('// Work in-progress in TomPlum/sleep...')
expect(table.timestampData({ row: 0 })).toHaveTextContent('-')
expect(table.authorData({ row: 0 })).toHaveTextContent('-')

// The row/column state is from index 1 on-wards,
// since the index pseudo-commit is rendered separately.
Expand Down Expand Up @@ -180,12 +192,16 @@ describe('Integration', () => {
// Check table state
const tableRowElement = table.row({ row: rowIndex })
expect(tableRowElement).toBeInTheDocument()

expect(table.commitMessageData({ row: rowIndex })).toHaveTextContent(commit.message)

expect(table.authorData({ row: rowIndex })).toHaveTextContent(commit?.author?.name ?? '-')

if (rowIndex > 1) {
expect(table.timestampData({ row: rowIndex })).toHaveTextContent(formatTimestamp(commit.committerDate))
} else {
expect(table.timestampData({ row: 1 })).toHaveTextContent('4 days ago')
// The first commit is an hour ago relative to the stubbed current time
expect(table.timestampData({ row: 1 })).toHaveTextContent('an hour ago')
}
})

Expand Down
20 changes: 14 additions & 6 deletions packages/library/src/_test/data/gitLogParser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,24 @@ import { parseGitLogOutput } from './gitLogParser'
describe('gitLogParser', () => {
it('parses valid git log output', () => {
const input = `
hash:be2b8a8,parents:1352f4c,branch:refs/remotes/origin/renovate/all-minor-patch,msg:fix(deps): update all non-major dependencies,cdate:2025-03-20 02:44:38 +0000,adate:2025-03-20 02:44:38 +0000
hash:c88f0b9,parents:786b044,branch:refs/heads/develop,msg:feat(highlights): cleaned up effect function,cdate:2025-03-07 20:42:31 +0000,adate:2025-03-07 20:42:31 +0000
`
hash:2079fb6,parents:1352f4c,branch:refs/remotes/origin/renovate/all-minor-patch,msg:fix(deps): update all non-major dependencies,cdate:2025-03-24 17:03:58 +0000,adate:2025-03-24 17:03:58 +0000,author:renovate[bot],email:29139614+renovate[bot]@users.noreply.github.com
hash:c88f0b9,parents:786b044,branch:refs/heads/develop,msg:feat(highlights): cleaned up effect function,cdate:2025-03-07 20:42:31 +0000,adate:2025-03-07 20:42:31 +0000,author:Thomas Plumpton,email:Thomas.Plumpton@hotmail.co.uk
`

const result = parseGitLogOutput(input.trim())

expect(result).toEqual([
{
hash: 'be2b8a8',
hash: '2079fb6',
parents: ['1352f4c'],
branch: 'refs/remotes/origin/renovate/all-minor-patch',
message: 'fix(deps): update all non-major dependencies',
committerDate: '2025-03-20 02:44:38 +0000',
authorDate: '2025-03-20 02:44:38 +0000',
committerDate: '2025-03-24 17:03:58 +0000',
authorDate: '2025-03-24 17:03:58 +0000',
author: {
email: '29139614+renovate[bot]@users.noreply.github.com',
name: 'renovate[bot]',
},
},
{
hash: 'c88f0b9',
Expand All @@ -26,6 +30,10 @@ hash:c88f0b9,parents:786b044,branch:refs/heads/develop,msg:feat(highlights): cle
message: 'feat(highlights): cleaned up effect function',
committerDate: '2025-03-07 20:42:31 +0000',
authorDate: '2025-03-07 20:42:31 +0000',
author: {
email: 'Thomas.Plumpton@hotmail.co.uk',
name: 'Thomas Plumpton',
},
}
])
})
Expand Down
9 changes: 8 additions & 1 deletion packages/library/src/_test/data/gitLogParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { GitLogEntry } from 'types'
export const parseGitLogOutput = (output: string): GitLogEntry[] => {
const commits = output.trim().split('\n')
const logRegex =
/^hash:(?<hash>\S+),parents:(?<parents>.*?),branch:(?<branch>\S*),msg:(?<message>.+),cdate:(?<committerDate>[\d\- :+]+),adate:(?<authorDate>[\d\- :+]+)/
/^hash:(?<hash>\S+),parents:(?<parents>.*?),branch:(?<branch>\S*),msg:(?<message>.+),cdate:(?<committerDate>[\d\- :+]+),adate:(?<authorDate>[\d\- :+]+),author:(?<author>.+),email:(?<email>.+)/

if (output.length === 0) {
return []
Expand All @@ -23,6 +23,13 @@ export const parseGitLogOutput = (output: string): GitLogEntry[] => {
message: match.groups.message,
committerDate: match.groups.committerDate.trim(),
authorDate: match.groups.authorDate.trim(),
author:
match.groups.author || match.groups.email
? {
name: match.groups.author?.trim() || undefined,
email: match.groups.email?.trim() || undefined,
}
: undefined
}
}

Expand Down
Loading