mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 02:04:11 +01:00 
			
		
		
		
	Show git-notes (#6984)
* Show git-notes * Make git-notes heading text localizable * Refactor git-notes data fetching to a separate function * Display the author and time of git notes * Move note bubble inside the commit bubble * Revert "Move note bubble inside the commit bubble" This reverts commit c0951fe0e3b4dea38064515546b1825c1bcf19e1. * Add test for git-notes * testing ui * Polish CSS * Apply suggestions from code review Co-Authored-By: Lauris BH <lauris@nix.lv>
This commit is contained in:
		
							parent
							
								
									d5a98a2969
								
							
						
					
					
						commit
						a98e085031
					
				
							
								
								
									
										60
									
								
								modules/git/notes.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								modules/git/notes.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
			
		||||
// Copyright 2019 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
 | 
			
		||||
	"gopkg.in/src-d/go-git.v4/plumbing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NotesRef is the git ref where Gitea will look for git-notes data.
 | 
			
		||||
// The value ("refs/notes/commits") is the default ref used by git-notes.
 | 
			
		||||
const NotesRef = "refs/notes/commits"
 | 
			
		||||
 | 
			
		||||
// Note stores information about a note created using git-notes.
 | 
			
		||||
type Note struct {
 | 
			
		||||
	Message []byte
 | 
			
		||||
	Commit  *Commit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetNote retrieves the git-notes data for a given commit.
 | 
			
		||||
func GetNote(repo *Repository, commitID string, note *Note) error {
 | 
			
		||||
	notes, err := repo.GetCommit(NotesRef)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	entry, err := notes.GetTreeEntryByPath(commitID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	blob := entry.Blob()
 | 
			
		||||
	dataRc, err := blob.DataAsync()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer dataRc.Close()
 | 
			
		||||
	d, err := ioutil.ReadAll(dataRc)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	note.Message = d
 | 
			
		||||
 | 
			
		||||
	commit, err := repo.gogitRepo.CommitObject(plumbing.Hash(notes.ID))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lastCommits, err := getLastCommitForPaths(commit, "", []string{commitID})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	note.Commit = convertCommit(lastCommits[commitID])
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								modules/git/notes_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								modules/git/notes_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
// Copyright 2019 The Gitea Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestGetNotes(t *testing.T) {
 | 
			
		||||
	bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
 | 
			
		||||
	bareRepo1, err := OpenRepository(bareRepo1Path)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	note := Note{}
 | 
			
		||||
	err = GetNote(bareRepo1, "95bb4d39648ee7e325106df01a621c530863a653", ¬e)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, []byte("Note contents\n"), note.Message)
 | 
			
		||||
	assert.Equal(t, "Vladimir Panteleev", note.Commit.Author.Name)
 | 
			
		||||
}
 | 
			
		||||
@ -19,13 +19,14 @@ func TestRepository_GetRefs(t *testing.T) {
 | 
			
		||||
	refs, err := bareRepo1.GetRefs()
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, refs, 4)
 | 
			
		||||
	assert.Len(t, refs, 5)
 | 
			
		||||
 | 
			
		||||
	expectedRefs := []string{
 | 
			
		||||
		BranchPrefix + "branch1",
 | 
			
		||||
		BranchPrefix + "branch2",
 | 
			
		||||
		BranchPrefix + "master",
 | 
			
		||||
		TagPrefix + "test",
 | 
			
		||||
		NotesRef,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, ref := range refs {
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
x¥ŽM
 | 
			
		||||
Â0F]ç³ëB<C3AB>&&m"ž@\¹Of¦6ÐHG¥··ô
 | 
			
		||||
~Ë·xïÃy³€Ñþ …Œ?[—Œ¶èBÓ&
 | 
			
		||||
H<bÛyß™NGtåÚ¨ø–~.ð"å1xÄIx`þÀå•å&=㚸,}¤ù{šX® <C2AE>ó¶	<09>p¬·)ÜãÂjÔ}^ 1AZ¡ÚÀ´3¦,•ú½ÀI0
 | 
			
		||||
							
								
								
									
										1
									
								
								modules/git/tests/repos/repo1_bare/refs/notes/commits
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								modules/git/tests/repos/repo1_bare/refs/notes/commits
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
ca6b5ddf303169a72d2a2971acde4f6eea194e5c
 | 
			
		||||
@ -125,6 +125,7 @@ func NewFuncMap() []template.FuncMap {
 | 
			
		||||
		"RenderCommitMessage":      RenderCommitMessage,
 | 
			
		||||
		"RenderCommitMessageLink":  RenderCommitMessageLink,
 | 
			
		||||
		"RenderCommitBody":         RenderCommitBody,
 | 
			
		||||
		"RenderNote":               RenderNote,
 | 
			
		||||
		"IsMultilineCommitMessage": IsMultilineCommitMessage,
 | 
			
		||||
		"ThemeColorMetaTag": func() string {
 | 
			
		||||
			return setting.UI.ThemeColorMetaTag
 | 
			
		||||
@ -392,6 +393,17 @@ func RenderCommitBody(msg, urlPrefix string, metas map[string]string) template.H
 | 
			
		||||
	return template.HTML(strings.Join(body[1:], "\n"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderNote renders the contents of a git-notes file as a commit message.
 | 
			
		||||
func RenderNote(msg, urlPrefix string, metas map[string]string) template.HTML {
 | 
			
		||||
	cleanMsg := template.HTMLEscapeString(msg)
 | 
			
		||||
	fullMessage, err := markup.RenderCommitMessage([]byte(cleanMsg), urlPrefix, "", metas)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("RenderNote: %v", err)
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	return template.HTML(string(fullMessage))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsMultilineCommitMessage checks to see if a commit message contains multiple lines.
 | 
			
		||||
func IsMultilineCommitMessage(msg string) bool {
 | 
			
		||||
	return strings.Count(strings.TrimSpace(msg), "\n") >= 1
 | 
			
		||||
 | 
			
		||||
@ -1314,6 +1314,7 @@ settings.unarchive.error = An error occured while trying to un-archive the repo.
 | 
			
		||||
diff.browse_source = Browse Source
 | 
			
		||||
diff.parent = parent
 | 
			
		||||
diff.commit = commit
 | 
			
		||||
diff.git-notes = Notes
 | 
			
		||||
diff.data_not_available = Diff Content Not Available
 | 
			
		||||
diff.show_diff_stats = Show Diff Stats
 | 
			
		||||
diff.show_split_view = Split View
 | 
			
		||||
 | 
			
		||||
@ -803,6 +803,8 @@ footer .ui.left,footer .ui.right{line-height:40px}
 | 
			
		||||
.stats-table .table-cell.tiny{height:.5em}
 | 
			
		||||
tbody.commit-list{vertical-align:baseline}
 | 
			
		||||
.commit-body{white-space:pre-wrap}
 | 
			
		||||
.git-notes.top{text-align:left}
 | 
			
		||||
.git-notes .commit-body{margin:0}
 | 
			
		||||
@media only screen and (max-width:767px){.ui.stackable.menu.mobile--margin-between-items>.item{margin-top:5px;margin-bottom:5px}
 | 
			
		||||
.ui.stackable.menu.mobile--no-negative-margins{margin-left:0;margin-right:0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2219,6 +2219,15 @@ tbody.commit-list {
 | 
			
		||||
    white-space: pre-wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.git-notes {
 | 
			
		||||
    &.top {
 | 
			
		||||
        text-align: left;
 | 
			
		||||
    }
 | 
			
		||||
    .commit-body {
 | 
			
		||||
        margin: 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media only screen and (max-width: 767px) {
 | 
			
		||||
    .ui.stackable.menu {
 | 
			
		||||
        &.mobile--margin-between-items > .item {
 | 
			
		||||
 | 
			
		||||
@ -15,6 +15,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/templates"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@ -246,6 +247,15 @@ func Diff(ctx *context.Context) {
 | 
			
		||||
	ctx.Data["Parents"] = parents
 | 
			
		||||
	ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
 | 
			
		||||
	ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", commitID)
 | 
			
		||||
 | 
			
		||||
	note := &git.Note{}
 | 
			
		||||
	err = git.GetNote(ctx.Repo.GitRepo, commitID, note)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		ctx.Data["Note"] = string(templates.ToUTF8WithFallback(note.Message))
 | 
			
		||||
		ctx.Data["NoteCommit"] = note.Commit
 | 
			
		||||
		ctx.Data["NoteAuthor"] = models.ValidateCommitWithEmail(note.Commit)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if commit.ParentCount() > 0 {
 | 
			
		||||
		ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", parents[0])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -65,6 +65,27 @@
 | 
			
		||||
					</div>
 | 
			
		||||
				{{end}}
 | 
			
		||||
			{{end}}
 | 
			
		||||
			{{if .Note}}
 | 
			
		||||
				<div class="ui top attached info segment message git-notes">
 | 
			
		||||
					<i class="sticky note icon"></i>
 | 
			
		||||
					{{.i18n.Tr "repo.diff.git-notes"}}:
 | 
			
		||||
					{{if .NoteAuthor}}
 | 
			
		||||
						<a href="{{.NoteAuthor.HomeLink}}">
 | 
			
		||||
							{{if .NoteAuthor.FullName}}
 | 
			
		||||
							  <strong>{{.NoteAuthor.FullName}}</strong>
 | 
			
		||||
							{{else}}
 | 
			
		||||
							  <strong>{{.NoteCommit.Author.Name}}</strong>
 | 
			
		||||
							{{end}}
 | 
			
		||||
						</a>
 | 
			
		||||
					{{else}}
 | 
			
		||||
						<strong>{{.NoteCommit.Author.Name}}</strong>
 | 
			
		||||
					{{end}}
 | 
			
		||||
					<span class="text grey" id="note-authored-time">{{TimeSince .NoteCommit.Author.When $.Lang}}</span>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="ui bottom attached info segment git-notes">
 | 
			
		||||
					<pre class="commit-body">{{RenderNote .Note $.RepoLink $.Repository.ComposeMetas}}</pre>
 | 
			
		||||
				</div>
 | 
			
		||||
			{{end}}
 | 
			
		||||
		{{end}}
 | 
			
		||||
 | 
			
		||||
		{{template "repo/diff/box" .}}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user