Skip to content

Commit

Permalink
Merge pull request #56 from philips-labs/feature/github-members
Browse files Browse the repository at this point in the history
Feature/GitHub members
  • Loading branch information
JeroenKnoops authored Oct 9, 2020
2 parents 9b5ab65 + 86e3039 commit e95232f
Show file tree
Hide file tree
Showing 8 changed files with 344 additions and 24 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/golang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,6 @@ jobs:
- name: Check out code
uses: actions/checkout@v2

- name: Lint
run: |
go install golang.org/x/tools/cmd/goimports
result=$($(go env GOPATH)/bin/goimports -d -e -local github.com/philips-labs/tabia $(go list -f {{.Dir}} ./...))
echo $result
[ -n "$result" ] && exit 1 || exit 0
- name: Cache Go modules
uses: actions/cache@v2
id: go-mod-cache
Expand All @@ -42,6 +35,13 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- name: Lint
run: |
go install golang.org/x/tools/cmd/goimports
result=$($(go env GOPATH)/bin/goimports -d -e -local github.com/philips-labs/tabia $(go list -f {{.Dir}} ./...))
echo $result
[ -n "$result" ] && exit 1 || exit 0
- name: Get dependencies
run: go mod download

Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ bin/tabia -O philips-labs -F templated -T markdown.tmpl > repositories.md

#### Filter

##### Repositories

The following repository fields can be filtered on.

* ID
Expand Down Expand Up @@ -154,6 +156,21 @@ $ bin/tabia github repositories -O philips-labs -f '{ !.IsPrivate() && !.IsInter
........
```

##### Members

The following member fields can be filtered on.

* ID
* Login
* Name
* Organization
* SamlIdentity
* ID

The following functions are available.

* `func (MemberFilterEnv) Contains(s, substr string) bool`

#### Download contents

```bash
Expand Down
83 changes: 82 additions & 1 deletion cmd/cmd_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,36 @@ func createGithub() *cli.Command {
},
},
},
{
Name: "members",
Usage: "display insights on members",
Action: githubMembers,
Flags: []cli.Flag{
&cli.StringSliceFlag{
Name: "organization",
Aliases: []string{"O"},
Usage: "fetches members for given organization",
},
&cli.StringFlag{
Name: "format",
Aliases: []string{"F"},
Usage: "Formats output in the given `FORMAT`",
EnvVars: []string{"TABIA_OUTPUT_FORMAT"},
DefaultText: "",
},
&cli.PathFlag{
Name: "template",
Aliases: []string{"T"},
Usage: "Formats output using the given `TEMPLATE`",
TakesFile: true,
},
&cli.StringFlag{
Name: "filter",
Aliases: []string{"f"},
Usage: "filters members based on the given `EXPRESSION`",
},
},
},
{
Name: "contents",
Usage: "Gets contents from a repository",
Expand Down Expand Up @@ -113,6 +143,57 @@ func newGithubClient(c *cli.Context) *github.Client {
return github.NewClientWithTokenAuth(token, ghWriter)
}

func githubMembers(c *cli.Context) error {
owners := c.StringSlice("organization")
format := c.String("format")
filter := c.String("filter")

client := newGithubClient(c)
ctx, cancel := context.WithCancel(c.Context)
defer cancel()

var ghMembers []github.Member
for _, owner := range owners {
members, err := client.FetchOrganziationMembers(ctx, "royal-philips", owner)
if err != nil {
return err
}
filtered, err := github.ReduceMembers(members, filter)
if err != nil {
return err
}
ghMembers = append(ghMembers, filtered...)
}

switch format {
case "json":
output.PrintJSON(c.App.Writer, ghMembers)
case "templated":
if !c.IsSet("template") {
return fmt.Errorf("you must specify the path to the template")
}

templateFile := c.Path("template")
tmplContent, err := ioutil.ReadFile(templateFile)
if err != nil {
return err
}
err = output.PrintUsingTemplate(c.App.Writer, tmplContent, ghMembers)
if err != nil {
return err
}
default:
w := tabwriter.NewWriter(c.App.Writer, 3, 0, 2, ' ', tabwriter.TabIndent)
fmt.Fprintln(w, " \tLogin\tSAML Identity\tOrganization\tName")
for i, m := range ghMembers {
fmt.Fprintf(w, "%04d\t%s\t%s\t%s\t%s\n", i+1, m.Login, m.SamlIdentity.ID, m.Organization, m.Name)
}
w.Flush()
}

return nil
}

func githubRepositories(c *cli.Context) error {
owners := c.StringSlice("owner")
format := c.String("format")
Expand All @@ -128,7 +209,7 @@ func githubRepositories(c *cli.Context) error {
if err != nil {
return err
}
filtered, err := github.Reduce(repos, filter)
filtered, err := github.ReduceRepositories(repos, filter)
if err != nil {
return err
}
Expand Down
36 changes: 34 additions & 2 deletions lib/github/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ type RepositoryFilterEnv struct {
Repositories []Repository
}

// MemberFilterEnv filter environment for members
type MemberFilterEnv struct {
Members []Member
}

// Contains reports wether substring is in s.
func (MemberFilterEnv) Contains(s, substring string) bool {
return strings.Contains(s, substring)
}

// Contains reports wether substring is in s.
func (RepositoryFilterEnv) Contains(s, substring string) bool {
return strings.Contains(s, substring)
Expand Down Expand Up @@ -82,8 +92,8 @@ func equalOrAfter(a time.Time, date string) bool {
return a.Equal(since) || a.After(since)
}

// Reduce filters the repositories based on the given filter
func Reduce(repositories []Repository, filter string) ([]Repository, error) {
// ReduceRepositories filters the repositories based on the given filter
func ReduceRepositories(repositories []Repository, filter string) ([]Repository, error) {
if strings.TrimSpace(filter) == "" {
return repositories, nil
}
Expand All @@ -103,3 +113,25 @@ func Reduce(repositories []Repository, filter string) ([]Repository, error) {
}
return repos, nil
}

// ReduceMembers filters the members based on the given filter
func ReduceMembers(members []Member, filter string) ([]Member, error) {
if strings.TrimSpace(filter) == "" {
return members, nil
}

program, err := expr.Compile(fmt.Sprintf("filter(Members, %s)", filter))
if err != nil {
return nil, err
}

result, err := expr.Run(program, MemberFilterEnv{members})
if err != nil {
return nil, err
}
var filtered []Member
for _, m := range result.([]interface{}) {
filtered = append(filtered, m.(Member))
}
return filtered, nil
}
51 changes: 37 additions & 14 deletions lib/github/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/philips-labs/tabia/lib/github"
)

func TestReduce(t *testing.T) {
func TestReduceRepositories(t *testing.T) {
assert := assert.New(t)

repos := []github.Repository{
Expand Down Expand Up @@ -48,59 +48,59 @@ func TestReduce(t *testing.T) {
},
}

reduced, err := github.Reduce(repos, "")
reduced, err := github.ReduceRepositories(repos, "")
if assert.NoError(err) {
assert.Len(reduced, 5)
assert.ElementsMatch(reduced, repos)
}

reduced, err = github.Reduce(repos, `{ .Name == "garo" }`)
reduced, err = github.ReduceRepositories(repos, `{ .Name == "garo" }`)
if assert.NoError(err) {
assert.Len(reduced, 1)
assert.Contains(reduced, repos[1])
}

reduced, err = github.Reduce(repos, `{ .IsPublic() }`)
reduced, err = github.ReduceRepositories(repos, `{ .IsPublic() }`)
if assert.NoError(err) {
assert.Len(reduced, 3)
assert.Contains(reduced, repos[0])
assert.Contains(reduced, repos[1])
assert.Contains(reduced, repos[2])
}

reduced, err = github.Reduce(repos, `{ .IsInternal() }`)
reduced, err = github.ReduceRepositories(repos, `{ .IsInternal() }`)
if assert.NoError(err) {
assert.Len(reduced, 1)
assert.Contains(reduced, repos[3])
}

reduced, err = github.Reduce(repos, `{ .IsPrivate() }`)
reduced, err = github.ReduceRepositories(repos, `{ .IsPrivate() }`)
if assert.NoError(err) {
assert.Len(reduced, 1)
assert.Contains(reduced, repos[4])
}

reduced, err = github.Reduce(repos, `{ Contains(.Name, "ar") }`)
reduced, err = github.ReduceRepositories(repos, `{ Contains(.Name, "ar") }`)
if assert.NoError(err) {
assert.Len(reduced, 2)
assert.Contains(reduced, repos[1])
assert.Contains(reduced, repos[2])
}

reduced, err = github.Reduce(repos, `{ .HasTopic("ip") }`)
reduced, err = github.ReduceRepositories(repos, `{ .HasTopic("ip") }`)
if assert.NoError(err) {
assert.Len(reduced, 1)
assert.Contains(reduced, repos[4])
}

reduced, err = github.Reduce(repos, `{ .HasLanguage("go") }`)
reduced, err = github.ReduceRepositories(repos, `{ .HasLanguage("go") }`)
if assert.NoError(err) {
assert.Len(reduced, 1)
assert.Contains(reduced, repos[0])
}

since := time.Now().Add(-25 * time.Hour).Format(time.RFC3339)
reduced, err = github.Reduce(repos, fmt.Sprintf(`{ .CreatedSince("%s") }`, since))
reduced, err = github.ReduceRepositories(repos, fmt.Sprintf(`{ .CreatedSince("%s") }`, since))
if assert.NoError(err) {
assert.Len(reduced, 3)
assert.Contains(reduced, repos[0])
Expand All @@ -109,7 +109,7 @@ func TestReduce(t *testing.T) {
}

since = time.Now().Add(-97 * time.Hour).Format(time.RFC3339)
reduced, err = github.Reduce(repos, fmt.Sprintf(`{ .UpdatedSince("%s") }`, since))
reduced, err = github.ReduceRepositories(repos, fmt.Sprintf(`{ .UpdatedSince("%s") }`, since))
if assert.NoError(err) {
assert.Len(reduced, 5)
assert.Contains(reduced, repos[0])
Expand All @@ -120,7 +120,7 @@ func TestReduce(t *testing.T) {
}

since = time.Now().Add(-49 * time.Hour).Format(time.RFC3339)
reduced, err = github.Reduce(repos, fmt.Sprintf(`{ .PushedSince("%s") }`, since))
reduced, err = github.ReduceRepositories(repos, fmt.Sprintf(`{ .PushedSince("%s") }`, since))
if assert.NoError(err) {
assert.Len(reduced, 4)
assert.Contains(reduced, repos[0])
Expand All @@ -130,19 +130,42 @@ func TestReduce(t *testing.T) {
}
}

func TestReduceMembers(t *testing.T) {
assert := assert.New(t)

members := []github.Member{
github.Member{Name: "John Doe"},
github.Member{Name: "Marco Franssen"},
github.Member{Name: "Jane Doe"},
}

reduced, err := github.ReduceMembers(members, `{ .Name == "Marco Franssen" }`)
if assert.NoError(err) {
assert.Len(reduced, 1)
assert.Contains(reduced, members[1])
}

reduced, err = github.ReduceMembers(members, `{ Contains(.Name, "Doe") }`)
if assert.NoError(err) {
assert.Len(reduced, 2)
assert.Contains(reduced, members[0])
assert.Contains(reduced, members[2])
}
}

func TestReduceWrongExpression(t *testing.T) {
assert := assert.New(t)

repos := []github.Repository{
github.Repository{Name: "tabia", Visibility: github.Public},
}

reduced, err := github.Reduce(repos, `.Name == "tabia"`)
reduced, err := github.ReduceRepositories(repos, `.Name == "tabia"`)
assert.Error(err)
assert.EqualError(err, "unexpected token Operator(\".\") (1:22)\n | filter(Repositories, .Name == \"tabia\")\n | .....................^")
assert.Nil(reduced)

reduced, err = github.Reduce(repos, `{ UnExistingFunc(.URL, "stuff") }`)
reduced, err = github.ReduceRepositories(repos, `{ UnExistingFunc(.URL, "stuff") }`)
assert.Error(err)
assert.EqualError(err, "cannot get \"UnExistingFunc\" from github.RepositoryFilterEnv (1:24)\n | filter(Repositories, { UnExistingFunc(.URL, \"stuff\") })\n | .......................^")
assert.Nil(reduced)
Expand Down
Loading

0 comments on commit e95232f

Please sign in to comment.