mirror of
https://github.com/lukaszraczylo/ghtracker.git
synced 2026-10-14 00:58:36 +00:00
fix(web): run automatic actions after a repository rescan
The rescan button of one repository now triggers automatic actions too. The webhook calls run in the background so the response does not wait for them.
This commit is contained in:
@@ -96,7 +96,7 @@ actions:
|
|||||||
|
|
||||||
### Automatic actions
|
### Automatic actions
|
||||||
|
|
||||||
An action with `auto: true` fires without a click. After every scan, and once at startup, the server sends the webhook for each current alert whose kind is in `kinds`. It sends once per action, repo, alert URL and head commit. A new commit on a pull request is a new send.
|
An action with `auto: true` fires without a click. After every scan, after every single-repository rescan, and once at startup, the server sends the webhook for each current alert whose kind is in `kinds`. It sends once per action, repo, alert URL and head commit. A new commit on a pull request is a new send.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
actions:
|
actions:
|
||||||
|
|||||||
@@ -119,10 +119,13 @@ func (c *Collector) OnRefresh(fn func(context.Context, View)) { c.onRefresh = ap
|
|||||||
|
|
||||||
func (c *Collector) refreshAndNotify(ctx context.Context) {
|
func (c *Collector) refreshAndNotify(ctx context.Context) {
|
||||||
c.Refresh(ctx)
|
c.Refresh(ctx)
|
||||||
if len(c.onRefresh) == 0 || ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v := c.View()
|
c.notify(ctx, c.View())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) notify(ctx context.Context, v View) {
|
||||||
for _, fn := range c.onRefresh {
|
for _, fn := range c.onRefresh {
|
||||||
fn(ctx, v)
|
fn(ctx, v)
|
||||||
}
|
}
|
||||||
@@ -239,7 +242,12 @@ func (c *Collector) RefreshRepo(ctx context.Context, name string) (View, error)
|
|||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.repos[canon] = r
|
c.repos[canon] = r
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
return c.View(), nil
|
v := c.View()
|
||||||
|
if len(c.onRefresh) > 0 {
|
||||||
|
// The request context ends with the response, which must not wait for webhooks.
|
||||||
|
go c.notify(context.WithoutCancel(ctx), v)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) configured(name string) (string, bool) {
|
func (c *Collector) configured(name string) (string, bool) {
|
||||||
|
|||||||
@@ -519,3 +519,37 @@ func TestPROpenDoesNotChangeCounts(t *testing.T) {
|
|||||||
t.Fatalf("view = %+v", v)
|
t.Fatalf("view = %+v", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRefreshRepoRunsRefreshHooksWithTheNewView(t *testing.T) {
|
||||||
|
f := &fakeFetcher{fn: func(name string) (model.Repo, error) {
|
||||||
|
return model.Repo{FullName: name, URL: "u", Issues: make([]model.Issue, 3)}, nil
|
||||||
|
}}
|
||||||
|
c := newCollector(f, "o/a")
|
||||||
|
got := make(chan View, 1)
|
||||||
|
c.OnRefresh(func(_ context.Context, v View) { got <- v })
|
||||||
|
if _, err := c.RefreshRepo(context.Background(), "o/a"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case v := <-got:
|
||||||
|
if len(v.Repos) != 1 || len(v.Repos[0].Issues) != 3 {
|
||||||
|
t.Fatalf("hook saw a stale view: %+v", v.Repos)
|
||||||
|
}
|
||||||
|
case <-time.After(2 * time.Second):
|
||||||
|
t.Fatal("refresh hook did not run after a repository refresh")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRefreshRepoFailureSkipsRefreshHooks(t *testing.T) {
|
||||||
|
c := newCollector(&fakeFetcher{fn: func(string) (model.Repo, error) { return model.Repo{}, errors.New("nope") }}, "o/a")
|
||||||
|
called := make(chan struct{}, 1)
|
||||||
|
c.OnRefresh(func(context.Context, View) { called <- struct{}{} })
|
||||||
|
if _, err := c.RefreshRepo(context.Background(), "unknown/x"); err == nil {
|
||||||
|
t.Fatal("unknown repository must fail")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-called:
|
||||||
|
t.Fatal("hook ran for a refused refresh")
|
||||||
|
case <-time.After(200 * time.Millisecond):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user