import "github.com/egdaemon/eg/runtime/x/wasi/egnotif"
Package egnotif sends notifications about the outcome of a workload to messaging platforms.
The package provides the api, platforms are implemented as deliverers which are responsible for their own configuration. slog and smtp deliverers are builtin since they only require the standard library. Any type with a Send(ctx context.Context, v Context) error method can be used as a deliverer, which allows platforms such as chat services to be implemented outside of this package.
Create a notifier when the module starts and pass the result of the work to Fatalln. A nil error sends the completed message, a non-nil error sends the failure message. The error is returned so the module still fails when the work fails.
func Tests(ctx context.Context, _ eg.Op) error {
return shell.Run(ctx, shell.New("make test"))
}
func main() {
ctx := context.Background()
notify := egnotif.New(egnotif.Log(os.Stderr, egnotif.LogOptions()...))
err := notify.Fatalln(ctx, eg.Perform(ctx, eggit.AutoClone, Tests))
if err != nil {
log.Fatalln(err)
}
}
The failure and completed messages are optional, builtin defaults are used when they are not provided. Messages are markdown text/templates executed against Context.
notify := egnotif.New(
egnotif.Log(os.Stderr, egnotif.LogOptions()...),
egnotif.Options().
Failure("**{{.Workload}} failed** after {{.Elapsed}}: {{.Cause}}").
Completed("**{{.Workload}} completed** in {{.Elapsed}}").
Timeout(10*time.Second)...,
)
The fields available to templates are:
Delivery is bounded by a timeout, 30 seconds by default, configured with Options().Timeout(d). A deliverer that does not complete in time returns a context.DeadlineExceeded error which is joined with the workload's error.
The SMTP deliverer sends the rendered message to the recipients using net/smtp.
notify := egnotif.New(egnotif.SMTP(
"smtp.example.com:587",
egnotif.SMTPOptions().
From("eg@example.com").
To("team@example.com").
Auth(smtp.PlainAuth("", "user", os.Getenv("SMTP_PASSWORD"), "smtp.example.com")).
StartTLS(&tls.Config{})...,
))
Implement Send to deliver to any other platform. Context.Message renders the failure or completed template for you.
type slack struct{ webhook string }
func (t slack) Send(ctx context.Context, v egnotif.Context) error {
msg, err := v.Message()
if err != nil {
return err
}
// post msg to t.webhook, respecting ctx for cancellation.
return nil
}
```<details><summary>Example (Custom Deliverer)</summary>
<p>
any type with a Send method is a deliverer.
```go
package main
import (
"context"
"fmt"
"github.com/egdaemon/eg/runtime/x/wasi/egnotif"
)
type stdout struct{}
func (stdout) Send(ctx context.Context, v egnotif.Context) error {
msg, err := v.Message()
if err != nil {
return err
}
fmt.Println(msg)
return nil
}
func main() {
notify := egnotif.New(stdout{}, egnotif.Options().Completed("done")...)
_ = notify.Fatalln(context.Background(), nil)
}
done
const (
// DefaultFailure is the markdown text/template used when a run fails and no override is provided.
DefaultFailure = "**eg workload failed** {{.Workload }} - {{.RunID}}\n\n{{.VCSURI}}@{{.Commit}} after {{.Elapsed}}\n\n{{.Cause}}"
// DefaultCompleted is the markdown text/template used when a run completes and no override is provided.
DefaultCompleted = "**eg workload completed** {{.Workload }} - {{.RunID}}\n\n{{.VCSURI}}@{{.Commit}} in {{.Elapsed}}"
)
DefaultSMTPSubject is the text/template used for the subject when no override is provided.
const DefaultSMTPSubject = "eg workload {{if .Failed}}failed{{else}}completed{{end}}: {{.VCSURI}} {{.Workload}}"
Context is the information provided to deliverers about the run.
type Context struct {
VCSURI string // canonical uri of the repository.
Commit string // commit hash being run.
RunID string // id of the run.
Workload string // entry path of the workload, "default" for the default workload.
AccountID string // id of the account the run belongs to.
Initiated time.Time // when the run started.
Elapsed time.Duration // time elapsed since the run started.
Cause error // reason for the failure, nil when the run completed.
Failure string // markdown text/template used when the run failed.
Completed string // markdown text/template used when the run completed.
}
func (t Context) Failed() bool
Failed reports whether the run failed.
func (t Context) Message() (string, error)
Message renders the failure template if the run failed, otherwise the completed template.
func (t Context) Render(tmpl string) (string, error)
Render executes the text/template against the context.
LogOption configures the log deliverer.
type LogOption func(*logOption)
Notifier delivers the outcome of a run.
type Notifier struct {
// contains filtered or unexported fields
}
func New(d deliverer, options ...Option) *Notifier
New creates a notifier that sends to d. the run is considered started at the time provided by the runtime, see egenv.Initiated.
package main
import (
"context"
"fmt"
"os"
"github.com/egdaemon/eg/runtime/x/wasi/egnotif"
)
func main() {
notify := egnotif.New(egnotif.Log(os.Stdout, egnotif.LogOptions().Attrs("service", "example")...))
// nil means the workload completed.
if err := notify.Fatalln(context.Background(), nil); err != nil {
fmt.Println("unexpected error", err)
}
}
func (t *Notifier) Fatalln(ctx context.Context, cause error) error
Fatalln notifies the deliverer of the outcome of the run represented by cause, nil means the run completed. cause is returned, joined with any delivery error. it does not exit the process.
Option configures the notifier.
type Option func(*option)
SMTPOption configures the smtp deliverer.
type SMTPOption func(*smtpOption)