Skip to content

Commit

Permalink
fix #28: add github contribution diff command
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilsk committed Jun 3, 2022
1 parent 85bb224 commit fc48373
Show file tree
Hide file tree
Showing 10 changed files with 412 additions and 80 deletions.
20 changes: 10 additions & 10 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@

- Add support GitHub Access Token by parameter

You could still provide it by the environment variable
You could still provide it by the environment variable

```bash
$ export GITHUB_TOKEN=secret
$ maintainer github ...
```
```bash
$ export GITHUB_TOKEN=secret
$ maintainer github ...
```

But now, you also could choose the parameter for its provisioning
But now, you also could choose the parameter for its provisioning

```bash
$ maintainer github --token=secret ...
```
```bash
$ maintainer github --token=secret ...
```

- Add commands to work with GitHub Contributions Calendar

Expand Down Expand Up @@ -61,7 +61,7 @@ $ maintainer github --token=secret ...
* Makes a snapshot of contributions for a specified year

```bash
$ maintainer github contribution snapshot 2013 | tee snap.2013.json | jq
$ maintainer github contribution snapshot 2013 | tee /tmp/snap.01.2013.json | jq
{
"2013-11-13T00:00:00Z": 1,
...
Expand Down
18 changes: 9 additions & 9 deletions docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@

- Add support GitHub Access Token by parameter

You could still provide it by the environment variable
You could still provide it by the environment variable

```bash
$ export GITHUB_TOKEN=secret
$ maintainer github ...
```
```bash
$ export GITHUB_TOKEN=secret
$ maintainer github ...
```

But now, you also could choose the parameter for its provisioning
But now, you also could choose the parameter for its provisioning

```bash
$ maintainer github --token=secret ...
```
```bash
$ maintainer github --token=secret ...
```

- Add commands to work with GitHub Contributions Calendar

Expand Down
191 changes: 149 additions & 42 deletions internal/command/github/contribution.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"go.octolab.org/toolset/maintainer/internal/command/github/view"
"go.octolab.org/toolset/maintainer/internal/config"
"go.octolab.org/toolset/maintainer/internal/model/github/contribution"
"go.octolab.org/toolset/maintainer/internal/pkg/config/flag"
"go.octolab.org/toolset/maintainer/internal/pkg/http"
"go.octolab.org/toolset/maintainer/internal/pkg/time"
"go.octolab.org/toolset/maintainer/internal/service/github"
Expand All @@ -21,6 +22,103 @@ func Contribution(cnf *config.Tool) *cobra.Command {
Use: "contribution",
}

//
// $ maintainer github contribution diff --base=/tmp/snap.01.2013.json --head=/tmp/snap.02.2013.json
//
// Day / Week #46 #48 #49 #50
// ---------------------- --------------- --------------- --------------- -----------
// Sunday - - - -
// Monday - - - -
// Tuesday - - - -
// Wednesday +4 - +1 -
// Thursday - - - +1
// Friday - +2 - -
// Saturday - - - -
// ---------------------- --------------- --------------- --------------- -----------
// The diff between head{"/tmp/snap.02.2013.json"} → base{"/tmp/snap.01.2013.json"}
//
// $ maintainer github contribution diff --base=/tmp/snap.01.2013.json 2013
//
diff := cobra.Command{
Use: "diff",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// dependencies and defaults
service := github.New(http.TokenSourcedClient(cmd.Context(), cnf.Token))
date := time.TruncateToYear(time.Now().UTC())

// input validation: files{params}, date(year){args}
var baseSource, headSource string
dst, err := flag.Adopt(cmd.Flags()).GetFile("base")
if err != nil {
return err
}
if dst == nil {
return fmt.Errorf("please provide a base file by `--base` parameter")
}
baseSource = dst.Name()

src, err := flag.Adopt(cmd.Flags()).GetFile("head")
if err != nil {
return err
}
if src == nil && len(args) == 0 {
return fmt.Errorf("please provide a compared file by `--head` parameter or year in args")
}
if src != nil && len(args) > 0 {
return fmt.Errorf("please omit `--head` or argument, only one of them is allowed")
}
if len(args) == 1 {
var err error
wrap := func(err error) error {
return fmt.Errorf(
"please provide argument in format YYYY, e.g., 2006: %w",
fmt.Errorf("invalid argument %q: %w", args[0], err),
)
}

switch input := args[0]; len(input) {
case len(time.RFC3339Year):
date, err = time.Parse(time.RFC3339Year, input)
default:
err = fmt.Errorf("unsupported format")
}
if err != nil {
return wrap(err)
}
headSource = fmt.Sprintf("upstream:year(%s)", date.Format(time.RFC3339Year))
} else {
headSource = src.Name()
}

// data provisioning
var (
base contribution.HeatMap
head contribution.HeatMap
)
if err := json.NewDecoder(dst).Decode(&base); err != nil {
return err
}
if src != nil {
if err := json.NewDecoder(src).Decode(&head); err != nil {
return err
}
} else {
scope := time.RangeByYears(date, 0, false).ExcludeFuture()
head, err = service.ContributionHeatMap(cmd.Context(), scope)
if err != nil {
return err
}
}

// data presentation
return view.Diff(cmd, base.Diff(head), baseSource, headSource)
},
}
flag.Adopt(diff.Flags()).File("base", "", "path to a base file")
flag.Adopt(diff.Flags()).File("head", "", "path to a head file")
cmd.AddCommand(&diff)

//
// $ maintainer github contribution histogram 2013
//
Expand Down Expand Up @@ -163,6 +261,57 @@ func Contribution(cnf *config.Tool) *cobra.Command {
}
cmd.AddCommand(&lookup)

//
// $ maintainer github contribution snapshot 2013 | tee /tmp/snap.01.2013.json | jq
//
// {
// "2013-11-13T00:00:00Z": 1,
// ...
// "2013-12-27T00:00:00Z": 2
// }
//
snapshot := cobra.Command{
Use: "snapshot",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// dependencies and defaults
service := github.New(http.TokenSourcedClient(cmd.Context(), cnf.Token))
date := time.TruncateToYear(time.Now().UTC())

// input validation: date(year)
if len(args) == 1 {
var err error
wrap := func(err error) error {
return fmt.Errorf(
"please provide argument in format YYYY, e.g., 2006: %w",
fmt.Errorf("invalid argument %q: %w", args[0], err),
)
}

switch input := args[0]; len(input) {
case len(time.RFC3339Year):
date, err = time.Parse(time.RFC3339Year, input)
default:
err = fmt.Errorf("unsupported format")
}
if err != nil {
return wrap(err)
}
}

// data provisioning
scope := time.RangeByYears(date, 0, false).ExcludeFuture()
chm, err := service.ContributionHeatMap(cmd.Context(), scope)
if err != nil {
return err
}

// data presentation
return json.NewEncoder(cmd.OutOrStdout()).Encode(chm)
},
}
cmd.AddCommand(&snapshot)

//
// $ maintainer github contribution suggest 2013-11-20
//
Expand Down Expand Up @@ -277,47 +426,5 @@ func Contribution(cnf *config.Tool) *cobra.Command {
}
cmd.AddCommand(&suggest)

snapshot := cobra.Command{
Use: "snapshot",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// dependencies and defaults
service := github.New(http.TokenSourcedClient(cmd.Context(), cnf.Token))
date := time.TruncateToYear(time.Now().UTC())

// input validation: date(year)
if len(args) == 1 {
var err error
wrap := func(err error) error {
return fmt.Errorf(
"please provide argument in format YYYY, e.g., 2006: %w",
fmt.Errorf("invalid argument %q: %w", args[0], err),
)
}

switch input := args[0]; len(input) {
case len(time.RFC3339Year):
date, err = time.Parse(time.RFC3339Year, input)
default:
err = fmt.Errorf("unsupported format")
}
if err != nil {
return wrap(err)
}
}

// data provisioning
scope := time.RangeByYears(date, 0, false).ExcludeFuture()
chm, err := service.ContributionHeatMap(cmd.Context(), scope)
if err != nil {
return err
}

// data presentation
return json.NewEncoder(cmd.OutOrStdout()).Encode(chm)
},
}
cmd.AddCommand(&snapshot)

return &cmd
}
87 changes: 87 additions & 0 deletions internal/command/github/view/diff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package view

import (
"fmt"
"github.com/alexeyco/simpletable"

"go.octolab.org/toolset/maintainer/internal/model/github/contribution"
"go.octolab.org/toolset/maintainer/internal/pkg/time"
)

func Diff(
printer interface{ Println(...interface{}) },
heatmap contribution.HeatMap,
base, head string,
) error {
data := prepare(heatmap)
table := simpletable.New()

if len(data) == 0 {
printer.Println(fmt.Sprintf("There is no diff between head{%q} → base{%q}", head, base))
return nil
}

table.Header = &simpletable.Header{
Cells: []*simpletable.Cell{
{Align: simpletable.AlignLeft, Text: "Day / Week"},
},
}
for i, week := range data {
if shiftIsNeeded(i, week.Report) {
continue
}
table.Header.Cells = append(table.Header.Cells, &simpletable.Cell{
Align: simpletable.AlignCenter,
Text: fmt.Sprintf("#%d", week.Number),
})
}

// shift Sunday to the right
row := make([]*simpletable.Cell, 0, 4)
row = append(row, &simpletable.Cell{Text: time.Sunday.String()})
for i := range data {
if shiftIsNeeded(i, data[i].Report) {
continue
}
// TODO:unclear explain
if i == 0 {
row = append(row, &simpletable.Cell{Align: simpletable.AlignCenter, Text: "-"})
continue
}
txt := "-"
if count := data[i-1].Report[time.Sunday]; count != 0 {
txt = fmt.Sprintf("%+d", count)
}
row = append(row, &simpletable.Cell{Align: simpletable.AlignCenter, Text: txt})
}
table.Body.Cells = append(table.Body.Cells, row)

for i := time.Monday; i <= time.Saturday; i++ {
row = make([]*simpletable.Cell, 0, 4)
row = append(row, &simpletable.Cell{Text: i.String()})
for j, week := range data {
if shiftIsNeeded(j, week.Report) {
continue
}
txt := "-"
if count := week.Report[i]; count != 0 {
txt = fmt.Sprintf("%+d", count)
}
row = append(row, &simpletable.Cell{Align: simpletable.AlignCenter, Text: txt})
}
table.Body.Cells = append(table.Body.Cells, row)
}

table.Footer = &simpletable.Footer{
Cells: []*simpletable.Cell{
{
Span: len(table.Header.Cells),
Text: fmt.Sprintf("The diff between head{%q} → base{%q}", head, base),
},
},
}

table.SetStyle(simpletable.StyleCompactLite)
printer.Println(table.String())
return nil
}
Loading

0 comments on commit fc48373

Please sign in to comment.