watchpr: detect merge/close in poll loop (was hanging after baseline)
watchpr only reported meaningful changes as transitions from the poll baseline. A PR already merged or closed when the watch started was captured as the baseline and never produced a transition, so the loop polled the dead PR forever (process alive, never exiting) -- the single-PR --interval case observed in production. Add a terminal-state check applied to the baseline snapshot: a PR that is already merged or closed the moment watchpr starts is reported and exits immediately, since it can never change again. Extract the baseline+poll loop into agent.Watch behind a StateFetcher interface so the loop, its open->merged/close detection, and its poll-error resilience are unit-testable with a fake client.
This commit is contained in:
+13
-26
@@ -117,36 +117,23 @@ func runOnce(c *agent.GiteaClient, refs []agent.PRRef, jsonMode bool) error {
|
||||
func runWatch(c *agent.GiteaClient, refs []agent.PRRef, interval time.Duration, jsonMode bool) error {
|
||||
login := agent.AgentLogin()
|
||||
|
||||
prev := make(map[string]agent.PRState, len(refs))
|
||||
for _, ref := range refs {
|
||||
st, err := agent.FetchState(c, ref, login)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prev[ref.String()] = st
|
||||
}
|
||||
if !jsonMode {
|
||||
fmt.Fprintf(os.Stderr, "watching %d PR(s) every %s; baseline established\n", len(refs), interval)
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(interval)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
for _, ref := range refs {
|
||||
key := ref.String()
|
||||
cur, err := agent.FetchState(c, ref, login)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "warning: polling %s: %v\n", key, err)
|
||||
continue
|
||||
}
|
||||
changed, reason := agent.MeaningfulChange(prev[key], cur)
|
||||
if changed {
|
||||
report(key, reason, cur, jsonMode)
|
||||
return nil
|
||||
}
|
||||
prev[key] = cur
|
||||
|
||||
onBaseline := func() {
|
||||
if !jsonMode {
|
||||
fmt.Fprintf(os.Stderr, "watching %d PR(s) every %s; baseline established\n", len(refs), interval)
|
||||
}
|
||||
}
|
||||
onError := func(ref agent.PRRef, err error) {
|
||||
fmt.Fprintf(os.Stderr, "warning: polling %s: %v\n", ref.String(), err)
|
||||
}
|
||||
|
||||
res, err := agent.Watch(c, refs, login, ticker.C, onBaseline, onError)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
report(res.Ref.String(), res.Reason, res.State, jsonMode)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user