Selaa lähdekoodia

Update docs and run go fmt

Vadim Markovtsev 7 vuotta sitten
vanhempi
commit
3c62e0ad93
9 muutettua tiedostoa jossa 110 lisäystä ja 65 poistoa
  1. 4 4
      blob_cache_test.go
  2. 8 8
      burndown_test.go
  3. 21 0
      cmd/hercules/main.go
  4. 49 28
      doc.go
  5. 1 1
      identity.go
  6. 9 6
      identity_test.go
  7. 6 6
      mailmap.go
  8. 1 1
      mailmap_test.go
  9. 11 11
      tree_diff_test.go

+ 4 - 4
blob_cache_test.go

@@ -195,8 +195,8 @@ func TestBlobCacheGetBlob(t *testing.T) {
 	}
 	getter := func(path string) (*object.File, error) {
 		assert.Equal(t, path, ".gitmodules")
-    commit, _ := testRepository.CommitObject(plumbing.NewHash(
-		  "13272b66c55e1ba1237a34104f30b84d7f6e4082"))
+		commit, _ := testRepository.CommitObject(plumbing.NewHash(
+			"13272b66c55e1ba1237a34104f30b84d7f6e4082"))
 		return commit.File("test_data/gitmodules")
 	}
 	blob, err := cache.getBlob(&entry, getter)
@@ -205,8 +205,8 @@ func TestBlobCacheGetBlob(t *testing.T) {
 	assert.Equal(t, err.Error(), plumbing.ErrObjectNotFound.Error())
 	getter = func(path string) (*object.File, error) {
 		assert.Equal(t, path, ".gitmodules")
-    commit, _ := testRepository.CommitObject(plumbing.NewHash(
-		  "13272b66c55e1ba1237a34104f30b84d7f6e4082"))
+		commit, _ := testRepository.CommitObject(plumbing.NewHash(
+			"13272b66c55e1ba1237a34104f30b84d7f6e4082"))
 		return commit.File("test_data/gitmodules_empty")
 	}
 	blob, err = cache.getBlob(&entry, getter)

+ 8 - 8
burndown_test.go

@@ -4,8 +4,8 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	"gopkg.in/src-d/go-git.v4/plumbing/object"
 	"gopkg.in/src-d/go-git.v4/plumbing"
+	"gopkg.in/src-d/go-git.v4/plumbing/object"
 )
 
 func TestBurndownMeta(t *testing.T) {
@@ -20,8 +20,8 @@ func TestBurndownMeta(t *testing.T) {
 
 func TestBurndownConsume(t *testing.T) {
 	burndown := BurndownAnalysis{
-		Granularity: 30,
-		Sampling: 30,
+		Granularity:  30,
+		Sampling:     30,
 		PeopleNumber: 1,
 	}
 	burndown.Initialize(testRepository)
@@ -37,7 +37,7 @@ func TestBurndownConsume(t *testing.T) {
 	cache[hash], _ = testRepository.BlobObject(hash)
 	deps["blob_cache"] = cache
 	changes := make(object.Changes, 2)
-  treeFrom, _ := testRepository.TreeObject(plumbing.NewHash(
+	treeFrom, _ := testRepository.TreeObject(plumbing.NewHash(
 		"a1eb2ea76eb7f9bfbde9b243861474421000eb96"))
 	treeTo, _ := testRepository.TreeObject(plumbing.NewHash(
 		"4d3f9500c2b9dc10925ad1705926b67f0f9101ca"))
@@ -77,14 +77,14 @@ func TestBurndownConsume(t *testing.T) {
 	assert.Equal(t, burndown.files[".travis.yml"].Len(), 12)
 	assert.Equal(t, burndown.files["analyser.go"].Len(), 309)
 	assert.Equal(t, len(burndown.people), 1)
-	assert.Equal(t, burndown.people[0][0], int64(12 + 309))
+	assert.Equal(t, burndown.people[0][0], int64(12+309))
 	assert.Equal(t, len(burndown.globalStatus), 1)
-	assert.Equal(t, burndown.globalStatus[0], int64(12 + 309))
+	assert.Equal(t, burndown.globalStatus[0], int64(12+309))
 	assert.Equal(t, len(burndown.globalHistory), 0)
 	assert.Equal(t, len(burndown.fileHistories), 0)
 	burndown = BurndownAnalysis{
-		Granularity: 30,
-		Sampling: 0,
+		Granularity:  30,
+		Sampling:     0,
 		PeopleNumber: 0,
 	}
 	burndown.Initialize(testRepository)

+ 21 - 0
cmd/hercules/main.go

@@ -3,6 +3,27 @@ Package main provides the command line tool to gather the line burndown
 statistics from Git repositories. Usage:
 
 	hercules <URL or FS path>
+
+Output is always written to stdout, progress is written to stderr.
+Output formats:
+
+- YAML (default)
+- Protocol Buffers (-pb)
+
+Extensions:
+
+-files include line burndown stats for each file alive in HEAD
+-people include line burndown stats for each developer
+-couples include coupling betwwen files and developers
+
+-granularity sets the number of days in each band of the burndown charts.
+-sampling set the frequency of measuring the state of burndown in days.
+
+-people-dict allows to specify a hand-crafted identity matching list. The format is text,
+each identity on separate line, matching names and emails separated with |
+
+-debug activates the debugging mode - hardly ever needed, used internally during the development.
+-profile activates the profile collection and runs the server on localhost:6060
 */
 package main
 

+ 49 - 28
doc.go

@@ -1,39 +1,60 @@
 /*
-Package hercules contains the functions which are needed to gather the line
-burndown statistics from a Git repository.
+Package hercules contains the functions which are needed to gather various statistics
+from a Git repository.
 
-Analyser is the main object which concentrates the high level logic. It
-provides Commits() and Analyse() methods to get the work done. The following
-example was taken from cmd/hercules:
+The analysis is expressed in a form of the tree: there are nodes - "pipeline items" - which
+require some other nodes to be executed prior to selves and in turn provide the data for
+dependent nodes. There are several service items which do not produce any useful
+statistics but rather provide the requirements for other items. The top-level items
+are:
+
+- BurndownAnalysis - line burndown statistics for project, files and developers.
+- Couples - coupling statistics for files and developers.
+
+The typical API usage is to initialize the Pipeline class:
+
+  import "gopkg.in/src-d/go-git.v4"
 
 	var repository *git.Repository
-	// ... initialize repository ...
-	analyser := hercules.Analyser{
-		Repository: repository,
-		OnProgress: func(commit, length int) {
-			fmt.Fprintf(os.Stderr, "%d / %d\r", commit, length)
-		},
-		Granularity:         30,
-		Sampling:            15,
-		SimilarityThreshold: 90,
-		Debug:               false,
-	}
-	commits := analyser.Commits()  // or specify a custom list
-	statuses := analyser.Analyse(commits)
-	// [y][x]int64 where y is the snapshot index and x is the granulated time index.
-
-As commented in the code, the list of commits can be any valid slice of *object.Commit.
-The returned statuses slice of slices is a rectangular 2D matrix where
-the number of rows equals to the repository's lifetime divided by the sampling
-value (detail factor) and the number of columns is the repository's lifetime
-divided by the granularity value (number of bands).
-
-Analyser depends heavily on https://github.com/src-d/go-git and leverages the
+	// ...initialize repository...
+	pipeline := hercules.NewPipeline(repository)
+
+Then add the required analysis tree nodes:
+
+  pipeline.AddItem(&hercules.BlobCache{})
+	pipeline.AddItem(&hercules.DaysSinceStart{})
+	pipeline.AddItem(&hercules.TreeDiff{})
+	pipeline.AddItem(&hercules.RenameAnalysis{SimilarityThreshold: 80})
+	pipeline.AddItem(&hercules.IdentityDetector{})
+
+Then initialize BurndownAnalysis:
+
+  burndowner := &hercules.BurndownAnalysis{
+    Granularity:  30,
+		Sampling:     30,
+  }
+  pipeline.AddItem(burndowner)
+
+Then execute the analysis tree:
+
+  pipeline.Initialize()
+	result, err := pipeline.Run(commits)
+
+Finally extract the result:
+
+  burndownResults := result[burndowner].(hercules.BurndownResult)
+
+The actual usage example is cmd/hercules/main.go - the command line tool's code.
+
+Hercules depends heavily on https://github.com/src-d/go-git and leverages the
 diff algorithm through https://github.com/sergi/go-diff.
 
 Besides, hercules defines File and RBTree. These are low level data structures
-required by Analyser. File carries an instance of RBTree and the current line
+required by BurndownAnalysis. File carries an instance of RBTree and the current line
 burndown state. RBTree implements the red-black balanced binary tree and is
 based on https://github.com/yasushi-saito/rbtree.
+
+Coupling stats are supposed to be further processed rather than observed directly.
+labours.py uses Swivel embeddings and visualises them in Tensorflow Projector.
 */
 package hercules

+ 1 - 1
identity.go

@@ -82,7 +82,7 @@ func (id *IdentityDetector) GeneratePeopleDict(commits []*object.Commit) {
 	names := map[int][]string{}
 	size := 0
 
-	mailmapFile, err := commits[len(commits) - 1].File(".mailmap")
+	mailmapFile, err := commits[len(commits)-1].File(".mailmap")
 	if err == nil {
 		mailMapContents, err := mailmapFile.Contents()
 		if err == nil {

+ 9 - 6
identity_test.go

@@ -17,7 +17,7 @@ func fixtureIdentityDetector() *IdentityDetector {
 	reversePeopleDict := make([]string, 1)
 	reversePeopleDict[0] = "Vadim"
 	id := IdentityDetector{
-		PeopleDict: peopleDict,
+		PeopleDict:        peopleDict,
 		ReversePeopleDict: reversePeopleDict,
 	}
 	id.Initialize(testRepository)
@@ -50,7 +50,7 @@ func TestIdentityDetectorConsume(t *testing.T) {
 
 func TestLoadPeopleDict(t *testing.T) {
 	id := fixtureIdentityDetector()
-  err := id.LoadPeopleDict(path.Join("test_data", "identities"))
+	err := id.LoadPeopleDict(path.Join("test_data", "identities"))
 	assert.Nil(t, err)
 	assert.Equal(t, len(id.PeopleDict), 7)
 	assert.Contains(t, id.PeopleDict, "linus torvalds")
@@ -96,21 +96,24 @@ func TestGeneratePeopleDict(t *testing.T) {
 	}
 	{
 		i := 0
-		for ; commits[i].Author.Name != "Vadim Markovtsev"; i++ {}
+		for ; commits[i].Author.Name != "Vadim Markovtsev"; i++ {
+		}
 		if i > 0 {
 			commit := commits[0]
 			commits[0] = commits[i]
 			commits[i] = commit
 		}
 		i = 1
-		for ; commits[i].Author.Name != "Alexander Bezzubov"; i++ {}
+		for ; commits[i].Author.Name != "Alexander Bezzubov"; i++ {
+		}
 		if i > 0 {
 			commit := commits[1]
 			commits[1] = commits[i]
 			commits[i] = commit
 		}
 		i = 2
-		for ; commits[i].Author.Name != "Máximo Cuadros"; i++ {}
+		for ; commits[i].Author.Name != "Máximo Cuadros"; i++ {
+		}
 		if i > 0 {
 			commit := commits[2]
 			commits[2] = commits[i]
@@ -119,7 +122,7 @@ func TestGeneratePeopleDict(t *testing.T) {
 	}
 	id.GeneratePeopleDict(commits)
 	assert.True(t, len(id.PeopleDict) >= 7)
-  assert.True(t, len(id.ReversePeopleDict) >= 3)
+	assert.True(t, len(id.ReversePeopleDict) >= 3)
 	assert.Equal(t, id.PeopleDict["vadim markovtsev"], 0)
 	assert.Equal(t, id.PeopleDict["vadim@sourced.tech"], 0)
 	assert.Equal(t, id.PeopleDict["gmarkhor@gmail.com"], 0)

+ 6 - 6
mailmap.go

@@ -11,7 +11,7 @@ import (
 // matching convention, that is, developers are identified by email
 // and by name independently.
 func ParseMailmap(contents string) map[string]object.Signature {
-  mm := map[string]object.Signature{}
+	mm := map[string]object.Signature{}
 	lines := strings.Split(contents, "\n")
 	for _, line := range lines {
 		line = strings.TrimSpace(line)
@@ -21,21 +21,21 @@ func ParseMailmap(contents string) map[string]object.Signature {
 		if strings.HasPrefix(line, "#") {
 			continue
 		}
-		if strings.LastIndex(line, ">") != len(line) - 1 {
+		if strings.LastIndex(line, ">") != len(line)-1 {
 			continue
 		}
 		ltp := strings.LastIndex(line, "<")
-		fromEmail := line[ltp + 1:len(line) - 1]
+		fromEmail := line[ltp+1 : len(line)-1]
 		line = strings.TrimSpace(line[:ltp])
 		gtp := strings.LastIndex(line, ">")
 		fromName := ""
-		if gtp != len(line) - 1 {
-			fromName = strings.TrimSpace(line[gtp + 1:])
+		if gtp != len(line)-1 {
+			fromName = strings.TrimSpace(line[gtp+1:])
 		}
 		toEmail := ""
 		if gtp > 0 {
 			ltp = strings.LastIndex(line, "<")
-			toEmail = line[ltp + 1:gtp]
+			toEmail = line[ltp+1 : gtp]
 			line = strings.TrimSpace(line[:ltp])
 		}
 		toName := line

+ 1 - 1
mailmap_test.go

@@ -1,8 +1,8 @@
 package hercules
 
 import (
-	"testing"
 	"github.com/stretchr/testify/assert"
+	"testing"
 )
 
 func TestParseMailmap(t *testing.T) {

+ 11 - 11
tree_diff_test.go

@@ -38,18 +38,18 @@ func TestTreeDiffConsume(t *testing.T) {
 	changes := res["changes"].(object.Changes)
 	assert.Equal(t, len(changes), 12)
 	baseline := map[string]merkletrie.Action{
-		"analyser.go": merkletrie.Delete,
-		"cmd/hercules/main.go": merkletrie.Modify,
-		"blob_cache.go": merkletrie.Insert,
-		"burndown.go": merkletrie.Insert,
-		"day.go": merkletrie.Insert,
-		"dummies.go": merkletrie.Insert,
-		"identity.go": merkletrie.Insert,
-		"pipeline.go": merkletrie.Insert,
-		"renames.go": merkletrie.Insert,
-		"toposort/toposort.go": merkletrie.Insert,
+		"analyser.go":               merkletrie.Delete,
+		"cmd/hercules/main.go":      merkletrie.Modify,
+		"blob_cache.go":             merkletrie.Insert,
+		"burndown.go":               merkletrie.Insert,
+		"day.go":                    merkletrie.Insert,
+		"dummies.go":                merkletrie.Insert,
+		"identity.go":               merkletrie.Insert,
+		"pipeline.go":               merkletrie.Insert,
+		"renames.go":                merkletrie.Insert,
+		"toposort/toposort.go":      merkletrie.Insert,
 		"toposort/toposort_test.go": merkletrie.Insert,
-		"tree_diff.go": merkletrie.Insert,
+		"tree_diff.go":              merkletrie.Insert,
 	}
 	for _, change := range changes {
 		action, err := change.Action()