mirror of
				https://github.com/taigrr/wtf
				synced 2025-01-18 04:03:14 -08:00 
			
		
		
		
	Merge branch 'feature/azure-dev-ops-module' of github.com:v-braun/wtf into v-braun-feature/azure-dev-ops-module
This commit is contained in:
		
						commit
						1bfd26a55c
					
				@ -14,6 +14,7 @@ import (
 | 
			
		||||
	"github.com/wtfutil/wtf/modules/datadog"
 | 
			
		||||
	"github.com/wtfutil/wtf/modules/digitalclock"
 | 
			
		||||
	"github.com/wtfutil/wtf/modules/docker"
 | 
			
		||||
	"github.com/wtfutil/wtf/modules/azuredevops"
 | 
			
		||||
	"github.com/wtfutil/wtf/modules/feedreader"
 | 
			
		||||
	"github.com/wtfutil/wtf/modules/gcal"
 | 
			
		||||
	"github.com/wtfutil/wtf/modules/gerrit"
 | 
			
		||||
@ -112,6 +113,9 @@ func MakeWidget(
 | 
			
		||||
	case "docker":
 | 
			
		||||
		settings := docker.NewSettingsFromYAML(moduleName, moduleConfig, config)
 | 
			
		||||
		widget = docker.NewWidget(app, pages, settings)
 | 
			
		||||
	case "azuredevops":
 | 
			
		||||
		settings := azuredevops.NewSettingsFromYAML(moduleName, moduleConfig, config)
 | 
			
		||||
		widget = azuredevops.NewWidget(app, pages, settings)
 | 
			
		||||
	case "feedreader":
 | 
			
		||||
		settings := feedreader.NewSettingsFromYAML(moduleName, moduleConfig, config)
 | 
			
		||||
		widget = feedreader.NewWidget(app, pages, settings)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@ -49,6 +49,8 @@ require (
 | 
			
		||||
	github.com/magiconair/properties v1.8.1 // indirect
 | 
			
		||||
	github.com/mattn/go-colorable v0.1.2 // indirect
 | 
			
		||||
	github.com/mattn/go-isatty v0.0.9 // indirect
 | 
			
		||||
	github.com/microsoft/azure-devops-go-api v0.0.0-20190912142452-3207b4a469d3 // indirect
 | 
			
		||||
	github.com/microsoft/azure-devops-go-api/azuredevops v0.0.0-20190912142452-3207b4a469d3
 | 
			
		||||
	github.com/mmcdole/gofeed v1.0.0-beta2.0.20190420154928-0e68beaf6fdf
 | 
			
		||||
	github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
 | 
			
		||||
	github.com/olebedev/config v0.0.0-20190528211619-364964f3a8e4
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.sum
									
									
									
									
									
								
							@ -159,6 +159,7 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
 | 
			
		||||
github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 | 
			
		||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 | 
			
		||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
			
		||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 | 
			
		||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
			
		||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 | 
			
		||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
 | 
			
		||||
@ -227,6 +228,10 @@ github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
 | 
			
		||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
 | 
			
		||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 | 
			
		||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 | 
			
		||||
github.com/microsoft/azure-devops-go-api v0.0.0-20190912142452-3207b4a469d3 h1:FhI3QJOcd1CaXz2+DeFHUNEsS47+gxDERzVhexlTGvg=
 | 
			
		||||
github.com/microsoft/azure-devops-go-api v0.0.0-20190912142452-3207b4a469d3/go.mod h1:HfrxIH2ObkhL6NepJKAuEwUYY8kNvspOWDp6HDRIRQs=
 | 
			
		||||
github.com/microsoft/azure-devops-go-api/azuredevops v0.0.0-20190912142452-3207b4a469d3 h1:Q42uNxLRytr5ynbRkqspq37TjcfnuXwKmrS9APJv/Bw=
 | 
			
		||||
github.com/microsoft/azure-devops-go-api/azuredevops v0.0.0-20190912142452-3207b4a469d3/go.mod h1:PoGiBqKSQK1vIfQ+yVaFcGjDySHvym6FM1cNYnwzbrY=
 | 
			
		||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 | 
			
		||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 | 
			
		||||
github.com/mmcdole/gofeed v1.0.0-beta2.0.20190420154928-0e68beaf6fdf h1:poo3e5STwUVGyyUX0e3fHQUwT1tV8IYEFUUpYd/7LuA=
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										59
									
								
								modules/azuredevops/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								modules/azuredevops/client.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
			
		||||
package azuredevops
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	azrBuild "github.com/microsoft/azure-devops-go-api/azuredevops/build"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (widget *Widget) getBuildStats() string {
 | 
			
		||||
	projName := widget.settings.projectName
 | 
			
		||||
	statusFilter := azrBuild.BuildStatusValues.All
 | 
			
		||||
	top := widget.settings.maxRows
 | 
			
		||||
	builds, err := widget.cli.GetBuilds(widget.ctx, azrBuild.GetBuildsArgs{Project: &projName, StatusFilter: &statusFilter, Top: &top})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrap(err, "could not get builds").Error()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result := ""
 | 
			
		||||
	for _, build := range builds.Value {
 | 
			
		||||
		num := *build.BuildNumber
 | 
			
		||||
		branch := *build.SourceBranch
 | 
			
		||||
		reason := *build.Reason
 | 
			
		||||
		triggers := *build.TriggerInfo
 | 
			
		||||
		if reason == azrBuild.BuildReasonValues.PullRequest {
 | 
			
		||||
			branch = triggers["pr.sourceBranch"]
 | 
			
		||||
		}
 | 
			
		||||
		branch = strings.TrimPrefix(branch, "refs/heads/")
 | 
			
		||||
		status := *build.Status
 | 
			
		||||
		statusDisplay := "[white:grey]unknown"
 | 
			
		||||
		if status == azrBuild.BuildStatusValues.InProgress {
 | 
			
		||||
			statusDisplay = "[white:blue]in progress"
 | 
			
		||||
		} else if status == azrBuild.BuildStatusValues.Cancelling {
 | 
			
		||||
			statusDisplay = "[white:orange]in cancelling"
 | 
			
		||||
		} else if (status == azrBuild.BuildStatusValues.Postponed) || (status == azrBuild.BuildStatusValues.NotStarted) {
 | 
			
		||||
			statusDisplay = "[white:blue]waiting"
 | 
			
		||||
		} else if status == azrBuild.BuildStatusValues.Completed {
 | 
			
		||||
			buildResult := *build.Result
 | 
			
		||||
			if buildResult == azrBuild.BuildResultValues.Succeeded {
 | 
			
		||||
				statusDisplay = "[white:green]succeeded"
 | 
			
		||||
			} else if buildResult == azrBuild.BuildResultValues.Failed {
 | 
			
		||||
				statusDisplay = "[white:red]failed"
 | 
			
		||||
			} else if buildResult == azrBuild.BuildResultValues.Canceled {
 | 
			
		||||
				statusDisplay = "[white:darkgrey]cancelled"
 | 
			
		||||
			} else if buildResult == azrBuild.BuildResultValues.PartiallySucceeded {
 | 
			
		||||
				statusDisplay = "[white:magenta]partially"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		result += fmt.Sprintf("%s[-:-:-] #%s %s (%s) \n", statusDisplay, num, branch, reason)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if result == "" {
 | 
			
		||||
		result = "no builds found"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								modules/azuredevops/example-conf.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								modules/azuredevops/example-conf.yml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
wtf:
 | 
			
		||||
  colors:
 | 
			
		||||
    # background: black
 | 
			
		||||
    # foreground: blue
 | 
			
		||||
    border:
 | 
			
		||||
      focusable: darkslateblue
 | 
			
		||||
      focused: orange
 | 
			
		||||
      normal: gray
 | 
			
		||||
    checked: yellow
 | 
			
		||||
    highlight: 
 | 
			
		||||
      fore: black
 | 
			
		||||
      back: gray
 | 
			
		||||
    rows:
 | 
			
		||||
      even: yellow
 | 
			
		||||
      odd: white
 | 
			
		||||
  grid:
 | 
			
		||||
    # How _wide_ the columns are, in terminal characters. In this case we have
 | 
			
		||||
    # four columns, each of which are 35 characters wide.
 | 
			
		||||
    # columns: [50, ]
 | 
			
		||||
    # How _high_ the rows are, in terminal lines. In this case we have four rows
 | 
			
		||||
    # that support ten line of text and one of four.
 | 
			
		||||
    # rows: [50]
 | 
			
		||||
  refreshInterval: 1
 | 
			
		||||
  openFileUtil: "open"
 | 
			
		||||
  mods:
 | 
			
		||||
    azuredevops:
 | 
			
		||||
      type: azuredevops
 | 
			
		||||
      title: "💻"
 | 
			
		||||
      enabled: true
 | 
			
		||||
      position:
 | 
			
		||||
        top: 0
 | 
			
		||||
        left: 0
 | 
			
		||||
        height: 3
 | 
			
		||||
        width: 3
 | 
			
		||||
      refreshInterval: 1
 | 
			
		||||
      labelColor: lightblue # title label color (optional / default: white)
 | 
			
		||||
      apiToken: "mysecret api token" # api key (required)
 | 
			
		||||
      orgUrl: "https://dev.azure.com/myawesomecompany/" # url to your azure devops project (required)
 | 
			
		||||
      prjectName: "the awesome project"  # name of your project (required)
 | 
			
		||||
      maxRows: 3 #max rows to show (optional / default 3)
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
							
								
								
									
										32
									
								
								modules/azuredevops/settings.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								modules/azuredevops/settings.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
package azuredevops
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/olebedev/config"
 | 
			
		||||
	"github.com/wtfutil/wtf/cfg"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const defaultTitle = "azuredevops"
 | 
			
		||||
 | 
			
		||||
// Settings defines the configuration options for this module
 | 
			
		||||
type Settings struct {
 | 
			
		||||
	common      *cfg.Common
 | 
			
		||||
	labelColor  string
 | 
			
		||||
	apiToken    string
 | 
			
		||||
	orgURL      string
 | 
			
		||||
	projectName string
 | 
			
		||||
	maxRows     int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSettingsFromYAML creates and returns an instance of Settings with configuration options populated
 | 
			
		||||
func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *config.Config) *Settings {
 | 
			
		||||
	settings := Settings{
 | 
			
		||||
		common:      cfg.NewCommonSettingsFromModule(name, defaultTitle, ymlConfig, globalConfig),
 | 
			
		||||
		labelColor:  ymlConfig.UString("labelColor", "white"),
 | 
			
		||||
		apiToken:    ymlConfig.UString("apiToken", "api token not specified"),
 | 
			
		||||
		orgURL:      ymlConfig.UString("orgURL", "org url not specified"),
 | 
			
		||||
		projectName: ymlConfig.UString("projectName", "project name not specified"),
 | 
			
		||||
		maxRows:     ymlConfig.UInt("maxRows", 3),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &settings
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								modules/azuredevops/widget.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								modules/azuredevops/widget.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
package azuredevops
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	azr "github.com/microsoft/azure-devops-go-api/azuredevops"
 | 
			
		||||
	azrBuild "github.com/microsoft/azure-devops-go-api/azuredevops/build"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/rivo/tview"
 | 
			
		||||
	"github.com/wtfutil/wtf/view"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Widget struct {
 | 
			
		||||
	view.TextWidget
 | 
			
		||||
	cli           *azrBuild.Client
 | 
			
		||||
	settings      *Settings
 | 
			
		||||
	displayBuffer string
 | 
			
		||||
	ctx           context.Context
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewWidget(app *tview.Application, pages *tview.Pages, settings *Settings) *Widget {
 | 
			
		||||
	widget := Widget{
 | 
			
		||||
		TextWidget: view.NewTextWidget(app, settings.common, false),
 | 
			
		||||
		settings:   settings,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	widget.View.SetScrollable(true)
 | 
			
		||||
	connection := azr.NewPatConnection(settings.orgURL, settings.apiToken)
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
 | 
			
		||||
	cli, err := azrBuild.NewClient(ctx, connection)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		widget.displayBuffer = errors.Wrap(err, "could not create client 2").Error()
 | 
			
		||||
	} else {
 | 
			
		||||
		widget.cli = cli
 | 
			
		||||
		widget.ctx = ctx
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	widget.refreshDisplayBuffer()
 | 
			
		||||
 | 
			
		||||
	return &widget
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (widget *Widget) Refresh() {
 | 
			
		||||
	widget.refreshDisplayBuffer()
 | 
			
		||||
	widget.Redraw(widget.display)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (widget *Widget) display() (string, string, bool) {
 | 
			
		||||
	return widget.CommonSettings().Title, widget.displayBuffer, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (widget *Widget) refreshDisplayBuffer() {
 | 
			
		||||
	if widget.cli == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	widget.displayBuffer = ""
 | 
			
		||||
 | 
			
		||||
	widget.displayBuffer += fmt.Sprintf("[%s::bul] build status - %s\n",
 | 
			
		||||
		widget.settings.labelColor,
 | 
			
		||||
		widget.settings.projectName)
 | 
			
		||||
 | 
			
		||||
	widget.displayBuffer += widget.getBuildStats()
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user