1
0
Fork 0
forked from forgejo/forgejo

Multiple GitGraph improvements: Exclude PR heads, Add branch/PR links, Show only certain branches, (#12766)

* Multiple GitGraph improvements.

Add backend support for excluding PRs, selecting branches and files.

Fix #10327

Signed-off-by: Andrew Thornton <art27@cantab.net>

* as per @silverwind

Signed-off-by: Andrew Thornton <art27@cantab.net>

* as per @silverwind

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Only show refs in dropdown we display on the graph

Signed-off-by: Andrew Thornton <art27@cantab.net>

* as per @silverwind

Signed-off-by: Andrew Thornton <art27@cantab.net>

* use flexbox for ui header

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Move Hide Pull Request button to the dropdown

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Add SHA and user pictures

Signed-off-by: Andrew Thornton <art27@cantab.net>

* fix test

Signed-off-by: Andrew Thornton <art27@cantab.net>

* fix test 2

Signed-off-by: Andrew Thornton <art27@cantab.net>

* fixes

* async

* more tweaks

* use tabs in tmpl

Signed-off-by: Andrew Thornton <art27@cantab.net>

* remove commented thing

Signed-off-by: Andrew Thornton <art27@cantab.net>

* fix linting

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Update web_src/js/features/gitgraph.js

Co-authored-by: silverwind <me@silverwind.io>

* graph tweaks

* more tweaks

* add title

Signed-off-by: Andrew Thornton <art27@cantab.net>

* fix loading indicator z-index and position

Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
Co-authored-by: Lauris BH <lauris@nix.lv>
This commit is contained in:
zeripath 2020-11-08 17:21:54 +00:00 committed by GitHub
parent d4e0b28655
commit c05a8abc76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 588 additions and 126 deletions

View file

@ -17,23 +17,42 @@ import (
)
// GetCommitGraph return a list of commit (GraphItems) from all branches
func GetCommitGraph(r *git.Repository, page int, maxAllowedColors int) (*Graph, error) {
format := "DATA:%d|%H|%ad|%an|%ae|%h|%s"
func GetCommitGraph(r *git.Repository, page int, maxAllowedColors int, hidePRRefs bool, branches, files []string) (*Graph, error) {
format := "DATA:%D|%H|%ad|%h|%s"
if page == 0 {
page = 1
}
graphCmd := git.NewCommand("log")
graphCmd.AddArguments("--graph",
"--date-order",
"--all",
args := make([]string, 0, 12+len(branches)+len(files))
args = append(args, "--graph", "--date-order", "--decorate=full")
if hidePRRefs {
args = append(args, "--exclude=refs/pull/*")
}
if len(branches) == 0 {
args = append(args, "--all")
}
args = append(args,
"-C",
"-M",
fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page),
"--date=iso",
fmt.Sprintf("--pretty=format:%s", format),
)
fmt.Sprintf("--pretty=format:%s", format))
if len(branches) > 0 {
args = append(args, branches...)
}
args = append(args, "--")
if len(files) > 0 {
args = append(args, files...)
}
graphCmd := git.NewCommand("log")
graphCmd.AddArguments(args...)
graph := NewGraph()
stderr := new(strings.Builder)

View file

@ -7,6 +7,10 @@ package gitgraph
import (
"bytes"
"fmt"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
)
// NewGraph creates a basic graph
@ -77,6 +81,48 @@ func (graph *Graph) AddCommit(row, column int, flowID int64, data []byte) error
return nil
}
// LoadAndProcessCommits will load the git.Commits for each commit in the graph,
// the associate the commit with the user author, and check the commit verification
// before finally retrieving the latest status
func (graph *Graph) LoadAndProcessCommits(repository *models.Repository, gitRepo *git.Repository) error {
var err error
var ok bool
emails := map[string]*models.User{}
keyMap := map[string]bool{}
for _, c := range graph.Commits {
if len(c.Rev) == 0 {
continue
}
c.Commit, err = gitRepo.GetCommit(c.Rev)
if err != nil {
return fmt.Errorf("GetCommit: %s Error: %w", c.Rev, err)
}
if c.Commit.Author != nil {
email := c.Commit.Author.Email
if c.User, ok = emails[email]; !ok {
c.User, _ = models.GetUserByEmail(email)
emails[email] = c.User
}
}
c.Verification = models.ParseCommitWithSignature(c.Commit)
_ = models.CalculateTrustStatus(c.Verification, repository, &keyMap)
statuses, err := models.GetLatestCommitStatus(repository, c.Commit.ID.String(), 0)
if err != nil {
log.Error("GetLatestCommitStatus: %v", err)
} else {
c.Status = models.CalcCommitStatus(statuses)
}
}
return nil
}
// NewFlow creates a new flow
func NewFlow(flowID int64, color, row, column int) *Flow {
return &Flow{
@ -142,42 +188,60 @@ var RelationCommit = &Commit{
// NewCommit creates a new commit from a provided line
func NewCommit(row, column int, line []byte) (*Commit, error) {
data := bytes.SplitN(line, []byte("|"), 7)
if len(data) < 7 {
data := bytes.SplitN(line, []byte("|"), 5)
if len(data) < 5 {
return nil, fmt.Errorf("malformed data section on line %d with commit: %s", row, string(line))
}
return &Commit{
Row: row,
Column: column,
// 0 matches git log --pretty=format:%d => ref names, like the --decorate option of git-log(1)
Branch: string(data[0]),
Refs: newRefsFromRefNames(data[0]),
// 1 matches git log --pretty=format:%H => commit hash
Rev: string(data[1]),
// 2 matches git log --pretty=format:%ad => author date (format respects --date= option)
Date: string(data[2]),
// 3 matches git log --pretty=format:%an => author name
Author: string(data[3]),
// 4 matches git log --pretty=format:%ae => author email
AuthorEmail: string(data[4]),
// 5 matches git log --pretty=format:%h => abbreviated commit hash
ShortRev: string(data[5]),
// 6 matches git log --pretty=format:%s => subject
Subject: string(data[6]),
// 3 matches git log --pretty=format:%h => abbreviated commit hash
ShortRev: string(data[3]),
// 4 matches git log --pretty=format:%s => subject
Subject: string(data[4]),
}, nil
}
func newRefsFromRefNames(refNames []byte) []git.Reference {
refBytes := bytes.Split(refNames, []byte{',', ' '})
refs := make([]git.Reference, 0, len(refBytes))
for _, refNameBytes := range refBytes {
if len(refNameBytes) == 0 {
continue
}
refName := string(refNameBytes)
if refName[0:5] == "tag: " {
refName = refName[5:]
} else if refName[0:8] == "HEAD -> " {
refName = refName[8:]
}
refs = append(refs, git.Reference{
Name: refName,
})
}
return refs
}
// Commit represents a commit at co-ordinate X, Y with the data
type Commit struct {
Flow int64
Row int
Column int
Branch string
Rev string
Date string
Author string
AuthorEmail string
ShortRev string
Subject string
Commit *git.Commit
User *models.User
Verification *models.CommitVerification
Status *models.CommitStatus
Flow int64
Row int
Column int
Refs []git.Reference
Rev string
Date string
ShortRev string
Subject string
}
// OnlyRelation returns whether this a relation only commit

View file

@ -22,7 +22,7 @@ func BenchmarkGetCommitGraph(b *testing.B) {
defer currentRepo.Close()
for i := 0; i < b.N; i++ {
graph, err := GetCommitGraph(currentRepo, 1, 0)
graph, err := GetCommitGraph(currentRepo, 1, 0, false, nil, nil)
if err != nil {
b.Error("Could get commit graph")
}
@ -34,7 +34,7 @@ func BenchmarkGetCommitGraph(b *testing.B) {
}
func BenchmarkParseCommitString(b *testing.B) {
testString := "* DATA:|4e61bacab44e9b4730e44a6615d04098dd3a8eaf|2016-12-20 21:10:41 +0100|Kjell Kvinge|kjell@kvinge.biz|4e61bac|Add route for graph"
testString := "* DATA:|4e61bacab44e9b4730e44a6615d04098dd3a8eaf|2016-12-20 21:10:41 +0100|4e61bac|Add route for graph"
parser := &Parser{}
parser.Reset()
@ -44,7 +44,7 @@ func BenchmarkParseCommitString(b *testing.B) {
if err := parser.AddLineToGraph(graph, 0, []byte(testString)); err != nil {
b.Error("could not parse teststring")
}
if graph.Flows[1].Commits[0].Author != "Kjell Kvinge" {
if graph.Flows[1].Commits[0].Rev != "4e61bacab44e9b4730e44a6615d04098dd3a8eaf" {
b.Error("Did not get expected data")
}
}
@ -244,7 +244,7 @@ func TestParseGlyphs(t *testing.T) {
}
func TestCommitStringParsing(t *testing.T) {
dataFirstPart := "* DATA:|4e61bacab44e9b4730e44a6615d04098dd3a8eaf|2016-12-20 21:10:41 +0100|Author|user@mail.something|4e61bac|"
dataFirstPart := "* DATA:|4e61bacab44e9b4730e44a6615d04098dd3a8eaf|2016-12-20 21:10:41 +0100|4e61bac|"
tests := []struct {
shouldPass bool
testName string