tools/passes/apicovered/apicovered.go (112 lines of code) (raw):

package apicovered import ( "fmt" "io" "os" "reflect" "sort" "text/tabwriter" "golang.org/x/tools/go/analysis" "gitlab.com/gitlab-org/terraform-provider-gitlab/tools/passes" clientgo "gitlab.com/gitlab-org/terraform-provider-gitlab/tools/passes/clientgo" "gitlab.com/gitlab-org/terraform-provider-gitlab/tools/passes/usage" ) var Output io.Writer = io.Discard var Analyzer = &analysis.Analyzer{ Doc: "Estimate usage of the client-go package", Name: "apicovered", ResultType: reflect.TypeOf((*Result)(nil)), Requires: []*analysis.Analyzer{clientgo.Analyzer, usage.Analyzer}, Run: run, } type Result struct { CoverageByFile map[string]Fraction } type Fraction struct { Count int Total int } func run(pass *analysis.Pass) (interface{}, error) { clientGo := pass.ResultOf[clientgo.Analyzer].(*clientgo.Result) usage := pass.ResultOf[usage.Analyzer].(*usage.Result) result := &Result{ CoverageByFile: make(map[string]Fraction), } process(result, clientGo.TypeToFilenames, usage.Types) process(result, clientGo.FuncToFilenames, usage.Funcs) process(result, clientGo.MethodToFilenames, usage.Methods) process(result, clientGo.FieldToFilenames, usage.Fields) if !passes.IsTestPackage(pass) { writeOutput(result) } return result, nil } func process(result *Result, nameToFilenames clientgo.MultiMap, seen usage.Set) { for _, filenames := range nameToFilenames { for _, filename := range filenames { coverage := result.CoverageByFile[filename] coverage.Total++ result.CoverageByFile[filename] = coverage } } for name := range seen { for _, filename := range nameToFilenames[name] { coverage := result.CoverageByFile[filename] coverage.Count++ result.CoverageByFile[filename] = coverage } } } func writeOutput(result *Result) { type row struct { filename string coverageString string coveragePercent int } newRow := func(filename string, fraction Fraction) row { return row{ filename: filename, coverageString: fmt.Sprintf("%d/%d", fraction.Count, fraction.Total), coveragePercent: makePercent(fraction.Count, fraction.Total), } } var rows []row for filename, coverage := range result.CoverageByFile { rows = append(rows, newRow(filename, coverage)) } sort.Slice(rows, func(i, j int) bool { if rows[i].coveragePercent == rows[j].coveragePercent { return rows[i].filename < rows[j].filename } return rows[i].coveragePercent < rows[j].coveragePercent }) totalRow := func() row { var totalCoverage Fraction for _, coverage := range result.CoverageByFile { totalCoverage.Count += coverage.Count totalCoverage.Total += coverage.Total } return newRow("Total", totalCoverage) }() w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) writeRow := func(row row) { fmt.Fprintf(w, "%s\t%d%%\t%s\n", row.filename, row.coveragePercent, row.coverageString) } fmt.Fprintf(w, "Filename\tCoverage\tLines\n") fmt.Fprintln(w, "--------\t--------\t-----") for _, row := range rows { writeRow(row) } fmt.Fprintln(w, "---\t---\t---") writeRow(totalRow) w.Flush() } func makePercent(n, d int) int { if d == 0 { if n == 0 { return 100 } return 0 } return 100 * n / d }