Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ vet:
@go vet ./...
@echo "ok"

build: tidy check
build: tidy format check
@echo "build storage"
@go build -o bin/community ./cmd/community
@echo "ok"
Expand Down
1 change: 1 addition & 0 deletions cmd/community/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var app = &cli.App{
Usage: "community tools for open source society",
Commands: []*cli.Command{
teamCmd,
reportCmd,
},
}

Expand Down
94 changes: 94 additions & 0 deletions cmd/community/report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package main

import (
"context"
"errors"
"fmt"
"strings"

"github.com/urfave/cli/v2"
"go.uber.org/zap"

"github.com/beyondstorage/go-community/env"
"github.com/beyondstorage/go-community/services"
)

var reportCmd = &cli.Command{
Name: "report",
Usage: "maintain community reports",
Subcommands: []*cli.Command{
reportWeeklyCmd,
},
}

var reportWeeklyCmd = &cli.Command{
Name: "weekly",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "type",
Usage: "type of report",
Required: true,
Value: "issue",
},
&cli.StringFlag{
Name: "output",
Usage: "destination of report",
Required: true,
},
&cli.StringFlag{
Name: "owner",
Usage: "github organization name",
Required: true,
EnvVars: []string{
env.GithubOwner,
},
},
&cli.StringFlag{
Name: "token",
Usage: "github access token",
Required: true,
EnvVars: []string{
env.GithubAccessToken,
},
},
},
Action: func(c *cli.Context) error {
logger, _ := zap.NewDevelopment()

g, err := services.NewGithub(
c.String("owner"),
c.String("token"))
if err != nil {
return err
}

ctx := context.Background()

repos, err := g.ListRepos(ctx, c.String("owner"))
if err != nil {
return err
}

b := &strings.Builder{}

for _, v := range repos {
content, err := g.GenerateReport(ctx, c.String("owner"), v)
if err != nil {
return nil
}
b.WriteString(content)
}

if c.String("type") != "issue" {
logger.Error("not supported report type", zap.String("type", c.String("type")))
return errors.New("not supported type")
}

url, err := g.CreateWeeklyReportIssue(ctx, c.String("output"), b.String())
if err != nil {
return err
}
fmt.Printf("Create issue %s\n", url)
return nil
},
}
4 changes: 3 additions & 1 deletion cmd/community/team.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package main

import (
"context"

"github.com/urfave/cli/v2"

"github.com/beyondstorage/go-community/env"
"github.com/beyondstorage/go-community/model"
"github.com/beyondstorage/go-community/services"
"github.com/urfave/cli/v2"
)

var teamCmd = &cli.Command{
Expand Down
169 changes: 157 additions & 12 deletions services/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ package services
import (
"context"
"fmt"
"github.com/beyondstorage/go-community/model"
"sort"
"strings"
"time"

"github.com/google/go-github/v35/github"
"go.uber.org/zap"
"golang.org/x/oauth2"

"github.com/beyondstorage/go-community/model"
)

var (
Expand Down Expand Up @@ -46,24 +51,32 @@ func (g *Github) ListRepos(ctx context.Context, org string) ([]string, error) {
opt := &github.RepositoryListByOrgOptions{
Type: "public",
ListOptions: github.ListOptions{
PerPage: 100, // hard code for POC
PerPage: 100,
},
}
repos, _, err := g.client.Repositories.ListByOrg(ctx, org, opt)
if err != nil {
g.logger.Error("list repos", zap.Error(err))
return nil, err
}

rs := make([]string, 0)
for {
repos, resp, err := g.client.Repositories.ListByOrg(ctx, org, opt)
if err != nil {
g.logger.Error("list repos", zap.Error(err))
return nil, err
}

for _, v := range repos {
if v.GetArchived() {
g.logger.Info("ignore archived repo", zap.String("repo", v.GetName()))
for _, v := range repos {
if v.GetArchived() {
g.logger.Info("ignore archived repo", zap.String("repo", v.GetName()))
}
rs = append(rs, v.GetName())
g.logger.Info("repo", zap.String("repo", v.GetName()))
}
rs = append(rs, v.GetName())
g.logger.Info("repo", zap.String("repo", v.GetName()))

if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}

return rs, nil
}

Expand Down Expand Up @@ -126,6 +139,87 @@ func (g *Github) SyncTeam(ctx context.Context, teams model.Teams) (err error) {
return
}

func (g *Github) GenerateReport(ctx context.Context, org, repo string) (content string, err error) {
events, err := g.listEvents(ctx, org, repo)
if err != nil {
return "", err
}

b := &strings.Builder{}
// Add front line with repo name.
// ## [repo](https://github.com/org/repo)
b.WriteString(fmt.Sprintf("## [%s](https://github.com/%s/%s)\n\n", repo, org, repo))

for _, v := range events {
typ := v.GetType()

raw, err := v.ParsePayload()
if err != nil {
return "", err
}
switch typ {
case "IssuesEvent":
e := raw.(*github.IssuesEvent)
switch e.GetAction() {
case "opened":
b.WriteString(fmt.Sprintf("- @%s opened issue %s\n",
v.GetActor().GetLogin(),
e.GetIssue().GetHTMLURL()))
case "closed":
b.WriteString(fmt.Sprintf("- @%s closed issue %s\n",
v.GetActor().GetLogin(),
e.GetIssue().GetHTMLURL()))
default:
g.logger.Info("ignore issue",
zap.String("repo", repo),
zap.String("action", e.GetAction()))
continue
}
case "PullRequestEvent":
e := raw.(*github.PullRequestEvent)
switch e.GetAction() {
case "opened":
b.WriteString(fmt.Sprintf("- @%s opened pull request %s\n",
v.GetActor().GetLogin(),
e.GetPullRequest().GetHTMLURL()))
case "closed":
if e.GetPullRequest().GetMerged() {
b.WriteString(fmt.Sprintf("- @%s merged pull request %s\n",
v.GetActor().GetLogin(),
e.GetPullRequest().GetHTMLURL()))
} else {
b.WriteString(fmt.Sprintf("- @%s closed pull request %s\n",
v.GetActor().GetLogin(),
e.GetPullRequest().GetHTMLURL()))
}
default:
g.logger.Info("ignore pull request",
zap.String("repo", repo),
zap.String("action", e.GetAction()))
continue
}
default:
panic("invalid event type")
}
}

// Add trailing empty line.
b.WriteString("\n")

return b.String(), nil
}

func (g *Github) CreateWeeklyReportIssue(ctx context.Context, repo, content string) (issueURL string, err error) {
issue, _, err := g.client.Issues.Create(ctx, g.owner, repo, &github.IssueRequest{
Title: github.String(fmt.Sprintf("Weekly report since %s", time.Now().AddDate(0, 0, -7).Format("2006-01-02"))),
Body: github.String(content),
})
if err != nil {
return
}
return issue.GetHTMLURL(), nil
}

func (g *Github) listTeams(ctx context.Context) (teams map[string]*github.Team, err error) {
opt := &github.ListOptions{
PerPage: 100,
Expand All @@ -149,6 +243,57 @@ func (g *Github) listTeams(ctx context.Context) (teams map[string]*github.Team,
return teams, nil
}

func (g *Github) listEvents(ctx context.Context, org, repo string) (es []*github.Event, err error) {
opt := &github.ListOptions{
PerPage: 100,
}

for {
events, resp, err := g.client.Activity.ListRepositoryEvents(ctx, org, repo, opt)
if err != nil {
g.logger.Error("list events", zap.Error(err))
return nil, err
}

for _, v := range events {
v := v

// Ignore all private events.
if !v.GetPublic() {
continue
}

// Ignore all events that happens before 7 days ago.
expectedSince := time.Now().AddDate(0, 0, -7)
createdAt := v.GetCreatedAt()
if createdAt.Before(expectedSince) {
continue
}

typ := v.GetType()
switch typ {
case "IssuesEvent", "PullRequestEvent":
es = append(es, v)
default:
// Ignore all events except issues and PRs.
g.logger.Debug("ignore events", zap.String("type", typ))
continue
}
}

if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}

// Sort all events.
sort.SliceStable(es, func(i, j int) bool {
return es[i].GetCreatedAt().Before(es[j].GetCreatedAt())
})
return
}

func (g *Github) listTeamMembers(ctx context.Context, team string) (users []string, err error) {
opt := &github.TeamListTeamMembersOptions{
ListOptions: github.ListOptions{
Expand Down