#8 implement interface Source and methods for gitea without Update #9
							
								
								
									
										6
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								go.mod
									
									
									
									
									
								
							@@ -11,6 +11,7 @@ require (
 | 
			
		||||
	github.com/jmoiron/sqlx v1.3.1
 | 
			
		||||
	github.com/pkg/errors v0.9.1
 | 
			
		||||
	github.com/spf13/cobra v1.8.0
 | 
			
		||||
	github.com/stretchr/testify v1.8.3
 | 
			
		||||
	go.unistack.org/micro-client-http/v4 v4.0.2
 | 
			
		||||
	go.unistack.org/micro-codec-json/v4 v4.0.0
 | 
			
		||||
	go.unistack.org/micro-codec-jsonpb/v4 v4.0.0
 | 
			
		||||
@@ -46,6 +47,7 @@ require (
 | 
			
		||||
	github.com/acomagu/bufpipe v1.0.4 // indirect
 | 
			
		||||
	github.com/cenkalti/backoff/v3 v3.2.2 // indirect
 | 
			
		||||
	github.com/cloudflare/circl v1.3.3 // indirect
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1 // indirect
 | 
			
		||||
	github.com/dustin/go-humanize v1.0.1 // indirect
 | 
			
		||||
	github.com/emirpasic/gods v1.18.1 // indirect
 | 
			
		||||
	github.com/fatih/structtag v1.2.0 // indirect
 | 
			
		||||
@@ -65,7 +67,7 @@ require (
 | 
			
		||||
	github.com/hashicorp/go-sockaddr v1.0.2 // indirect
 | 
			
		||||
	github.com/hashicorp/hcl v1.0.0 // indirect
 | 
			
		||||
	github.com/hashicorp/vault/api v1.9.2 // indirect
 | 
			
		||||
	github.com/iancoleman/strcase v0.3.0 // indirect
 | 
			
		||||
	github.com/iancoleman/strcase v0.2.0 // indirect
 | 
			
		||||
	github.com/imdario/mergo v0.3.16 // indirect
 | 
			
		||||
	github.com/jackc/chunkreader/v2 v2.0.1 // indirect
 | 
			
		||||
	github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530 // indirect
 | 
			
		||||
@@ -86,6 +88,7 @@ require (
 | 
			
		||||
	github.com/ncruces/go-strftime v0.1.9 // indirect
 | 
			
		||||
	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
 | 
			
		||||
	github.com/pjbgf/sha1cd v0.3.0 // indirect
 | 
			
		||||
	github.com/pmezard/go-difflib v1.0.0 // indirect
 | 
			
		||||
	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
 | 
			
		||||
	github.com/rs/zerolog v1.30.0 // indirect
 | 
			
		||||
	github.com/ryanuber/go-glob v1.0.0 // indirect
 | 
			
		||||
@@ -102,7 +105,6 @@ require (
 | 
			
		||||
	golang.org/x/sys v0.17.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.14.0 // indirect
 | 
			
		||||
	golang.org/x/time v0.3.0 // indirect
 | 
			
		||||
	golang.org/x/tools v0.11.0 // indirect
 | 
			
		||||
	gopkg.in/warnings.v0 v0.1.2 // indirect
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.1 // indirect
 | 
			
		||||
	lukechampine.com/uint128 v1.3.0 // indirect
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.sum
									
									
									
									
									
								
							@@ -1005,6 +1005,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 | 
			
		||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
 | 
			
		||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 | 
			
		||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 | 
			
		||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 | 
			
		||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										94
									
								
								internal/analyzer/coverage/coverage.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								internal/analyzer/coverage/coverage.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
package coverage
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"git.unistack.org/unistack-org/pkgdash/internal/models"
 | 
			
		||||
	"golang.org/x/tools/cover"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Analyze(ctx context.Context, dataCoverage io.Reader, pack models.Package) (float64, error) {
 | 
			
		||||
	calculcate, err := calculateFiles(dataCoverage)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mapCover := make(map[string]float64)
 | 
			
		||||
	{
 | 
			
		||||
		tree, err := GetTreeFromGit(ctx, pack.URL)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		list, err := tree.GoFileList("")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, f := range list {
 | 
			
		||||
			mapCover[f] = 0.0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cur := len(mapCover)
 | 
			
		||||
 | 
			
		||||
	for _, d := range calculcate.Files {
 | 
			
		||||
		file := strings.TrimPrefix(d.Name, pack.Name+"/")
 | 
			
		||||
		mapCover[file] = d.Coverage
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// check)
 | 
			
		||||
	if len(mapCover) != cur {
 | 
			
		||||
		fmt.Printf("add new keys, was: %d, has: %d", cur, len(mapCover))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//TODO add calculate full
 | 
			
		||||
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Data struct {
 | 
			
		||||
	Files []*calculateFile
 | 
			
		||||
	Set   bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type calculateFile struct {
 | 
			
		||||
	Name     string
 | 
			
		||||
	Coverage float64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func calculateFiles(coverSrc io.Reader) (d *Data, err error) {
 | 
			
		||||
	profiles, err := cover.ParseProfilesFromReader(coverSrc)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	d = new(Data)
 | 
			
		||||
	for _, profile := range profiles {
 | 
			
		||||
		fn := profile.FileName
 | 
			
		||||
		if profile.Mode == "set" {
 | 
			
		||||
			d.Set = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		d.Files = append(d.Files, &calculateFile{
 | 
			
		||||
			Name:     fn,
 | 
			
		||||
			Coverage: percentCovered(profile),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return d, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func percentCovered(p *cover.Profile) float64 {
 | 
			
		||||
	var total, covered int64
 | 
			
		||||
	for _, b := range p.Blocks {
 | 
			
		||||
		total += int64(b.NumStmt)
 | 
			
		||||
		if b.Count > 0 {
 | 
			
		||||
			covered += int64(b.NumStmt)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if total == 0 {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return float64(covered) / float64(total) * 100
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								internal/analyzer/coverage/coverage_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								internal/analyzer/coverage/coverage_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
package coverage
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"git.unistack.org/unistack-org/pkgdash/internal/models"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"os"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Test_Calculate(t *testing.T) {
 | 
			
		||||
	file, err := os.Open("cover_test.out")
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	defer func() {
 | 
			
		||||
		assert.Nil(t, file.Close())
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	dataFiles, err := calculateFiles(file)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotNil(t, dataFiles)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_Analyze(t *testing.T) {
 | 
			
		||||
	file, err := os.Open("cover_test.out")
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	defer func() {
 | 
			
		||||
		assert.Nil(t, file.Close())
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	analyze, err := Analyze(context.Background(), file, models.Package{
 | 
			
		||||
		Name: "go.unistack.org/micro/v4",
 | 
			
		||||
		URL:  "https://git.unistack.org/unistack-org/micro.git",
 | 
			
		||||
	})
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, analyze, 0.0)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								internal/analyzer/coverage/git.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								internal/analyzer/coverage/git.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
package coverage
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/go-git/go-git/v5"
 | 
			
		||||
	"github.com/go-git/go-git/v5/plumbing/filemode"
 | 
			
		||||
	"github.com/go-git/go-git/v5/plumbing/object"
 | 
			
		||||
	"github.com/go-git/go-git/v5/storage/memory"
 | 
			
		||||
	"os"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	fileNil = errors.New("file pointer is nil")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func GetTreeFromGit(ctx context.Context, url string) (*Tree, error) {
 | 
			
		||||
	cloneOpts := &git.CloneOptions{
 | 
			
		||||
		URL:      url,
 | 
			
		||||
		Progress: os.Stdout,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repo, err := git.CloneContext(ctx, memory.NewStorage(), nil, cloneOpts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ref, err := repo.Head()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("failed to get head: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	commit, err := repo.CommitObject(ref.Hash())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("failed to get commit: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tree, err := commit.Tree()
 | 
			
		||||
 | 
			
		||||
	return &Tree{tree}, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Tree struct {
 | 
			
		||||
	*object.Tree
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t Tree) GoFileList(pattern string) ([]string, error) {
 | 
			
		||||
	matcher, err := regexp.Compile(pattern)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var list []string
 | 
			
		||||
	err = t.Files().ForEach(func(file *object.File) error {
 | 
			
		||||
		if file == nil {
 | 
			
		||||
			return fileNil
 | 
			
		||||
		}
 | 
			
		||||
		if file.Mode == filemode.Regular && strings.HasSuffix(file.Name, ".go") && !strings.HasSuffix(file.Name, "_test.go") && matcher.MatchString(file.Name) {
 | 
			
		||||
			list = append(list, file.Name)
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return list, err
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user