Skip to content

Commit c9a16f3

Browse files
authored
Add file parameter to blame so it doesn't return all the results… (#988)
Add file parameter to blame so it doesn't return all the results from a commit
2 parents d3a5cfc + 1ab306d commit c9a16f3

File tree

7 files changed

+65
-70
lines changed

7 files changed

+65
-70
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
### Changed
1515

1616
- Add progress for each partition in SHOW PROCESSLIST ([#855](https://github.com/src-d/go-mysql-server/pull/855))
17+
- Change BLAME to also take a file parameter.
1718

1819
## [0.24.0-rc3] - 2019-10-23
1920

docs/using-gitbase/examples.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -203,15 +203,15 @@ The output will be similar to this:
203203
## Get miscelaneous information about lines with a "// TODO" comment in HEAD
204204

205205
```sql
206-
SELECT repository_id,
207-
JSON_UNQUOTE(JSON_EXTRACT(bl, "$.file")),
206+
SELECT repository_id, file_path,
208207
JSON_UNQUOTE(JSON_EXTRACT(bl, "$.linenum")),
209208
JSON_UNQUOTE(JSON_EXTRACT(bl, "$.author")),
210209
JSON_UNQUOTE(JSON_EXTRACT(bl, "$.text"))
211-
FROM (SELECT repository_id,
212-
EXPLODE(BLAME(repository_id, commit_hash)) AS bl
210+
FROM (SELECT repository_id, file_path,
211+
EXPLODE(BLAME(repository_id, commit_hash, file_path)) AS bl
213212
FROM ref_commits
214213
NATURAL JOIN blobs
214+
NATURAL JOIN commit_files
215215
WHERE ref_name = 'HEAD'
216216
AND NOT IS_BINARY(blob_content)
217217
) as p
@@ -225,9 +225,10 @@ SELECT
225225
JSON_UNQUOTE(JSON_EXTRACT(bl, "$.author")),
226226
COUNT(JSON_UNQUOTE(JSON_EXTRACT(bl, "$.author")))
227227

228-
FROM (SELECT EXPLODE(BLAME(repository_id, commit_hash)) AS bl
228+
FROM (SELECT EXPLODE(BLAME(repository_id, commit_hash, file_path)) AS bl
229229
FROM ref_commits
230230
NATURAL JOIN blobs
231+
NATURAL JOIN commit_files
231232
WHERE ref_name = 'HEAD'
232233
AND NOT IS_BINARY(blob_content)
233234
) AS p

docs/using-gitbase/functions.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ To make some common tasks easier for the user, there are some functions to inter
66

77
| Name | Description |
88
|:-------------|:-------------------------------------------------------------------------------------------------------------------------------|
9-
|`blame(repository, commit)`|Returns an array of lines changes and authorship. |
9+
|`blame(repository, commit, file)`|Returns an array of lines changes and authorship for the specific file and commit.
1010
|`commit_file_stats(repository_id, [from_commit_hash], to_commit_hash) json array`|returns an array with the stats of each file in `to_commit_hash` since the given `from_commit_hash`. If `from_commit_hash` is not given, the parent commit will be used. Vendored files stats are not included in the result of this function. This function is more thoroughly explained later in this document.|
1111
|`commit_stats(repository_id, [from_commit_hash], to_commit_hash) json`|returns the stats between two commits for a repository. If `from_commit_hash` is empty, it will compare the given `to_commit_hash` with its parent commit. Vendored files stats are not included in the result of this function. This function is more thoroughly explained later in this document.|
1212
|`is_remote(reference_name)bool`| checks if the given reference name is from a remote one. |

integration_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -514,12 +514,12 @@ func TestIntegration(t *testing.T) {
514514
SELECT repository_id, JSON_EXTRACT(bl, "$.author"),
515515
COUNT(bl)
516516
FROM (
517-
SELECT repository_id, EXPLODE(BLAME(repository_id, commit_hash)) as bl
517+
SELECT repository_id, EXPLODE(BLAME(repository_id, commit_hash, '.gitignore')) as bl
518518
FROM commits
519519
WHERE commit_hash = '918c48b83bd081e863dbe1b80f8998f058cd8294'
520520
) as p
521521
`,
522-
[]sql.Row{{"worktree", "[email protected]", int64(7235)}},
522+
[]sql.Row{{"worktree", "[email protected]", int64(12)}},
523523
},
524524
}
525525

internal/function/blame.go

+33-51
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import (
44
"fmt"
55
"io"
66

7-
"github.com/sirupsen/logrus"
8-
97
"github.com/src-d/gitbase"
108
"github.com/src-d/go-mysql-server/sql"
119
"gopkg.in/src-d/go-git.v4"
@@ -17,55 +15,38 @@ import (
1715
type BlameGenerator struct {
1816
ctx *sql.Context
1917
commit *object.Commit
20-
fIter *object.FileIter
18+
file string
2119
curLine int
22-
curFile *object.File
2320
lines []*git.Line
2421
}
2522

26-
func NewBlameGenerator(ctx *sql.Context, c *object.Commit, f *object.FileIter) (*BlameGenerator, error) {
27-
return &BlameGenerator{ctx: ctx, commit: c, fIter: f, curLine: -1}, nil
28-
}
29-
30-
func (g *BlameGenerator) loadNewFile() error {
31-
var err error
32-
g.curFile, err = g.fIter.Next()
33-
if err != nil {
34-
return err
35-
}
36-
37-
result, err := git.Blame(g.commit, g.curFile.Name)
23+
func NewBlameGenerator(ctx *sql.Context, c *object.Commit, f string) (*BlameGenerator, error) {
24+
result, err := git.Blame(c, f)
3825
if err != nil {
39-
msg := fmt.Sprintf(
40-
"Error in BLAME for file %s: %s",
41-
g.curFile.Name,
42-
err.Error(),
43-
)
44-
logrus.Warn(msg)
45-
g.ctx.Warn(0, msg)
46-
return io.EOF
47-
}
48-
49-
if len(result.Lines) == 0 {
50-
return g.loadNewFile()
26+
return nil, err
5127
}
52-
53-
g.lines = result.Lines
54-
g.curLine = 0
55-
return nil
28+
return &BlameGenerator{
29+
ctx: ctx,
30+
commit: c,
31+
file: f,
32+
curLine: 0,
33+
lines: result.Lines,
34+
}, nil
5635
}
5736

5837
func (g *BlameGenerator) Next() (interface{}, error) {
59-
if g.curLine == -1 || g.curLine >= len(g.lines) {
60-
err := g.loadNewFile()
61-
if err != nil {
62-
return nil, err
63-
}
38+
select {
39+
case <-g.ctx.Done():
40+
return nil, io.EOF
41+
default:
42+
}
43+
44+
if len(g.lines) == 0 || g.curLine >= len(g.lines) {
45+
return nil, io.EOF
6446
}
6547

6648
l := g.lines[g.curLine]
6749
b := BlameLine{
68-
File: g.curFile.Name,
6950
LineNum: g.curLine,
7051
Author: l.Author,
7152
Text: l.Text,
@@ -75,7 +56,6 @@ func (g *BlameGenerator) Next() (interface{}, error) {
7556
}
7657

7758
func (g *BlameGenerator) Close() error {
78-
g.fIter.Close()
7959
return nil
8060
}
8161

@@ -86,20 +66,20 @@ type (
8666
Blame struct {
8767
repo sql.Expression
8868
commit sql.Expression
69+
file sql.Expression
8970
}
9071

9172
// BlameLine represents each line of git blame's output
9273
BlameLine struct {
93-
File string `json:"file"`
9474
LineNum int `json:"linenum"`
9575
Author string `json:"author"`
9676
Text string `json:"text"`
9777
}
9878
)
9979

10080
// NewBlame constructor
101-
func NewBlame(repo, commit sql.Expression) sql.Expression {
102-
return &Blame{repo, commit}
81+
func NewBlame(repo, commit, file sql.Expression) sql.Expression {
82+
return &Blame{repo, commit, file}
10383
}
10484

10585
func (b *Blame) String() string {
@@ -112,26 +92,26 @@ func (*Blame) Type() sql.Type {
11292
}
11393

11494
func (b *Blame) WithChildren(children ...sql.Expression) (sql.Expression, error) {
115-
if len(children) != 2 {
95+
if len(children) != 3 {
11696
return nil, sql.ErrInvalidChildrenNumber.New(b, len(children), 2)
11797
}
11898

119-
return NewBlame(children[0], children[1]), nil
99+
return NewBlame(children[0], children[1], children[2]), nil
120100
}
121101

122102
// Children implements the Expression interface.
123103
func (b *Blame) Children() []sql.Expression {
124-
return []sql.Expression{b.repo, b.commit}
104+
return []sql.Expression{b.repo, b.commit, b.file}
125105
}
126106

127107
// IsNullable implements the Expression interface.
128108
func (b *Blame) IsNullable() bool {
129-
return b.repo.IsNullable() || (b.commit.IsNullable())
109+
return b.repo.IsNullable() || (b.commit.IsNullable()) || (b.file.IsNullable())
130110
}
131111

132112
// Resolved implements the Expression interface.
133113
func (b *Blame) Resolved() bool {
134-
return b.repo.Resolved() && b.commit.Resolved()
114+
return b.repo.Resolved() && b.commit.Resolved() && b.file.Resolved()
135115
}
136116

137117
// Eval implements the sql.Expression interface.
@@ -151,14 +131,16 @@ func (b *Blame) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
151131
return nil, nil
152132
}
153133

154-
fIter, err := commit.Files()
134+
file, err := exprToString(ctx, b.file, row)
155135
if err != nil {
156-
return nil, err
136+
ctx.Warn(0, err.Error())
137+
return nil, nil
157138
}
158139

159-
bg, err := NewBlameGenerator(ctx, commit, fIter)
140+
bg, err := NewBlameGenerator(ctx, commit, file)
160141
if err != nil {
161-
return nil, err
142+
ctx.Warn(0, err.Error())
143+
return nil, nil
162144
}
163145

164146
return bg, nil

internal/function/blame_test.go

+21-10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func TestBlameEval(t *testing.T) {
2828
name string
2929
repo sql.Expression
3030
commit sql.Expression
31+
file sql.Expression
3132
row sql.Row
3233
expected BlameLine
3334
expectedNil bool
@@ -38,11 +39,11 @@ func TestBlameEval(t *testing.T) {
3839
name: "init commit",
3940
repo: expression.NewGetField(0, sql.Text, "repository_id", false),
4041
commit: expression.NewGetField(1, sql.Text, "commit_hash", false),
41-
row: sql.NewRow("worktree", "b029517f6300c2da0f4b651b8642506cd6aaf45d"),
42+
file: expression.NewGetField(2, sql.Text, "file", false),
43+
row: sql.NewRow("worktree", "b029517f6300c2da0f4b651b8642506cd6aaf45d", ".gitignore"),
4244
testedLine: 0,
4345
lineCount: 12,
4446
expected: BlameLine{
45-
".gitignore",
4647
0,
4748
4849
"*.class",
@@ -53,11 +54,11 @@ func TestBlameEval(t *testing.T) {
5354
name: "changelog",
5455
repo: expression.NewGetField(0, sql.Text, "repository_id", false),
5556
commit: expression.NewGetField(1, sql.Text, "commit_hash", false),
56-
row: sql.NewRow("worktree", "b8e471f58bcbca63b07bda20e428190409c2db47"),
57+
file: expression.NewGetField(2, sql.Text, "file", false),
58+
row: sql.NewRow("worktree", "b8e471f58bcbca63b07bda20e428190409c2db47", "CHANGELOG"),
5759
testedLine: 0,
5860
lineCount: 1,
5961
expected: BlameLine{
60-
"CHANGELOG",
6162
0,
6263
6364
"Initial changelog",
@@ -68,7 +69,8 @@ func TestBlameEval(t *testing.T) {
6869
name: "no repo",
6970
repo: expression.NewGetField(0, sql.Text, "repository_id", false),
7071
commit: expression.NewGetField(1, sql.Text, "commit_hash", false),
71-
row: sql.NewRow("foo", "bar"),
72+
file: expression.NewGetField(2, sql.Text, "file", false),
73+
row: sql.NewRow("foo", "bar", "baz"),
7274
testedLine: 0,
7375
lineCount: 1,
7476
expected: BlameLine{},
@@ -78,7 +80,19 @@ func TestBlameEval(t *testing.T) {
7880
name: "no commit",
7981
repo: expression.NewGetField(0, sql.Text, "repository_id", false),
8082
commit: expression.NewGetField(1, sql.Text, "commit_hash", false),
81-
row: sql.NewRow("worktree", "foo"),
83+
file: expression.NewGetField(2, sql.Text, "file", false),
84+
row: sql.NewRow("worktree", "foo", "bar"),
85+
testedLine: 0,
86+
lineCount: 1,
87+
expected: BlameLine{},
88+
expectedNil: true,
89+
},
90+
{
91+
name: "no file",
92+
repo: expression.NewGetField(0, sql.Text, "repository_id", false),
93+
commit: expression.NewGetField(1, sql.Text, "commit_hash", false),
94+
file: expression.NewGetField(2, sql.Text, "file", false),
95+
row: sql.NewRow("worktree", "b8e471f58bcbca63b07bda20e428190409c2db47", "foo"),
8296
testedLine: 0,
8397
lineCount: 1,
8498
expected: BlameLine{},
@@ -88,7 +102,7 @@ func TestBlameEval(t *testing.T) {
88102

89103
for _, tc := range testCases {
90104
t.Run(tc.name, func(t *testing.T) {
91-
blame := NewBlame(tc.repo, tc.commit)
105+
blame := NewBlame(tc.repo, tc.commit, tc.file)
92106
blameGen, err := blame.Eval(ctx, tc.row)
93107
require.NoError(t, err)
94108

@@ -105,9 +119,6 @@ func TestBlameEval(t *testing.T) {
105119
lineCount := 0
106120
for i, err := bg.Next(); err == nil; i, err = bg.Next() {
107121
i := i.(BlameLine)
108-
if i.File != tc.expected.File {
109-
continue
110-
}
111122
if lineCount != tc.testedLine {
112123
lineCount++
113124
continue

internal/function/registry.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ var Functions = []sql.Function{
1717
sql.Function1{Name: "uast_children", Fn: NewUASTChildren},
1818
sql.Function1{Name: "uast_imports", Fn: NewUASTImports},
1919
sql.Function1{Name: "is_vendor", Fn: NewIsVendor},
20-
sql.Function2{Name: "blame", Fn: NewBlame},
20+
sql.Function3{Name: "blame", Fn: NewBlame},
2121
}

0 commit comments

Comments
 (0)