mirror of
https://github.com/lukaszraczylo/ghtracker.git
synced 2026-10-13 00:48:42 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78a6723143 |
@@ -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