Skip to content

Commit

Permalink
Convert over to Cobra CLI framework
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben Selby authored and benmatselby committed May 25, 2021
1 parent 0f9b6dd commit 33942b4
Show file tree
Hide file tree
Showing 22 changed files with 1,231 additions and 897 deletions.
6 changes: 0 additions & 6 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,3 @@ jobs:
- name: Test
run: |
make test
- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,3 @@ trace.out
debug.test
vendor/
debug

# Sonar
.scannerwork/
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Changelog

## next

- Convert to [Cobra](https://github.com/spf13/cobra).

## 1.0.0

- Original CLI app, written with [urfave/cli](https://github.com/urfave/cli)
46 changes: 26 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,43 @@
# Donny

[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=donny&metric=alert_status)](https://sonarcloud.io/dashboard?id=donny)
![Go](https://github.com/benmatselby/donny/workflows/Go/badge.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/benmatselby/donny?style=flat-square)](https://goreportcard.com/report/github.com/benmatselby/donny)

_Forget it, Donny, you're out of your element!_

CLI application for getting information out of Azure DevOps. It's based on [Trello CLI](https://github.com/benmatselby/trello-cli) so the aims are the same:

```shell
COMMANDS:
help, h Shows a list of commands or help for one command
build:
build:list, bl List all the builds
build:overview, bo Show build overview for build definitions in a given path
code:
code:branches, cb Show branch information for a repo
iteration:
iteration:burndown, ib Show column based data for the iteration
iteration:items, ii List all the work items in a given iteration
iteration:list, il List all the iterations
iteration:people, ip Show people based data for the iteration
plans:
plan:list, pll List all the delivery plans
plan:timeline, plt Show the timeline for the delivery plan
pull requests:
pr:list, pul List all the pull requests
CLI application for retrieving data from Azure DevOps

Usage:
donny [command]

Available Commands:
branch Provide a list of pull requests
builds Provide a list of builds
help Help about any command
iteration-burndown Provide a burndown of the iterations
iteration-items Provide a list of items in an iterations
iteration-people Provide a person breakdown for the iteration
iterations Provide a list of iterations
plan Get information about a delivery plan
plans Provide a list of delivery plans
prs Provide a list of pull requests
teams Provide a list of teams (Defaults to teams you are in)

Flags:
--config string config file (default is $HOME/.benmatselby/donny.yaml)
-h, --help help for donny

Use "donny [command] --help" for more information about a command.
```

## Requirements

If you are wanting to build and develop this, you will need the following items installed. If, however, you just want to run the application I recommend using the docker container (See below)

- Go version 1.12+
- Go version 1.16+

## Configuration

Expand Down Expand Up @@ -65,7 +71,7 @@ $ docker run \
git clone git@github.com:benmatselby/donny.git
cd donny
make all
./donny iteration:list
./donny builds
```

You can also install into your `$GOPATH/bin` by `go install`
132 changes: 0 additions & 132 deletions build.go

This file was deleted.

97 changes: 97 additions & 0 deletions cmd/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package cmd

import (
"fmt"
"os"
"regexp"
"text/tabwriter"
"time"

"github.com/benmatselby/donny/ui"
"github.com/benmatselby/go-azuredevops/azuredevops"
"github.com/spf13/cobra"
)

// ListBuildsOptions defines what arguments/options the user can provide for the
// command.
type ListBuildsOptions struct {
Args []string
Repo string
Branch string
Count int
}

func NewListBuildsCommand(client *azuredevops.Client) *cobra.Command {
var opts ListBuildsOptions
cmd := &cobra.Command{
Use: "builds",
Short: "Provide a list of builds",
RunE: func(cmd *cobra.Command, args []string) error {
opts.Args = args

options := &azuredevops.BuildsListOptions{
Count: opts.Count,
}

builds, err := client.Builds.List(options)
if err != nil {
return fmt.Errorf("unable to get a list of builds: %v", err)
}

if len(builds) > 0 {
renderBuilds(builds, len(builds), opts.Branch)
}

return nil
},
}

flags := cmd.Flags()
flags.StringVar(&opts.Repo, "repo", "", "The repo to filter on")
flags.IntVar(&opts.Count, "count", 10, "How many builds to show")
flags.StringVar(&opts.Branch, "branch", "", "The branch to filter on")

return cmd
}

func renderBuilds(builds []azuredevops.Build, count int, filterBranch string) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.FilterHTML)
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", "", "Name", "Branch", "Build", "Finished")
for index := 0; index < count; index++ {
build := builds[index]
name := build.Definition.Name
result := build.Result
status := build.Status
buildNo := build.BuildNumber
branch := build.Branch

// Deal with date formatting for the finish time
finish, err := time.Parse(time.RFC3339, builds[index].FinishTime)
finishAt := finish.Format(ui.AppDateTimeFormat)
if err != nil {
finishAt = builds[index].FinishTime
}

// Filter on branches
matched, _ := regexp.MatchString(".*"+filterBranch+".*", branch)
if !matched {
continue
}

if status == "inProgress" {
result = ui.AppProgress
} else if status == "notStarted" {
result = ui.AppPending
} else {
if result == "failed" {
result = ui.AppFailure
} else {
result = ui.AppSuccess
}
}

fmt.Fprintf(w, "%s \t%s\t%s\t%s\t%s\n", result, name, branch, buildNo, finishAt)
}

w.Flush()
}
69 changes: 69 additions & 0 deletions cmd/code.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cmd

import (
"fmt"
"os"
"text/tabwriter"

"github.com/benmatselby/donny/ui"
"github.com/benmatselby/go-azuredevops/azuredevops"
"github.com/spf13/cobra"
)

// ListBranchInfoOptions defines what arguments/options the user can provide for the
// command.
type ListBranchInfoOptions struct {
Args []string
Repo string
}

func NewListBranchInfoCommand(client *azuredevops.Client) *cobra.Command {
var opts ListBranchInfoOptions
cmd := &cobra.Command{
Use: "branch",
Short: "Provide a list of pull requests",
RunE: func(cmd *cobra.Command, args []string) error {
opts.Args = args

if opts.Repo == "" {
return fmt.Errorf("expected argument of repo")
}
gitRefOps := azuredevops.GitRefListOptions{
IncludeStatuses: true,
LatestStatusesOnly: true,
}
refs, _, err := client.Git.ListRefs(opts.Repo, "heads", &gitRefOps)
if err != nil {
return fmt.Errorf("unable to get git refs for %s: %+v", opts.Repo, err)
}

w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.FilterHTML)

for _, ref := range refs {
state := ui.AppUnknown
if len(ref.Statuses) > 0 {
state = ref.Statuses[0].State

if state == "failed" {
state = ui.AppFailure
} else if state == "pending" {
state = ui.AppPending
} else {
state = ui.AppSuccess
}
}

fmt.Fprintf(w, "%s \t%s\n", state, ref.Name)
}

w.Flush()

return nil
},
}

flags := cmd.Flags()
flags.StringVar(&opts.Repo, "repo", "", "The repo to filter on")

return cmd
}
Loading

0 comments on commit 33942b4

Please sign in to comment.