gitcontrib

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 12, 2023 License: Apache-2.0 Imports: 13 Imported by: 0

README

gitcontrib: a Bonzai™ branch and standalone tool for git analysis

License

Usage

Navigate to a git repo in your terminal and run:

gitcontrib summary

or

gitcontrib s

See full documentation with:

gitcontrib help

Install

This command can be installed as a standalone program or composed into a Bonzai command tree.

Standalone

go install git.gvk.idi.ntnu.no/morngrar/gitcontrib/cmd/gitcontrib@latest

Composed into a Bonzai™ command tree

package z

import (
	Z "github.com/rwxrob/bonzai/z"
	gitcontrib "git.gvk.idi.ntnu.no/morngrar/gitcontrib"
)

var Cmd = &Z.Cmd{
	Name:     `z`,
	Commands: []*Z.Cmd{help.Cmd, gitcontrib.Cmd},
}

What is a Bonzai™ command tree?

Bonzai is a framework for creating composable command trees, which are multiplatform single-executable toolkits. Each subcommand can be imported into any other such command tree, or work as a standalone command tree, so that each toolkit creator can mix and match branches in their own command trees. It also comes with a simple way to autocomplete under bash and having embedded dynamic documentation.

See the library repo for more details, and the original command tree that seeded the creation of the framework for a concrete example other than gitcontrib.

Tab Completion

To activate bash completion just use the complete -C option from your .bashrc or command line. There is no messy sourcing required. All the completion is done by the program itself.

complete -C gitcontrib gitcontrib

If you don't have bash or tab completion check use the shortcut commands instead.

Embedded Documentation

All documentation (like manual pages) has been embedded into the source code of the application. See the source or run the program with help to access it.

This repo used the bonzai example template as a starting point. It is heavily modified, but some fragments may remain. Bonzai and that example is licensed under the Apache-2.0 license.

This project is itself also licensed under Apache-2.0

Documentation

Overview

Package example provides the Bonzai command branch of the same name.

Index

Constants

This section is empty.

Variables

View Source
var AuthorChangesCmd = &Z.Cmd{
	Name:    `authorchanges`,
	Summary: `lists the line changes per author in current branch`,
	Aliases: []string{"ach"},
	Call: func(_ *Z.Cmd, _ ...string) error {

		w := new(tabwriter.Writer)

		w.Init(os.Stdout, 8, 8, 0, '\t', 0)
		defer w.Flush()

		fmt.Fprintf(w, " %s\t%s\t%s\n", "Author", "Additions", "Deletions")
		fmt.Fprintf(w, " %s\t%s\t%s\n", "------", "---------", "---------")
		for k, v := range MapLineChanges() {
			fmt.Fprintf(w, " %s\t%d\t%d\n", k, v.Additions, v.Deletions)
		}

		return nil
	},
	Commands: []*Z.Cmd{help.Cmd},
}
View Source
var AuthorCommitsCmd = &Z.Cmd{
	Name:    `authorcommits`,
	Summary: `lists the number of commits per author in current dir`,
	Aliases: []string{"ac"},
	Call: func(_ *Z.Cmd, _ ...string) error {

		w := new(tabwriter.Writer)

		w.Init(os.Stdout, 8, 8, 0, '\t', 0)
		defer w.Flush()

		fmt.Fprintf(w, " %s\t%s\n", "Author", "Commits")
		fmt.Fprintf(w, " %s\t%s\n", "------", "-------")
		for k, v := range AuthorCommits() {
			fmt.Fprintf(w, " %s\t%d\n", k, v)
		}

		return nil
	},
	Commands: []*Z.Cmd{help.Cmd},
}
View Source
var Cmd = &Z.Cmd{

	Name:      `gitcontrib`,
	Summary:   `a command tree branch for analysing git author contributions`,
	Version:   `v0.2.0`,
	Copyright: `Copyright 2023 Svein-Kåre Bjørnsen`,
	License:   `Apache-2.0`,
	Source:    `git@git.gvk.idi.ntnu.no:morngrar/gitcontrib.git`,
	Issues:    `https://git.gvk.idi.ntnu.no/morngrar/gitcontrib/-/issues`,

	Commands: []*Z.Cmd{

		help.Cmd,

		AuthorChangesCmd, AuthorCommitsCmd, ContributionSummaryCmd,
		CsvCmd,
	},

	Dynamic: template.FuncMap{
		"uname": func(_ *Z.Cmd) string { return Z.Out("uname", "-a") },
		"dir":   func() string { return Z.Out("dir") },
		"pwd":   func() string { return Z.Out("pwd") },
	},

	Description: `
		The {{aka}} command is a command tree for analysing author
		contributions in git repositories. The most extensive overview is the
		'summary' subcommand, that has the alias 's'. This shows aggregated
		metrics like line change ratio and commit granularity per author.
		Larger numbers means higher contribution for all categories.
		`,
}

Cmd provides a Bonzai branch command that can be composed into Bonzai trees or used as a standalone with light wrapper (see cmd/).

View Source
var ContributionSummaryCmd = &Z.Cmd{
	Name:    `summary`,
	Summary: `lists commits, line changes and aggregated metrics`,
	Aliases: []string{"s"},
	Call: func(_ *Z.Cmd, _ ...string) error {

		commitMap := AuthorCommits()
		lineChangesMap := MapLineChanges()
		commitRatioMap := make(map[string]float64)
		lineRatioMap := make(map[string]float64)
		granularityMap := make(map[string]float64)

		commitTotal := 0
		for _, v := range commitMap {
			commitTotal += v
		}

		lineTotal := 0
		for _, v := range lineChangesMap {
			lineTotal += v.Sum()
		}

		for k, v := range lineChangesMap {
			linesum := v.Sum()
			lineRatio := float64(linesum) / float64(lineTotal)
			lineRatioMap[k] = lineRatio
			commitRatio := float64(commitMap[k]) / float64(commitTotal)
			commitRatioMap[k] = commitRatio
			granularityMap[k] = 1.0 / (float64(linesum) / float64(commitMap[k]))
		}

		w := new(tabwriter.Writer)

		w.Init(os.Stdout, 8, 8, 0, '\t', 0)

		fmt.Fprintf(w, " %s\t%s\t%s\t%s\t%s\t%s\t%s\n", "Author", "Commits", "Additions", "Deletions", "Line ratio", "Commit ratio", "Granularity")
		fmt.Fprintf(w, " %s\t%s\t%s\t%s\t%s\t%s\t%s\n", "------", "-------", "---------", "---------", "----------", "------------", "-----------")
		for k, v := range MapLineChanges() {
			fmt.Fprintf(w, " %s\t%v\t%v\t%v\t%.3f\t%.3f\t%.3f\n", k, commitMap[k], v.Additions, v.Deletions, lineRatioMap[k], commitRatioMap[k], granularityMap[k])
		}
		err := w.Flush()
		if err != nil {
			return fmt.Errorf("failed to flush output buffer: %w", err)
		}

		fmt.Printf(
			"\n Overall repo commit granularity: %.3f\n",
			1.0/(float64(lineTotal)/float64(commitTotal)),
		)

		return nil
	},
	Commands: []*Z.Cmd{help.Cmd},
}
View Source
var CsvAuthorChangesCmd = &Z.Cmd{
	Name:    `authorchanges`,
	Summary: `outputs CSV rows of the line changes per author in current branch`,
	Aliases: []string{"ach"},
	Description: `
		The {{aka}} subcommand gives the same output data as the  root
		subcommand of the same name, however, this one outputs CSV rows instead
		of the human-readable tabulated output of the original command. The
		first field of each row is the name of the repo directory itself, the
		rest follow the same order as the original command. Strings are wrapped
		in double quotes, and the CSV header is not printed to accomodate
		scripting.

		The fields of this command is the following, in the given order:

		Repo directory, Author, Additions, Deletions
		`,
	Call: func(_ *Z.Cmd, _ ...string) error {

		reponame, err := getRepoDirName()
		if err != nil {
			return fmt.Errorf("error getting repo name: %w", err)
		}

		for k, v := range MapLineChanges() {
			fmt.Printf(
				"\"%s\",\"%s\",%d,%d\n",
				reponame, k, v.Additions, v.Deletions,
			)
		}

		return nil
	},
	Commands: []*Z.Cmd{help.Cmd},
}

CsvAuthorChangesCmd provides a CSV-outputing equivalent of AuthorChangesCmd

View Source
var CsvAuthorCommitsCmd = &Z.Cmd{
	Name:    `authorcommits`,
	Summary: `outputs CSV rows with the number of commits per author in current dir`,
	Aliases: []string{"ac"},
	Description: `
		The {{aka}} subcommand gives the same output data as the  root
		subcommand of the same name, however, this one outputs CSV rows instead
		of the human-readable tabulated output of the original command. The
		first field of each row is the name of the repo directory itself, the
		rest follow the same order as the original command. Strings are wrapped
		in double quotes, and the CSV header is not printed to accomodate
		scripting.

		The fields of this command is the following, in the given order:

		Repo directory, Author, Commits
		`,
	Call: func(_ *Z.Cmd, _ ...string) error {

		reponame, err := getRepoDirName()
		if err != nil {
			return fmt.Errorf("error getting repo name: %w", err)
		}

		for k, v := range AuthorCommits() {
			fmt.Printf("\"%s\",\"%s\",%d\n", reponame, k, v)
		}

		return nil
	},
	Commands: []*Z.Cmd{help.Cmd},
}

CsvAuthorCommitsCmd provides a CSV-outputing equivalent of AuthorCommitsCmd

View Source
var CsvCmd = &Z.Cmd{
	Name:    `csv`,
	Summary: `outputs CSV rows for the various report`,
	Aliases: []string{"c"},
	Commands: []*Z.Cmd{

		help.Cmd,

		CsvAuthorChangesCmd, CsvAuthorCommitsCmd, CsvContributionSummaryCmd,
	},
	Description: `
		The {{aka}} subcommand supplies the same commands as the root command, 
		however, these output CSV rows instead of the human-readable tabulated
		output of the original commands. The first field of each row is the
		name of the repo directory itself, the rest follow the same order as 
		the original command. Strings are wrapped in double quotes.

		Do 'cmd COMMAND help' for further details.
		`,
}

CsvCmd provides a subtree command containing CSV-outputing equvalents of the basic `gitcontrib` reports.

View Source
var CsvContributionSummaryCmd = &Z.Cmd{
	Name:    `summary`,
	Summary: `outputs CSV rows for the 'summary' report`,
	Aliases: []string{"s"},
	Description: `

		The {{aka}} subcommand gives the same output data as the  root
		subcommand of the same name, however, this one outputs CSV rows instead
		of the human-readable tabulated output of the original command. The
		first field of each row is the name of the repo directory itself, the
		rest follow the same order as the original command. Strings are wrapped
		in double quotes, and the CSV header is not printed to accomodate
		scripting.

		The fields of this command is the following, in the given order:

		Repo directory, Author, Commits, Additions, Deletions, Line ratio,
		Commit ratio, Granularity.
		`,

	Call: func(_ *Z.Cmd, _ ...string) error {

		commitMap := AuthorCommits()
		lineChangesMap := MapLineChanges()
		commitRatioMap := make(map[string]float64)
		lineRatioMap := make(map[string]float64)
		granularityMap := make(map[string]float64)

		commitTotal := 0
		for _, v := range commitMap {
			commitTotal += v
		}

		lineTotal := 0
		for _, v := range lineChangesMap {
			lineTotal += v.Sum()
		}

		for k, v := range lineChangesMap {
			linesum := v.Sum()
			lineRatio := float64(linesum) / float64(lineTotal)
			lineRatioMap[k] = lineRatio
			commitRatio := float64(commitMap[k]) / float64(commitTotal)
			commitRatioMap[k] = commitRatio
			granularityMap[k] = 1.0 / (float64(linesum) / float64(commitMap[k]))
		}

		reponame, err := getRepoDirName()
		if err != nil {
			return fmt.Errorf("error getting repo name: %w", err)
		}

		for k, v := range MapLineChanges() {
			fmt.Printf("\"%s\",\"%s\",%v,%v,%v,%.3f,%.3f,%.3f\n", reponame, k, commitMap[k], v.Additions, v.Deletions, lineRatioMap[k], commitRatioMap[k], granularityMap[k])
		}

		return nil
	},
	Commands: []*Z.Cmd{help.Cmd},
}

CsvContributionSummaryCmd provides a CSV-outputing equivalent of ContributionSummaryCmd

Functions

func AuthorCommits

func AuthorCommits() map[string]int

AuthorCommits returns a map of author names with their respective non-merge commit counts as values

func MapLineChanges

func MapLineChanges() map[string]LineChanges

MapLineChanges returns an author map containing the line changes of each author in the current repo branch.

Types

type LineChanges

type LineChanges struct {
	Additions int
	Deletions int
}

func (*LineChanges) Add

func (lc *LineChanges) Add(n int)

func (*LineChanges) Del

func (lc *LineChanges) Del(n int)

func (*LineChanges) Sum

func (lc *LineChanges) Sum() int

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL