[READ-ONLY] Mirror of https://github.com/openstatusHQ/cli. OpenStatus CLI www.openstatus.dev
cli cli-app synthetic-monitoring
0

Configure Feed

Select the types of activity you want to include in your feed.

🚧 wip

+196 -15
+2
.gitignore
··· 1 + 2 + dist/
+47
.goreleaser.yaml
··· 1 + # This is an example .goreleaser.yml file with some sensible defaults. 2 + # Make sure to check the documentation at https://goreleaser.com 3 + 4 + # The lines below are called `modelines`. See `:help modeline` 5 + # Feel free to remove those if you don't want/need to use them. 6 + # yaml-language-server: $schema=https://goreleaser.com/static/schema.json 7 + # vim: set ts=2 sw=2 tw=0 fo=cnqoj 8 + 9 + version: 2 10 + 11 + before: 12 + hooks: 13 + # You may remove this if you don't use go modules. 14 + - go mod tidy 15 + # you may remove this if you don't need go generate 16 + - go generate ./... 17 + 18 + builds: 19 + - env: 20 + - CGO_ENABLED=0 21 + goos: 22 + - linux 23 + - windows 24 + - darwin 25 + - main: ./cmd/openstatus 26 + 27 + archives: 28 + - format: tar.gz 29 + # this name template makes the OS and Arch compatible with the results of `uname`. 30 + name_template: >- 31 + {{ .ProjectName }}_ 32 + {{- title .Os }}_ 33 + {{- if eq .Arch "amd64" }}x86_64 34 + {{- else if eq .Arch "386" }}i386 35 + {{- else }}{{ .Arch }}{{ end }} 36 + {{- if .Arm }}v{{ .Arm }}{{ end }} 37 + # use zip for windows archives 38 + format_overrides: 39 + - goos: windows 40 + format: zip 41 + 42 + changelog: 43 + sort: asc 44 + filters: 45 + exclude: 46 + - "^docs:" 47 + - "^test:"
+5
config.openstatus.yaml
··· 1 + tests: 2 + ids: 3 + - 2260 4 + - 2264 5 +
-5
config.openstatus.yml
··· 1 - tests: 2 - - id: 3 - - 1 4 - - 660 5 -
+4
go.mod
··· 6 6 7 7 require ( 8 8 github.com/fatih/color v1.18.0 9 + github.com/knadh/koanf/parsers/yaml v0.1.0 10 + github.com/knadh/koanf/providers/file v1.1.2 9 11 github.com/knadh/koanf/v2 v2.1.1 10 12 github.com/rodaine/table v1.3.0 11 13 ) 12 14 13 15 require ( 16 + github.com/fsnotify/fsnotify v1.7.0 // indirect 14 17 github.com/go-viper/mapstructure/v2 v2.2.1 // indirect 15 18 github.com/knadh/koanf/maps v0.1.1 // indirect 16 19 github.com/mattn/go-colorable v0.1.13 // indirect ··· 18 21 github.com/mitchellh/copystructure v1.2.0 // indirect 19 22 github.com/mitchellh/reflectwalk v1.0.2 // indirect 20 23 golang.org/x/sys v0.26.0 // indirect 24 + gopkg.in/yaml.v3 v3.0.1 // indirect 21 25 )
+7
go.sum
··· 3 3 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 4 github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= 5 5 github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= 6 + github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= 7 + github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= 6 8 github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= 7 9 github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 8 10 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 9 11 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 10 12 github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= 11 13 github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= 14 + github.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP1XFUxVI5w= 15 + github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY= 16 + github.com/knadh/koanf/providers/file v1.1.2 h1:aCC36YGOgV5lTtAFz2qkgtWdeQsgfxUkxDOe+2nQY3w= 17 + github.com/knadh/koanf/providers/file v1.1.2/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI= 12 18 github.com/knadh/koanf/v2 v2.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM= 13 19 github.com/knadh/koanf/v2 v2.1.1/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es= 14 20 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= ··· 43 49 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 44 50 golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= 45 51 golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 52 + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 46 53 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 47 54 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 48 55 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+20 -1
internal/config/config.go
··· 1 1 package config 2 2 3 - import "github.com/knadh/koanf/v2" 3 + import ( 4 + "github.com/knadh/koanf/parsers/yaml" 5 + "github.com/knadh/koanf/providers/file" 6 + 7 + "github.com/knadh/koanf/v2" 8 + ) 4 9 5 10 var k = koanf.New(".") 6 11 ··· 11 16 type Config struct { 12 17 Tests TestsConfig `koanf:"tests"` 13 18 } 19 + 20 + func ReadConfig(path string) (*Config, error) { 21 + k.Load(file.Provider(path), yaml.Parser()) 22 + 23 + var out Config 24 + 25 + err := k.Unmarshal("", &out) 26 + if err != nil { 27 + return nil, err 28 + } 29 + 30 + return &out, nil 31 + 32 + }
+4 -1
internal/monitors/monitor_info.go
··· 51 51 fmt.Println("Monitor information") 52 52 monitorId := cmd.Args().Get(0) 53 53 err := getMonitorInfo(http.DefaultClient, cmd.String("access-token"), monitorId) 54 - return err 54 + if err != nil { 55 + return cli.Exit("Failed to get monitor information", 1) 56 + } 57 + return nil 55 58 }, 56 59 Flags: []cli.Flag{ 57 60 &cli.StringFlag{
+1 -2
internal/monitors/monitor_trigger.go
··· 100 100 monitorId := cmd.Args().Get(0) 101 101 err := monitorTrigger(http.DefaultClient, cmd.String("access-token"), monitorId) 102 102 if err != nil { 103 - return err 103 + return cli.Exit("Failed to trigger monitor", 1) 104 104 } 105 - // fmt.Println("Triggering monitor test", r) 106 105 return nil 107 106 }, 108 107 }
+4 -1
internal/monitors/monitors_list.go
··· 72 72 }, 73 73 Action: func(ctx context.Context, cmd *cli.Command) error { 74 74 fmt.Println("List of all monitors") 75 - listMonitors(http.DefaultClient, cmd.String("access-token")) 75 + err := listMonitors(http.DefaultClient, cmd.String("access-token")) 76 + if err != nil { 77 + return cli.Exit("Failed to list monitors", 1) 78 + } 76 79 return nil 77 80 }, 78 81 }
+95 -2
internal/run/run.go
··· 2 2 3 3 import ( 4 4 "context" 5 + "encoding/json" 5 6 "fmt" 7 + "io" 8 + "net/http" 9 + "sync" 6 10 11 + "github.com/fatih/color" 12 + "github.com/openstatusHQ/cli/internal/config" 13 + "github.com/openstatusHQ/cli/internal/monitors" 14 + "github.com/rodaine/table" 7 15 "github.com/urfave/cli/v3" 8 16 ) 9 17 18 + func monitorTrigger(httpClient *http.Client, apiKey string, monitorId string) error { 19 + 20 + if monitorId == "" { 21 + return fmt.Errorf("Monitor ID is required") 22 + } 23 + 24 + url := fmt.Sprintf("https://api.openstatus.dev/v1/monitor/%s/run", monitorId) 25 + 26 + req, err := http.NewRequest("POST", url, nil) 27 + if err != nil { 28 + return err 29 + } 30 + req.Header.Add("x-openstatus-key", apiKey) 31 + res, err := httpClient.Do(req) 32 + if err != nil { 33 + return err 34 + } 35 + 36 + if res.StatusCode != http.StatusOK { 37 + return fmt.Errorf("Failed to trigger monitor test") 38 + } 39 + 40 + defer res.Body.Close() 41 + body, _ := io.ReadAll(res.Body) 42 + 43 + var result []monitors.RunResult 44 + err = json.Unmarshal(body, &result) 45 + if err != nil { 46 + return err 47 + } 48 + fmt.Println("Results for monitor:", monitorId) 49 + headerFmt := color.New(color.FgGreen, color.Underline).SprintfFunc() 50 + columnFmt := color.New(color.FgYellow).SprintfFunc() 51 + 52 + tbl := table.New("Region", "Latency (ms)", "Status") 53 + tbl.WithHeaderFormatter(headerFmt).WithFirstColumnFormatter(columnFmt) 54 + 55 + var inError bool 56 + for _, r := range result { 57 + if r.Error != "" { 58 + inError = true 59 + tbl.AddRow(r.Region, r.Latency, color.RedString("❌")) 60 + } else { 61 + tbl.AddRow(r.Region, r.Latency, color.GreenString("✔")) 62 + } 63 + 64 + } 65 + tbl.Print() 66 + 67 + if inError { 68 + fmt.Println(color.RedString("Some regions failed")) 69 + return fmt.Errorf("Some regions failed") 70 + } else { 71 + fmt.Println(color.GreenString("All regions passed")) 72 + } 73 + return nil 74 + } 75 + 10 76 func RunCmd() *cli.Command { 11 77 runCmd := cli.Command{ 12 78 Name: "run", ··· 14 80 Usage: "Run your synthetics tests defined in your configuration file", 15 81 Action: func(ctx context.Context, cmd *cli.Command) error { 16 82 17 - fmt.Println(cmd.String("config")) 18 - fmt.Println("Test ran 🔥") 83 + path := cmd.String("config") 84 + conf, err := config.ReadConfig(path) 85 + if err != nil { 86 + return err 87 + } 88 + size := len(conf.Tests.Ids) 89 + ch := make(chan error, size) 90 + 91 + fmt.Println("Tests are running") 92 + 93 + var wg sync.WaitGroup 94 + 95 + for _, id := range conf.Tests.Ids { 96 + wg.Add(1) 97 + go func(id int) { 98 + defer wg.Done() 99 + if err := monitorTrigger(http.DefaultClient, cmd.String("access-token"), fmt.Sprintf("%d", id)); err != nil { 100 + ch <- err 101 + } 102 + 103 + }(id) 104 + } 105 + wg.Wait() 106 + close(ch) // Close the channel when all workers have finished 107 + 108 + if len(ch) > 0 { 109 + return cli.Exit("Some tests failed", 1) 110 + } 111 + fmt.Println("Test ran succesfully🔥") 19 112 return nil 20 113 }, 21 114 Flags: []cli.Flag{
+7 -1
internal/whoami/whoami.go
··· 27 27 } 28 28 29 29 defer res.Body.Close() 30 + if res.StatusCode != http.StatusOK { 31 + return fmt.Errorf("Failed to get workspace information") 32 + } 30 33 body, _ := io.ReadAll(res.Body) 31 34 var whoami Whoami 32 35 err = json.Unmarshal(body, &whoami) ··· 47 50 Usage: "Get your current workspace information", 48 51 Action: func(ctx context.Context, cmd *cli.Command) error { 49 52 fmt.Println("Your current workspace information") 50 - getWhoamiCmd(http.DefaultClient, cmd.String("access-token")) 53 + err := getWhoamiCmd(http.DefaultClient, cmd.String("access-token")) 54 + if err != nil { 55 + return cli.Exit("Failed to get workspace information", 1) 56 + } 51 57 return nil 52 58 }, 53 59 Flags: []cli.Flag{
-2
openstatus.yml
··· 1 - tests: 2 - - id: 1