feat(git): add commit information

resolves #3331
This commit is contained in:
Jan De Dobbeleer 2023-01-08 20:31:44 +01:00 committed by Jan De Dobbeleer
parent a627be6b64
commit b8c09f92ab
3 changed files with 153 additions and 0 deletions

View file

@ -6,6 +6,7 @@ import (
"path/filepath"
"strconv"
"strings"
"time"
"github.com/jandedobbeleer/oh-my-posh/src/platform"
"github.com/jandedobbeleer/oh-my-posh/src/properties"
@ -14,6 +15,19 @@ import (
"gopkg.in/ini.v1"
)
type Commit struct {
// git log -1 --pretty="format:%an%n%ae%n%cn%n%ce%n%at%n%s"
Author *User
Committer *User
Subject string
Timestamp time.Time
}
type User struct {
Name string
Email string
}
// GitStatus represents part of the status of a git repository
type GitStatus struct {
ScmStatus
@ -119,6 +133,8 @@ type Git struct {
poshgit bool
stashCount int
worktreeCount int
commit *Commit
}
func (g *Git) Template() string {
@ -160,6 +176,43 @@ func (g *Git) Enabled() bool {
return true
}
func (g *Git) Commit() *Commit {
if g.commit != nil {
return g.commit
}
g.commit = &Commit{
Author: &User{},
Committer: &User{},
}
commitBody := g.getGitCommandOutput("log", "-1", "--pretty=format:an:%an%nae:%ae%ncn:%cn%nce:%ce%nat:%at%nsu:%s")
splitted := strings.Split(strings.TrimSpace(commitBody), "\n")
for _, line := range splitted {
line = strings.TrimSpace(line)
if len(line) <= 3 {
continue
}
anchor := line[:3]
line = line[3:]
switch anchor {
case "an:":
g.commit.Author.Name = line
case "ae:":
g.commit.Author.Email = line
case "cn:":
g.commit.Committer.Name = line
case "ce:":
g.commit.Committer.Email = line
case "at:":
if t, err := strconv.ParseInt(line, 10, 64); err == nil {
g.commit.Timestamp = time.Unix(t, 0)
}
case "su:":
g.commit.Subject = line
}
}
return g.commit
}
func (g *Git) StashCount() int {
if g.poshgit || g.stashCount != 0 {
return g.stashCount

View file

@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"
"testing"
"time"
"github.com/jandedobbeleer/oh-my-posh/src/mock"
"github.com/jandedobbeleer/oh-my-posh/src/platform"
@ -892,3 +893,85 @@ func TestGitIgnoreSubmodules(t *testing.T) {
assert.Equal(t, tc.Expected, got, tc.Case)
}
}
func TestGitCommit(t *testing.T) {
cases := []struct {
Case string
Expected *Commit
Output string
}{
{
Case: "Clean commit",
Output: `
an:Jan De Dobbeleer
ae:jan@ohmyposh.dev
cn:Jan De Dobbeleer
ce:jan@ohmyposh.dev
at:1673176335
su:docs(error): you can't use cross segment properties
`,
Expected: &Commit{
Author: &User{
Name: "Jan De Dobbeleer",
Email: "jan@ohmyposh.dev",
},
Committer: &User{
Name: "Jan De Dobbeleer",
Email: "jan@ohmyposh.dev",
},
Subject: "docs(error): you can't use cross segment properties",
Timestamp: time.Unix(1673176335, 0),
},
},
{
Case: "No commit output",
Expected: &Commit{
Author: &User{},
Committer: &User{},
},
},
{
Case: "No author",
Output: `
an:
ae:
cn:Jan De Dobbeleer
ce:jan@ohmyposh.dev
at:1673176335
su:docs(error): you can't use cross segment properties
`,
Expected: &Commit{
Author: &User{},
Committer: &User{
Name: "Jan De Dobbeleer",
Email: "jan@ohmyposh.dev",
},
Subject: "docs(error): you can't use cross segment properties",
Timestamp: time.Unix(1673176335, 0),
},
},
{
Case: "Bad timestamp",
Output: `
at:err
`,
Expected: &Commit{
Author: &User{},
Committer: &User{},
},
},
}
for _, tc := range cases {
env := new(mock.MockedEnvironment)
env.MockGitCommand("", tc.Output, "log", "-1", "--pretty=format:an:%an%nae:%ae%ncn:%cn%nce:%ce%nat:%at%nsu:%s")
g := &Git{
scm: scm{
env: env,
command: "git",
},
}
got := g.Commit()
assert.Equal(t, tc.Expected, got, tc.Case)
}
}

View file

@ -145,6 +145,7 @@ You can set the following properties to `true` to enable fetching additional inf
| `.IsBare` | `boolean` | if in a bare repo or not, only set when `fetch_bare_info` is set to `true` |
| `.Dir` | `string` | the repository's root directory |
| `.Kraken` | `string` | a link to the current HEAD in [GitKraken][kraken-ref] for use in [hyperlinks][hyperlinks] in templates `{{ url .HEAD .Kraken }}` |
| `.Commit` | `Commit` | HEAD commit information (see below) |
### GitStatus
@ -158,6 +159,22 @@ You can set the following properties to `true` to enable fetching additional inf
| `.Changed` | `boolean` | if the status contains changes or not |
| `.String` | `string` | a string representation of the changes above |
### Commit
| Name | Type | Description |
| ------------ | ----------- | -------------------------------------- |
| `.Author` | `User` | the author or the commit (see below) |
| `.Committer` | `User` | the comitter or the commit (see below) |
| `.Subject` | `string` | the commit subject |
| `.Timestamp` | `time.Time` | the commit timestamp |
### User
| Name | Type | Description |
| -------- | -------- | ---------------- |
| `.Name` | `string` | the user's name |
| `.Email` | `string` | the user's email |
Local changes use the following syntax:
| Icon | Description |