diff --git a/Makefile b/Makefile index a1464c1..80c5e2b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ MAKEOPTS = $(MAKEOPTS) GIT_COMMIT := $(shell git rev-list -1 HEAD) -VERSION := 0.2.9.3 +VERSION := 0.2.9.4-dev BUILDOPTS :=$(BUILDOPTS) -ldflags "-X main.version=$(VERSION) -X main.gitCommit=$(GIT_COMMIT)" .PHONY: install all clean diff --git a/bacillus.go b/bacillus.go index 368521e..912245d 100644 --- a/bacillus.go +++ b/bacillus.go @@ -42,8 +42,10 @@ const ( ) type cmdItem struct { - script string - lastStatus int + script string + lastRunStartTime time.Time + lastRunDuration time.Duration + lastStatus int } var ( @@ -591,12 +593,12 @@ func manualJobTriggersHTML(fullLogLink bool) (ret string) { ret += fmt.Sprintf("-- job script %s not found --\n", cmdMap[jobName].script) } else { if isParameterizedBuildScript(cmdMap[jobName].script) { - ret += fmt.Sprintf("[▹] %s [action %s] [last status: %d]\n", - jobName, jobName, cmdMap[jobName].script, cmdMap[jobName].lastStatus) + ret += fmt.Sprintf("[▹] %s [action %s] [last status: %d/%v]\n", + jobName, jobName, cmdMap[jobName].script, cmdMap[jobName].lastStatus, cmdMap[jobName].lastRunDuration) } else { fn := strings.Replace(jobName, "-", "", -1) - ret += fmt.Sprintf(`[▸] %s [action %s] [last status: %d]`+"\n", - fn, jobName, jobName, cmdMap[jobName].script, cmdMap[jobName].lastStatus) + ret += fmt.Sprintf(`[▸] %s [action %s] [last status: %d/%v]`+"\n", + fn, jobName, jobName, cmdMap[jobName].script, cmdMap[jobName].lastStatus, cmdMap[jobName].lastRunDuration) } } } @@ -920,6 +922,10 @@ func execJob(j jobCtx, hookData hookEvt) { strings.Replace(workerOutputRelPath, jobHomeDir, "/"+jobHomeDir+"/fullconsole", 1)) //nolint:errcheck fmt.Fprintf(c.Stdout, "%s\n", j.jobTag) //nolint:errcheck + tmp := cmdMap[j.jobTag] + tmp.lastRunStartTime = time.Now() + cmdMap[j.jobTag] = tmp + cerr := c.Start() if cerr != nil { log.Printf("[exec.Cmd: %+v]\n", c) @@ -951,6 +957,10 @@ func execJob(j jobCtx, hookData hookEvt) { } werr := c.Wait() + tmp = cmdMap[j.jobTag] + tmp.lastRunDuration = time.Since(tmp.lastRunStartTime).Truncate(100 * time.Millisecond) + cmdMap[j.jobTag] = tmp + var exitStatus int if werr, ok := werr.(*exec.ExitError); ok { // The program has exited with an exit code != 0 @@ -990,26 +1000,32 @@ func execJob(j jobCtx, hookData hookEvt) { } if werr == nil { - log.Printf("[✓]%s[%s{%s}[⩐] completed with status 0]%s\n", + log.Printf("[✓]%s[%s{%s}[⩐] completed with status 0/%v]%s\n", jobID, instColour, workerOutputRelPath, indentStr, j.jobTag, jobID, j.jobOpts, j.jobTag, jobID, + cmdMap[j.jobTag].lastRunDuration, stageStr) // Update job last completion status - cmdMap[j.jobTag] = cmdItem{script: cmdMap[j.jobTag].script, lastStatus: int(0)} + tmp := cmdMap[j.jobTag] + tmp.lastStatus = int(0) + cmdMap[j.jobTag] = tmp } else { - log.Printf("[!]%s[%s{%s}[⩌] completed with error %s]%s\n", + log.Printf("[!]%s[%s{%s}[⩌] completed with error %s/%v]%s\n", jobID, instColour, workerOutputRelPath, indentStr, j.jobTag, jobID, j.jobOpts, j.jobTag, jobID, werr, + cmdMap[j.jobTag].lastRunDuration, stageStr) // Update job last completion status - cmdMap[j.jobTag] = cmdItem{script: cmdMap[j.jobTag].script, lastStatus: int(exitStatus)} + tmp := cmdMap[j.jobTag] + tmp.lastStatus = int(exitStatus) + cmdMap[j.jobTag] = tmp } delete(runningJobs, jobID) } @@ -1023,7 +1039,7 @@ func jobLastStatusHandler(w http.ResponseWriter, r *http.Request) { slugs := strings.Split(r.URL.String(), "/") if len(slugs) >= 2 { tag := slugs[len(slugs)-2] - writeStr(w, fmt.Sprintf("%s lastStatus:%d", tag, cmdMap[tag].lastStatus)) + writeStr(w, fmt.Sprintf("%d", cmdMap[tag].lastStatus)) } else { writeStr(w, "error") } @@ -1050,6 +1066,20 @@ func jobLastStatusIconHandler(w http.ResponseWriter, r *http.Request) { } } +func jobLastRunDurationHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-type", "text/html;charset=UTF-8") + if !httpAuthSession(w, r) { + return + } + slugs := strings.Split(r.URL.String(), "/") + if len(slugs) >= 2 { + tag := slugs[len(slugs)-2] + writeStr(w, fmt.Sprintf("%v", cmdMap[tag].lastRunDuration)) + } else { + writeStr(w, "error") + } +} + func jobCancelHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-type", "text/html;charset=UTF-8") if !httpAuthSession(w, r) { @@ -1574,9 +1604,11 @@ func main() { // it isn't read). launchJobListener(mainCtx, cmd, tag, jobOpts, jobEnv, cmdMap) - // Endpoint to return lastStatus for the job + // Endpoint to return lastStatus value and success/fail badge for the job http.HandleFunc("/"+tag+"/lastStatus", jobLastStatusHandler) http.HandleFunc("/"+tag+"/lastStatusIcon", jobLastStatusIconHandler) + // Endpoint to return last run duration for the job + http.HandleFunc("/"+tag+"/lastRunDuration", jobLastRunDurationHandler) } }