100 lines
2.3 KiB
Go
100 lines
2.3 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func ciCommands() []Command {
|
||
|
|
return []Command{
|
||
|
|
{Path: []string{"ci", "status"}, Tier: TierRead,
|
||
|
|
Summary: "pipeline status for HEAD/a commit: ci status [commit]", Run: ciStatus},
|
||
|
|
{Path: []string{"ci", "watch"}, Tier: TierRead,
|
||
|
|
Summary: "poll the pipeline for HEAD (or a commit) to terminal; non-zero on failure", Run: ciWatch},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func short(s string) string {
|
||
|
|
if len(s) > 8 {
|
||
|
|
return s[:8]
|
||
|
|
}
|
||
|
|
return s
|
||
|
|
}
|
||
|
|
|
||
|
|
func firstLine(s string) string { return strings.SplitN(s, "\n", 2)[0] }
|
||
|
|
|
||
|
|
// currentHEAD returns the full HEAD sha of the cwd repo (empty if not a repo).
|
||
|
|
func currentHEAD() string {
|
||
|
|
cwd, _ := os.Getwd()
|
||
|
|
root, err := gitRepoRoot(cwd)
|
||
|
|
if err != nil {
|
||
|
|
return ""
|
||
|
|
}
|
||
|
|
sha, _ := gitOutput(root, "rev-parse", "HEAD")
|
||
|
|
return sha
|
||
|
|
}
|
||
|
|
|
||
|
|
func ciStatus(args []string) error {
|
||
|
|
commit, _ := firstPositional(args)
|
||
|
|
c, err := newWPClient()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
id, err := c.repoID()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
p, err := c.findPipeline(id, commit)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
fmt.Printf("#%d %s event=%s %s %s\n", p.Number, p.Status, p.Event, short(p.Commit), firstLine(p.Message))
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func ciWatch(args []string) error {
|
||
|
|
commit, _ := firstPositional(args)
|
||
|
|
if commit == "" {
|
||
|
|
commit = currentHEAD()
|
||
|
|
}
|
||
|
|
if commit == "" {
|
||
|
|
return fmt.Errorf("no commit given and not in a git repo")
|
||
|
|
}
|
||
|
|
c, err := newWPClient()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
id, err := c.repoID()
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
timeout := 20 * time.Minute
|
||
|
|
deadline := time.Now().Add(timeout)
|
||
|
|
last := ""
|
||
|
|
for time.Now().Before(deadline) {
|
||
|
|
p, err := c.findPipeline(id, commit)
|
||
|
|
if err != nil {
|
||
|
|
if last != "waiting" {
|
||
|
|
fmt.Fprintf(os.Stderr, "homelab: waiting for pipeline (%s)...\n", short(commit))
|
||
|
|
last = "waiting"
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if p.Status != last {
|
||
|
|
fmt.Fprintf(os.Stderr, "homelab: #%d %s\n", p.Number, p.Status)
|
||
|
|
last = p.Status
|
||
|
|
}
|
||
|
|
if isTerminalStatus(p.Status) {
|
||
|
|
fmt.Printf("#%d %s %s\n", p.Number, p.Status, short(commit))
|
||
|
|
if isFailureStatus(p.Status) {
|
||
|
|
return fmt.Errorf("pipeline #%d %s (woodpecker repo, see UI/DB for the failing step)", p.Number, p.Status)
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
time.Sleep(15 * time.Second)
|
||
|
|
}
|
||
|
|
return fmt.Errorf("timed out after %s waiting for CI on %s", timeout, short(commit))
|
||
|
|
}
|