]> source.dussan.org Git - gitea.git/commitdiff
add commit compare functionality
authorChristopher Brickley <brickley@gmail.com>
Tue, 26 Aug 2014 12:20:18 +0000 (08:20 -0400)
committerChristopher Brickley <brickley@gmail.com>
Mon, 1 Sep 2014 18:56:19 +0000 (14:56 -0400)
cmd/web.go
models/action.go
models/git_diff.go
models/slack.go
models/update.go
models/webhook.go
public/css/gogs.css
routers/repo/commit.go
templates/repo/commits.tmpl
templates/repo/commits_table.tmpl [new file with mode: 0644]
templates/repo/diff.tmpl

index 275d3fb90e929a3e4bce5a759bbd33085ad0ed73..2199d4ca1e439e696093ab6c887df741825d3c92 100644 (file)
@@ -342,6 +342,7 @@ func runWeb(*cli.Context) {
                r.Get("/commit/:branchname/*", repo.Diff)
                r.Get("/releases", repo.Releases)
                r.Get("/archive/*.*", repo.Download)
+               r.Get("/compare/:before([a-z0-9]+)...:after([a-z0-9]+)", repo.CompareDiff)
        }, ignSignIn, middleware.RepoAssignment(true, true))
 
        m.Group("/:username", func(r *macaron.Router) {
index d536c84dd0a411c80c4a3c4c27a4e865237e8396..5a8c31697cccd706fc93bbfa538b0f546d1eaf9c 100644 (file)
@@ -172,7 +172,7 @@ func updateIssuesCommit(userId, repoId int64, repoUserName, repoName string, com
 
 // CommitRepoAction adds new action for committing repository.
 func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
-       repoId int64, repoUserName, repoName string, refFullName string, commit *base.PushCommits) error {
+       repoId int64, repoUserName, repoName string, refFullName string, commit *base.PushCommits, oldCommitId string, newCommitId string) error {
 
        opType := COMMIT_REPO
        // Check it's tag push or branch.
@@ -226,6 +226,7 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
        }
 
        repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName)
+       compareUrl := fmt.Sprintf("%s/compare/%s...%s", repoLink, oldCommitId, newCommitId)
        commits := make([]*PayloadCommit, len(commit.Commits))
        for i, cmt := range commit.Commits {
                commits[i] = &PayloadCommit{
@@ -258,6 +259,9 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
                        Name:  repo.Owner.LowerName,
                        Email: repo.Owner.Email,
                },
+               Before:     oldCommitId,
+               After:      newCommitId,
+               CompareUrl: compareUrl,
        }
 
        for _, w := range ws {
index 4b4d1234dd03df1935638c8bba5987975459232d..21a624de5fbfcd8e273dbf121820f6572a007684 100644 (file)
@@ -175,25 +175,30 @@ func ParsePatch(pid int64, cmd *exec.Cmd, reader io.Reader) (*Diff, error) {
        return diff, nil
 }
 
-func GetDiff(repoPath, commitid string) (*Diff, error) {
+func GetDiffRange(repoPath, beforeCommitId string, afterCommitId string) (*Diff, error) {
        repo, err := git.OpenRepository(repoPath)
        if err != nil {
                return nil, err
        }
 
-       commit, err := repo.GetCommit(commitid)
+       commit, err := repo.GetCommit(afterCommitId)
        if err != nil {
                return nil, err
        }
 
        rd, wr := io.Pipe()
        var cmd *exec.Cmd
-       // First commit of repository.
-       if commit.ParentCount() == 0 {
-               cmd = exec.Command("git", "show", commitid)
+       // if "after" commit given
+       if beforeCommitId == "" {
+               // First commit of repository.
+               if commit.ParentCount() == 0 {
+                       cmd = exec.Command("git", "show", afterCommitId)
+               } else {
+                       c, _ := commit.Parent(0)
+                       cmd = exec.Command("git", "diff", c.Id.String(), afterCommitId)
+               }
        } else {
-               c, _ := commit.Parent(0)
-               cmd = exec.Command("git", "diff", c.Id.String(), commitid)
+               cmd = exec.Command("git", "diff", beforeCommitId, afterCommitId)
        }
        cmd.Dir = repoPath
        cmd.Stdout = wr
@@ -208,7 +213,7 @@ func GetDiff(repoPath, commitid string) (*Diff, error) {
        }()
        defer rd.Close()
 
-       desc := fmt.Sprintf("GetDiff(%s)", repoPath)
+       desc := fmt.Sprintf("GetDiffRange(%s)", repoPath)
        pid := process.Add(desc, cmd)
        go func() {
                // In case process became zombie.
@@ -226,3 +231,7 @@ func GetDiff(repoPath, commitid string) (*Diff, error) {
 
        return ParsePatch(pid, cmd, rd)
 }
+
+func GetDiffCommit(repoPath, commitId string) (*Diff, error) {
+       return GetDiffRange(repoPath, "", commitId)
+}
index 0a557409479ca2da71eefc2458b9b9bde77fedb1..714b2f6ca213c31370b546ff4ac21e89a7ad9f11 100644 (file)
@@ -70,19 +70,21 @@ func getSlackPushPayload(p *Payload, slack *Slack) (*SlackPayload, error) {
        branchName := refSplit[len(refSplit)-1]
        var commitString string
 
-       // TODO: add commit compare before/after link when gogs adds it
        if len(p.Commits) == 1 {
                commitString = "1 new commit"
        } else {
                commitString = fmt.Sprintf("%d new commits", len(p.Commits))
+               commitString = SlackLinkFormatter(p.CompareUrl, commitString)
        }
 
-       text := fmt.Sprintf("[%s:%s] %s pushed by %s", p.Repo.Name, branchName, commitString, p.Pusher.Name)
+       repoLink := SlackLinkFormatter(p.Repo.Url, p.Repo.Name)
+       branchLink := SlackLinkFormatter(p.Repo.Url+"/src/"+branchName, branchName)
+       text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.Name)
        var attachmentText string
 
        // for each commit, generate attachment text
        for i, commit := range p.Commits {
-               attachmentText += fmt.Sprintf("<%s|%s>: %s - %s", commit.Url, commit.Id[:7], SlackFormatter(commit.Message), commit.Author.Name)
+               attachmentText += fmt.Sprintf("%s: %s - %s", SlackLinkFormatter(commit.Url, commit.Id[:7]), SlackTextFormatter(commit.Message), SlackTextFormatter(commit.Author.Name))
                // add linebreak to each commit but the last
                if i < len(p.Commits)-1 {
                        attachmentText += "\n"
@@ -103,7 +105,7 @@ func getSlackPushPayload(p *Payload, slack *Slack) (*SlackPayload, error) {
 }
 
 // see: https://api.slack.com/docs/formatting
-func SlackFormatter(s string) string {
+func SlackTextFormatter(s string) string {
        // take only first line of commit
        first := strings.Split(s, "\n")[0]
        // replace & < >
@@ -112,3 +114,7 @@ func SlackFormatter(s string) string {
        first = strings.Replace(first, ">", "&gt;", -1)
        return first
 }
+
+func SlackLinkFormatter(url string, text string) string {
+       return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text))
+}
index 68a92ada1dbb726af80206d17b51606ae08d1449..ec6a9790169a79337a24c2adfbd7f52854dbfea9 100644 (file)
@@ -101,7 +101,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
                commit := &base.PushCommits{}
 
                if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
-                       repos.Id, repoUserName, repoName, refName, commit); err != nil {
+                       repos.Id, repoUserName, repoName, refName, commit, oldCommitId, newCommitId); err != nil {
                        log.GitLogger.Fatal(4, "runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
                }
                return err
@@ -152,7 +152,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 
        //commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()})
        if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
-               repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits}); err != nil {
+               repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits}, oldCommitId, newCommitId); err != nil {
                return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
        }
        return nil
index 55ed4844ed4460288a99ab05295f918a85651fbc..0b7b3a9948d516453a0052d55b1a2da35036af37 100644 (file)
@@ -169,11 +169,14 @@ type BasePayload interface {
 
 // Payload represents a payload information of hook.
 type Payload struct {
-       Secret  string           `json:"secret"`
-       Ref     string           `json:"ref"`
-       Commits []*PayloadCommit `json:"commits"`
-       Repo    *PayloadRepo     `json:"repository"`
-       Pusher  *PayloadAuthor   `json:"pusher"`
+       Secret     string           `json:"secret"`
+       Ref        string           `json:"ref"`
+       Commits    []*PayloadCommit `json:"commits"`
+       Repo       *PayloadRepo     `json:"repository"`
+       Pusher     *PayloadAuthor   `json:"pusher"`
+       Before     string           `json:"before"`
+       After      string           `json:"after"`
+       CompareUrl string           `json:"compare_url"`
 }
 
 func (p Payload) GetJSONPayload() ([]byte, error) {
index 2d30d0628418ccdf4d3e2a9cdc4cc4d35b67143f..0af09a3ecc59231c4f971d22b8b525b8e622f54c 100755 (executable)
@@ -968,6 +968,13 @@ body {
 .guide-box .zclip {
     left: auto !important;
 }
+div.compare div#commits {
+    margin-top: 5px;
+}
+div.compare div#commits h4 {
+  margin: 10px 0;
+  line-height: 1.1;
+}
 .diff-head-box h4 {
     margin-top: 0;
     margin-bottom: 0;
index 6320123b40aa056d5965150de77acfd3503d473b..54acc85b3e2354afe09a3e9a5f569a4063c5b91f 100644 (file)
@@ -114,9 +114,9 @@ func Diff(ctx *middleware.Context) {
 
        commit := ctx.Repo.Commit
 
-       diff, err := models.GetDiff(models.RepoPath(userName, repoName), commitId)
+       diff, err := models.GetDiffCommit(models.RepoPath(userName, repoName), commitId)
        if err != nil {
-               ctx.Handle(404, "GetDiff", err)
+               ctx.Handle(404, "GetDiffCommit", err)
                return
        }
 
@@ -162,6 +162,67 @@ func Diff(ctx *middleware.Context) {
        ctx.HTML(200, DIFF)
 }
 
+func CompareDiff(ctx *middleware.Context) {
+       ctx.Data["IsRepoToolbarCommits"] = true
+       ctx.Data["IsDiffCompare"] = true
+       userName := ctx.Repo.Owner.Name
+       repoName := ctx.Repo.Repository.Name
+       beforeCommitId := ctx.Params(":before")
+       afterCommitId := ctx.Params(":after")
+
+       commit, err := ctx.Repo.GitRepo.GetCommit(afterCommitId)
+       if err != nil {
+               ctx.Handle(404, "GetCommit", err)
+               return
+       }
+
+       diff, err := models.GetDiffRange(models.RepoPath(userName, repoName), beforeCommitId, afterCommitId)
+       if err != nil {
+               ctx.Handle(404, "GetDiffRange", err)
+               return
+       }
+
+       isImageFile := func(name string) bool {
+               blob, err := commit.GetBlobByPath(name)
+               if err != nil {
+                       return false
+               }
+
+               dataRc, err := blob.Data()
+               if err != nil {
+                       return false
+               }
+               buf := make([]byte, 1024)
+               n, _ := dataRc.Read(buf)
+               if n > 0 {
+                       buf = buf[:n]
+               }
+               _, isImage := base.IsImageFile(buf)
+               return isImage
+       }
+
+       commits, err := commit.CommitsBeforeUntil(beforeCommitId)
+       if err != nil {
+               ctx.Handle(500, "CommitsBeforeUntil", err)
+               return
+       }
+
+       ctx.Data["Commits"] = commits
+       ctx.Data["CommitCount"] = commits.Len()
+       ctx.Data["BeforeCommitId"] = beforeCommitId
+       ctx.Data["AfterCommitId"] = afterCommitId
+       ctx.Data["Username"] = userName
+       ctx.Data["Reponame"] = repoName
+       ctx.Data["IsImageFile"] = isImageFile
+       ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitId) + "..." + base.ShortSha(afterCommitId) + " ยท " + userName + "/" + repoName
+       ctx.Data["Commit"] = commit
+       ctx.Data["Diff"] = diff
+       ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
+       ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", afterCommitId)
+       ctx.Data["RawPath"] = "/" + path.Join(userName, repoName, "raw", afterCommitId)
+       ctx.HTML(200, DIFF)
+}
+
 func FileHistory(ctx *middleware.Context) {
        ctx.Data["IsRepoToolbarCommits"] = true
 
index 420e973a50a462ffa9c5f34b8404dea1754dbf62..e7518e983529ea031fac5b2088f4a27887fdd7c7 100644 (file)
@@ -3,47 +3,6 @@
 {{template "repo/nav" .}}
 {{template "repo/toolbar" .}}
 <div id="body" class="container">
-    <div id="commits">
-        <div class="panel panel-default commit-box info-box">
-            <div class="panel-heading info-head">
-                <form class="search pull-right col-md-3" action="{{.RepoLink}}/commits/{{.BranchName}}/search" method="get" id="commits-search-form">
-                    <div class="input-group">
-                        <input class="form-control search" type="search" placeholder="search commit" name="q" value="{{.Keyword}}" />
-                        <div class="input-group-btn">
-                            <button type="submit" class="btn btn-default">Find</button>
-                        </div>
-                    </div>
-                </form>
-                <h4>{{.CommitCount}} Commits</h4>
-            </div>
-            <table class="panel-footer table commit-list table table-striped">
-                <thead>
-                    <tr>
-                        <th class="author">Author</th>
-                        <th class="sha">SHA1</th>
-                        <th class="message">Message</th>
-                        <th class="date">Date</th>
-                    </tr>
-                </thead>
-                <tbody>
-                {{ $username := .Username}}
-                {{ $reponame := .Reponame}}
-                {{$r := List .Commits}}
-                {{range $r}}
-                <tr>
-                    <td class="author"><img class="avatar" src="{{AvatarLink .Author.Email}}" alt=""/><a href="/user/email2user?email={{.Author.Email}}">{{.Author.Name}}</a></td>
-                    <td class="sha"><a rel="nofollow" class="label label-success" href="/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
-                    <td class="message">{{.Summary}} </td>
-                    <td class="date">{{TimeSince .Author.When $.Lang}}</td>
-                </tr>
-                {{end}}
-                </tbody>
-            </table>
-        </div>
-        {{if not .IsSearchPage}}<ul class="pagination" id="commits-pager">
-            {{if .LastPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}{{if .FileName}}/{{.FileName}}{{end}}?p={{.LastPageNum}}" rel="nofollow">&laquo; Newer</a></li>{{end}}
-            {{if .NextPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}{{if .FileName}}/{{.FileName}}{{end}}?p={{.NextPageNum}}" rel="nofollow">&raquo; Older</a></li>{{end}}
-        </ul>{{end}}
-    </div>
+  {{template "repo/commits_table" .}}
 </div>
 {{template "base/footer" .}}
diff --git a/templates/repo/commits_table.tmpl b/templates/repo/commits_table.tmpl
new file mode 100644 (file)
index 0000000..4612398
--- /dev/null
@@ -0,0 +1,42 @@
+<div id="commits">
+    <div class="panel panel-default commit-box info-box">
+        <div class="panel-heading info-head">
+            <form class="search pull-right col-md-3" action="{{.RepoLink}}/commits/{{.BranchName}}/search" method="get" id="commits-search-form">
+                <div class="input-group">
+                    <input class="form-control search" type="search" placeholder="search commit" name="q" value="{{.Keyword}}" />
+                    <div class="input-group-btn">
+                        <button type="submit" class="btn btn-default">Find</button>
+                    </div>
+                </div>
+            </form>
+            <h4>{{.CommitCount}} Commits</h4>
+        </div>
+        <table class="panel-footer table commit-list table table-striped">
+            <thead>
+                <tr>
+                    <th class="author">Author</th>
+                    <th class="sha">SHA1</th>
+                    <th class="message">Message</th>
+                    <th class="date">Date</th>
+                </tr>
+            </thead>
+            <tbody>
+            {{ $username := .Username}}
+            {{ $reponame := .Reponame}}
+            {{$r := List .Commits}}
+            {{range $r}}
+            <tr>
+                <td class="author"><img class="avatar" src="{{AvatarLink .Author.Email}}" alt=""/><a href="/user/email2user?email={{.Author.Email}}">{{.Author.Name}}</a></td>
+                <td class="sha"><a rel="nofollow" class="label label-success" href="/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
+                <td class="message">{{.Summary}} </td>
+                <td class="date">{{TimeSince .Author.When $.Lang}}</td>
+            </tr>
+            {{end}}
+            </tbody>
+        </table>
+    </div>
+    {{if not .IsSearchPage}}<ul class="pagination" id="commits-pager">
+        {{if .LastPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}{{if .FileName}}/{{.FileName}}{{end}}?p={{.LastPageNum}}" rel="nofollow">&laquo; Newer</a></li>{{end}}
+        {{if .NextPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}{{if .FileName}}/{{.FileName}}{{end}}?p={{.NextPageNum}}" rel="nofollow">&raquo; Older</a></li>{{end}}
+    </ul>{{end}}
+</div>
index 6adea04593cf2460fd0d258ffa60d2664be2f69f..787334508362f7c0bb09f9cdadf41a38c1485620 100644 (file)
@@ -3,7 +3,18 @@
 {{template "repo/nav" .}}
 <div id="body" class="container" data-page="repo">
     <div id="source">
+      {{if .IsDiffCompare }}
         <div class="panel panel-info diff-box diff-head-box">
+            <div class="panel-heading">
+                <a class="pull-right btn btn-primary btn-sm" rel="nofollow" href="{{.SourcePath}}">Browse Source</a>
+                <h4><a href="{{$.RepoLink}}/commit/{{.BeforeCommitId}}" class="label label-success">{{ShortSha .BeforeCommitId}}</a> ... <a href="{{$.RepoLink}}/commit/{{.AfterCommitId}}" class="label label-success">{{ShortSha .AfterCommitId}}</a></h4>
+            </div>
+            <div class="panel-body compare">
+              {{template "repo/commits_table" .}}
+            </div>
+        </div>
+      {{else}}
+          <div class="panel panel-info diff-box diff-head-box">
             <div class="panel-heading">
                 <a class="pull-right btn btn-primary btn-sm" rel="nofollow" href="{{.SourcePath}}">Browse Source</a>
                 <h4>{{.Commit.Message}}</h4>
@@ -22,9 +33,9 @@
                     <a class="name" href="/user/email2user?email={{.Commit.Author.Email}}"><strong>{{.Commit.Author.Name}}</strong></a>
                     <span class="time">{{TimeSince .Commit.Author.When $.Lang}}</span>
                 </p>
-            </div>
+          </div>
         </div>
-
+      {{end}}
         {{if .DiffNotAvailable}}
         <h4>Diff Data Not Available.</h4>
         {{else}}