Skip to content

Commit

Permalink
Merge pull request #42 from grisu48/revtui
Browse files Browse the repository at this point in the history
Follow jobs
  • Loading branch information
grisu48 authored Apr 29, 2021
2 parents 5ec776f + 3a18b74 commit 94d054c
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 38 deletions.
111 changes: 77 additions & 34 deletions cmd/openqa-revtui/openqa-revtui.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"github.com/grisu48/gopenqa"
)

const VERSION = "0.2b"

/* Group is a single configurable monitoring unit. A group contains all parameters that will be queried from openQA */
type Group struct {
Name string
Expand Down Expand Up @@ -107,6 +109,27 @@ func hideJob(job gopenqa.Job) bool {
return false
}

func isReviewed(job gopenqa.Job, instance gopenqa.Instance) (bool, error) {
comments, err := instance.GetComments(job.ID)
if err != nil {
return false, nil
}
for _, c := range comments {
if len(c.BugRefs) > 0 {
return true, nil
}
// Manually check for poo or bsc reference
if strings.Contains(c.Text, "poo#") || strings.Contains(c.Text, "bsc#") {
return true, nil
}
// Or for link to progress/bugzilla ticket
if strings.Contains(c.Text, "://progress.opensuse.org/issues/") || strings.Contains(c.Text, "://bugzilla.suse.com/show_bug.cgi?id=") {
return true, nil
}
}
return false, nil
}

func FetchJobGroups(instance gopenqa.Instance) (map[int]gopenqa.JobGroup, error) {
jobGroups := make(map[int]gopenqa.JobGroup)
groups, err := instance.GetJobGroups()
Expand All @@ -121,17 +144,21 @@ func FetchJobGroups(instance gopenqa.Instance) (map[int]gopenqa.JobGroup, error)

/* Get job or restarted current job of the given job ID */
func FetchJob(id int, instance gopenqa.Instance) (gopenqa.Job, error) {
for {
job, err := instance.GetJob(id)
var job gopenqa.Job
for i := 0; i < 10; i++ { // Max recursion depth is 10
var err error
job, err = instance.GetJob(id)
if err != nil {
return job, err
}
if job.CloneID == 0 || job.CloneID == job.ID {
return job, nil
} else {
if job.CloneID != 0 && job.CloneID != job.ID {
id = job.CloneID
continue
} else {
return job, nil
}
}
return job, fmt.Errorf("max recursion depth reached")
}

func FetchJobs(instance gopenqa.Instance) ([]gopenqa.Job, error) {
Expand All @@ -142,7 +169,7 @@ func FetchJobs(instance gopenqa.Instance) ([]gopenqa.Job, error) {
if err != nil {
return ret, err
}
// Limit jobs to at most 100, otherwise it's too much
// Limit jobs to at most MaxJobs
if len(jobs) > cf.MaxJobs {
jobs = jobs[:cf.MaxJobs]
}
Expand All @@ -167,25 +194,19 @@ func rabbitRemote(remote string) string {
return remote
}

/** Try to update the given job, if it exists and if not the same. Returns the found job and true, if an update was successful*/
func updateJob(job gopenqa.Job, instance gopenqa.Instance) (gopenqa.Job, bool, error) {
/** Try to update the given job, if it exists and if not the same. Returns the found job and true, if an update was successful */
func updateJob(orig_id int, job gopenqa.Job, instance gopenqa.Instance) (gopenqa.Job, bool) {
for i, j := range knownJobs {
if j.ID == job.ID {
// Follow jobs
if job.CloneID != 0 && job.CloneID != job.ID {
job, err := instance.GetJob(job.CloneID)
knownJobs[i] = job
return knownJobs[i], true, err
}
if j.State != job.State || j.Result != job.Result {
if j.ID == orig_id {
if j.ID != job.ID || j.State != job.State || j.Result != job.Result {
knownJobs[i] = job
return knownJobs[i], true, nil
return knownJobs[i], true
} else {
return job, false, nil
return job, false
}
}
}
return job, false, nil
return job, false
}

/** Try to update the job with the given status, if present. Returns the found job and true if the job was present */
Expand Down Expand Up @@ -400,32 +421,43 @@ func refreshJobs(tui *TUI, instance gopenqa.Instance) error {
status := tui.Status()
tui.SetStatus("Refreshing jobs ... ")
tui.Update()
if jobs, err := FetchJobs(instance); err != nil {
return err
} else {
for _, j := range jobs {
job, found, err := updateJob(j, instance)
jobs := tui.Model.Jobs()
for i, job := range jobs {
orig_id := job.ID
job, err := FetchJob(job.ID, instance)
if err != nil {
return err
}
job, found := updateJob(orig_id, job, instance)
if found {
status = fmt.Sprintf("Last update: [%s] Job %d-%s %s", time.Now().Format("15:04:05"), job.ID, job.Name, job.JobState())
tui.SetStatus(status)
jobs[i] = job
tui.Model.Apply(jobs)
tui.Update()
if cf.Notify && !hideJob(job) {
NotifySend(fmt.Sprintf("%s: %s %s", job.JobState(), job.Name, job.Test))
}
}
// Failed jobs will be also scanned for comments
if job.JobState() == "failed" {
reviewed, err := isReviewed(job, instance)
if err != nil {
return err
}
if found {
status = fmt.Sprintf("Last update: [%s] Job %d-%s %s", time.Now().Format("15:04:05"), job.ID, job.Name, job.JobState())
tui.SetStatus(status)
tui.Update()
if cf.Notify && !hideJob(job) {
NotifySend(fmt.Sprintf("%s: %s %s", job.JobState(), job.Name, job.Test))
}
}
tui.Model.SetReviewed(job.ID, reviewed)
tui.Update()
}
}
tui.Model.Apply(jobs)
tui.SetStatus(status)
tui.Update()
return nil
}

// main routine for the TUI instance
func tui_main(tui *TUI, instance gopenqa.Instance) int {
title := "openqa Review TUI Dashboard"
title := "openqa Review TUI Dashboard v" + VERSION
var rabbitmq gopenqa.RabbitMQ
var err error

Expand Down Expand Up @@ -488,9 +520,20 @@ func tui_main(tui *TUI, instance gopenqa.Instance) int {
fmt.Fprintf(os.Stderr, "Error fetching jobs: %s\n", err)
os.Exit(1)
}
// Failed jobs will be also scanned for comments
for _, job := range jobs {
if job.JobState() == "failed" {
reviewed, err := isReviewed(job, instance)
if err != nil {
fmt.Fprintf(os.Stderr, "Error fetching job comment: %s\n", err)
os.Exit(1)
}
tui.Model.SetReviewed(job.ID, reviewed)
}
}
knownJobs = jobs
tui.Start()
tui.Model.Apply(knownJobs)
tui.Start()
tui.Update()

// Register RabbitMQ
Expand Down
30 changes: 27 additions & 3 deletions cmd/openqa-revtui/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ func CreateTUI() TUI {
tui.showStatus = true
tui.Model.jobs = make([]gopenqa.Job, 0)
tui.Model.jobGroups = make(map[int]gopenqa.JobGroup, 0)
tui.Model.reviewed = make(map[int]bool, 0)
return tui
}

Expand All @@ -75,6 +76,7 @@ type TUIModel struct {
mutex sync.Mutex // Access mutex to the model
offset int // Line offset for printing
printLines int // Lines that would need to be printed, needed for offset handling
reviewed map[int]bool // Indicating if failed jobs are reviewed
}

func (tui *TUI) visibleJobCount() int {
Expand All @@ -87,6 +89,15 @@ func (tui *TUI) visibleJobCount() int {
return counter
}

func (model *TUIModel) SetReviewed(job int, reviewed bool) {
model.reviewed[job] = reviewed
}

func (model *TUIModel) isReviewed(job int) bool {
reviewed, found := model.reviewed[job]
return found && reviewed
}

func (tui *TUIModel) MoveHome() {
tui.mutex.Lock()
defer tui.mutex.Unlock()
Expand All @@ -99,6 +110,10 @@ func (tui *TUIModel) Apply(jobs []gopenqa.Job) {
tui.jobs = jobs
}

func (model *TUIModel) Jobs() []gopenqa.Job {
return model.jobs
}

func (tui *TUIModel) SetJobGroups(grps map[int]gopenqa.JobGroup) {
tui.jobGroups = grps
}
Expand Down Expand Up @@ -271,7 +286,7 @@ func (tui *TUI) printJobs(width, height int) {
for _, job := range tui.Model.jobs {
if !tui.hideJob(job) {
if line++; line > tui.Model.offset {
fmt.Println(formatJobLine(job, width))
fmt.Println(tui.formatJobLine(job, width))
}
}
}
Expand Down Expand Up @@ -316,7 +331,7 @@ func (tui *TUI) printJobsByGroup(width, height int) int {
lines = append(lines, fmt.Sprintf("===== %s ====================\n", grp.Name))
for _, job := range jobs {
if !tui.hideJob(job) {
lines = append(lines, formatJobLine(job, width))
lines = append(lines, tui.formatJobLine(job, width))
} else {
hidden++
}
Expand Down Expand Up @@ -468,7 +483,7 @@ func getDateColorcode(t time.Time) string {
return ANSI_WHITE
}

func formatJobLine(job gopenqa.Job, width int) string {
func (tui *TUI) formatJobLine(job gopenqa.Job, width int) string {
c1 := ANSI_WHITE // date color
tStr := "" // Timestamp string

Expand All @@ -488,6 +503,15 @@ func formatJobLine(job gopenqa.Job, width int) string {
if state != "scheduled" && timestamp.Unix() > 0 {
tStr = timestamp.Format("2006-01-02-15:04:05")
}
// For failed jobs check if they are reviewed
if state == "failed" {
if reviewed, found := tui.Model.reviewed[job.ID]; found {
if reviewed {
state = "reviewed"
c2 = ANSI_MAGENTA
}
}
}

// Full status line requires 89 characters (20+4+8+1+12+1+40+3) plus name
if width > 90 {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ go 1.11

require (
github.com/BurntSushi/toml v0.3.1
github.com/grisu48/gopenqa v0.0.0-20210301131952-e781e21a6e9c
github.com/grisu48/gopenqa v0.3.3
github.com/streadway/amqp v1.0.0
)
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/grisu48/gopenqa v0.0.0-20210224104953-f86136cfe826/go.mod h1:ZVDyBqnwiOAv+vm7FFB8/S94Rt+0da4lQD5TaZWl8oE=
github.com/grisu48/gopenqa v0.0.0-20210301125648-f72f716c6bfb h1:Xvj1gHwROF2xIPETjhUW7TFXBeq29qoqYRLxu7E4J5w=
github.com/grisu48/gopenqa v0.0.0-20210301125648-f72f716c6bfb/go.mod h1:ZVDyBqnwiOAv+vm7FFB8/S94Rt+0da4lQD5TaZWl8oE=
github.com/grisu48/gopenqa v0.0.0-20210301131952-e781e21a6e9c h1:g8/Zih9pi182bkyGoa3Y/AFXS/qLhv5nTpoQjilwgHo=
github.com/grisu48/gopenqa v0.0.0-20210301131952-e781e21a6e9c/go.mod h1:ZVDyBqnwiOAv+vm7FFB8/S94Rt+0da4lQD5TaZWl8oE=
github.com/grisu48/gopenqa v0.0.0-20210420081537-0d0d61f743e6 h1:b+OqOOGaLU9eWIEZVEeh6KCb4DYaMLDM36gSutC+hTg=
github.com/grisu48/gopenqa v0.0.0-20210420081537-0d0d61f743e6/go.mod h1:D7EFTPhtzNvnHnDol9UoPCFmnzOiLBVa1tOOYqJDgGo=
github.com/grisu48/gopenqa v0.3.0 h1:LSstlioho4vFqxSf3jNVJSU9BeCYqLW6mlSwy0Qzw9k=
github.com/grisu48/gopenqa v0.3.0/go.mod h1:D7EFTPhtzNvnHnDol9UoPCFmnzOiLBVa1tOOYqJDgGo=
github.com/grisu48/gopenqa v0.3.2 h1:v8h5iYqZqGHph69OlPvrd3+E4AqnOAph51+NbAihzUk=
github.com/grisu48/gopenqa v0.3.2/go.mod h1:D7EFTPhtzNvnHnDol9UoPCFmnzOiLBVa1tOOYqJDgGo=
github.com/grisu48/gopenqa v0.3.3 h1:WTwTBcIc06uFW4NgMkbhq6bkH+3TGF1H3p5u2/9wYoI=
github.com/grisu48/gopenqa v0.3.3/go.mod h1:D7EFTPhtzNvnHnDol9UoPCFmnzOiLBVa1tOOYqJDgGo=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo=
github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=

0 comments on commit 94d054c

Please sign in to comment.