From 32825bea2048dd3d62fa1fab8dcc0dac561e3e4b Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Wed, 15 Jan 2020 16:10:41 +0300 Subject: [PATCH 1/9] Fix cookbook syntax --- COOKBOOK.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/COOKBOOK.md b/COOKBOOK.md index 58f9f5a0..c28f5c73 100644 --- a/COOKBOOK.md +++ b/COOKBOOK.md @@ -977,7 +977,7 @@ command "-" "Check environment" Waits for PID file. -**Syntax:** `wait-pid ` +**Syntax:** `wait-pid [timeout]` **Arguments:** @@ -1000,7 +1000,7 @@ command "-" "Check environment" Waits for file/directory. -**Syntax:** `wait-fs ` +**Syntax:** `wait-fs [timeout]` **Arguments:** @@ -1072,7 +1072,7 @@ Sends signal to process. If `pid-file` not defined signal will be sent to current process. -**Syntax:** `signal ` +**Syntax:** `signal [pid-file]` **Arguments:** From 9ab05991b9afdcd291efd3e17614ea242e643f4b Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Wed, 15 Jan 2020 16:59:25 +0300 Subject: [PATCH 2/9] Refactoring --- action/http.go | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/action/http.go b/action/http.go index 66f6c6e4..8d661d25 100644 --- a/action/http.go +++ b/action/http.go @@ -157,8 +157,7 @@ func HTTPContains(action *recipe.Action) error { // isHTTPMethodSupported returns true if HTTP method is supported func isHTTPMethodSupported(method string) bool { switch method { - case req.GET, req.POST, req.DELETE, - req.PUT, req.PATCH, req.HEAD: + case req.GET, req.POST, req.DELETE, req.PUT, req.PATCH, req.HEAD: return true } @@ -167,25 +166,24 @@ func isHTTPMethodSupported(method string) bool { // makeHTTPRequest creates request struct func makeHTTPRequest(method, url string) *req.Request { - if !strings.Contains(url, "@") { - return &req.Request{Method: method, URL: url, AutoDiscard: true, FollowRedirect: true} + r := &req.Request{Method: method, URL: url, AutoDiscard: true, FollowRedirect: true} + + if strings.Contains(url, "@") { + url, user, pass := extractAuthInfo(url) + r.URL, r.BasicAuthUsername, r.BasicAuthPassword = url, user, pass } + return r +} + +// extractAuthInfo extracts username and password for basic auth from URL +func extractAuthInfo(url string) (string, string, string) { auth := strutil.ReadField(url, 0, false, "@") auth = strings.Replace(auth, "http://", "", -1) auth = strings.Replace(auth, "https://", "", -1) url = strings.Replace(url, auth+"@", "", -1) - login := strutil.ReadField(auth, 0, false, ":") - pass := strutil.ReadField(auth, 1, false, ":") - - return &req.Request{ - Method: method, - URL: url, - BasicAuthUsername: login, - BasicAuthPassword: pass, - AutoDiscard: true, - FollowRedirect: true, - } + return url, strutil.ReadField(auth, 0, false, ":"), + strutil.ReadField(auth, 1, false, ":") } From e2647fb60834a7ba33ff9cf500ba1933ac55c748 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Wed, 15 Jan 2020 17:19:38 +0300 Subject: [PATCH 3/9] BIP-23 Add the possibility to define a payload for POST requests --- action/http.go | 66 ++++++++++++++++++++++++++++++++++++++++-------- recipe/tokens.go | 6 ++--- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/action/http.go b/action/http.go index 8d661d25..0fce4548 100644 --- a/action/http.go +++ b/action/http.go @@ -21,6 +21,8 @@ import ( // HTTPStatus is action processor for "http-status" func HTTPStatus(action *recipe.Action) error { + var payload string + method, err := action.GetS(0) if err != nil { @@ -39,11 +41,17 @@ func HTTPStatus(action *recipe.Action) error { return err } - if !isHTTPMethodSupported(method) { - return fmt.Errorf("Method %s is not supported", method) + if action.Has(3) { + payload, _ = action.GetS(3) } - resp, err := makeHTTPRequest(method, url).Do() + err = checkRequestData(method, payload) + + if err != nil { + return err + } + + resp, err := makeHTTPRequest(method, url, payload).Do() if err != nil { return fmt.Errorf("Can't send HTTP request %s %s", method, url) @@ -61,6 +69,8 @@ func HTTPStatus(action *recipe.Action) error { // HTTPHeader is action processor for "http-header" func HTTPHeader(action *recipe.Action) error { + var payload string + method, err := action.GetS(0) if err != nil { @@ -85,11 +95,17 @@ func HTTPHeader(action *recipe.Action) error { return err } - if !isHTTPMethodSupported(method) { - return fmt.Errorf("Method %s is not supported", method) + if action.Has(4) { + payload, _ = action.GetS(4) } - resp, err := makeHTTPRequest(method, url).Do() + err = checkRequestData(method, payload) + + if err != nil { + return err + } + + resp, err := makeHTTPRequest(method, url, payload).Do() if err != nil { return fmt.Errorf("Can't send HTTP request %s %s", method, url) @@ -112,6 +128,8 @@ func HTTPHeader(action *recipe.Action) error { // HTTPContains is action processor for "http-contains" func HTTPContains(action *recipe.Action) error { + var payload string + method, err := action.GetS(0) if err != nil { @@ -130,11 +148,17 @@ func HTTPContains(action *recipe.Action) error { return err } - if !isHTTPMethodSupported(method) { - return fmt.Errorf("Method %s is not supported", method) + if action.Has(4) { + payload, _ = action.GetS(4) + } + + err = checkRequestData(method, payload) + + if err != nil { + return err } - resp, err := makeHTTPRequest(method, url).Do() + resp, err := makeHTTPRequest(method, url, payload).Do() if err != nil { return fmt.Errorf("Can't send HTTP request %s %s", method, url) @@ -164,8 +188,26 @@ func isHTTPMethodSupported(method string) bool { return false } +func checkRequestData(method, payload string) error { + switch method { + case req.GET, req.POST, req.DELETE, req.PUT, req.PATCH, req.HEAD: + // nop + default: + return fmt.Errorf("Method %s is not supported", method) + } + + switch method { + case req.GET, req.DELETE, req.HEAD: + if payload != "" { + return fmt.Errorf("Method %s does not support payload", method) + } + } + + return nil +} + // makeHTTPRequest creates request struct -func makeHTTPRequest(method, url string) *req.Request { +func makeHTTPRequest(method, url, payload string) *req.Request { r := &req.Request{Method: method, URL: url, AutoDiscard: true, FollowRedirect: true} if strings.Contains(url, "@") { @@ -173,6 +215,10 @@ func makeHTTPRequest(method, url string) *req.Request { r.URL, r.BasicAuthUsername, r.BasicAuthPassword = url, user, pass } + if payload != "" { + r.Body = payload + } + return r } diff --git a/recipe/tokens.go b/recipe/tokens.go index dee264b5..20d0761e 100644 --- a/recipe/tokens.go +++ b/recipe/tokens.go @@ -169,9 +169,9 @@ var Tokens = []TokenInfo{ {ACTION_SERVICE_ENABLED, 1, 1, false, true}, {ACTION_SERVICE_WORKS, 1, 1, false, true}, - {ACTION_HTTP_STATUS, 3, 3, false, true}, - {ACTION_HTTP_HEADER, 4, 4, false, true}, - {ACTION_HTTP_CONTAINS, 3, 3, false, true}, + {ACTION_HTTP_STATUS, 3, 4, false, true}, + {ACTION_HTTP_HEADER, 4, 5, false, true}, + {ACTION_HTTP_CONTAINS, 3, 4, false, true}, {ACTION_LIB_LOADED, 1, 1, false, true}, {ACTION_LIB_HEADER, 1, 1, false, true}, From 3aca7ce7ccd9cad6889d54d3644ba85ac3975640 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Wed, 15 Jan 2020 17:24:15 +0300 Subject: [PATCH 4/9] Fix copy-paste bug --- action/http.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/action/http.go b/action/http.go index 0fce4548..423281ae 100644 --- a/action/http.go +++ b/action/http.go @@ -148,8 +148,8 @@ func HTTPContains(action *recipe.Action) error { return err } - if action.Has(4) { - payload, _ = action.GetS(4) + if action.Has(3) { + payload, _ = action.GetS(3) } err = checkRequestData(method, payload) From 800b997b851e942e39fb22d148bb018de53a8861 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Thu, 16 Jan 2020 00:23:58 +0300 Subject: [PATCH 5/9] Refactoring --- action/http.go | 2 +- recipe/recipe.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/action/http.go b/action/http.go index 423281ae..c2b4540a 100644 --- a/action/http.go +++ b/action/http.go @@ -191,7 +191,7 @@ func isHTTPMethodSupported(method string) bool { func checkRequestData(method, payload string) error { switch method { case req.GET, req.POST, req.DELETE, req.PUT, req.PATCH, req.HEAD: - // nop + // NOOP default: return fmt.Errorf("Method %s is not supported", method) } diff --git a/recipe/recipe.go b/recipe/recipe.go index 800ffc3f..fff956c6 100644 --- a/recipe/recipe.go +++ b/recipe/recipe.go @@ -60,8 +60,8 @@ type Action struct { } type Variable struct { - Value string - ReadOnly bool + Value string + IsReadOnly bool } // ////////////////////////////////////////////////////////////////////////////////// // @@ -127,7 +127,7 @@ func (r *Recipe) SetVariable(name, value string) error { return nil } - if !varInfo.ReadOnly { + if !varInfo.IsReadOnly { r.variables[name].Value = value return nil } From ccc52ae63b630c8e17d78fab99d252c35ff79cd1 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Thu, 16 Jan 2020 02:12:48 +0300 Subject: [PATCH 6/9] Add the possibility to set basic auth data and headers for http requests --- COOKBOOK.md | 88 +++++++++++++++++++++++++++++++---- action/http.go | 99 ++++++++++++++++++++++++++++++---------- cli/cli.go | 2 +- cli/executor/executor.go | 2 + recipe/recipe.go | 35 +++++++++++++- recipe/recipe_test.go | 12 +++++ recipe/tokens.go | 10 ++-- 7 files changed, 211 insertions(+), 37 deletions(-) diff --git a/COOKBOOK.md b/COOKBOOK.md index c28f5c73..d7c8ccfd 100644 --- a/COOKBOOK.md +++ b/COOKBOOK.md @@ -68,6 +68,8 @@ * [`http-status`](#http-status) * [`http-header`](#http-header) * [`http-contains`](#http-contains) + * [`http-set-auth`](#http-set-auth) + * [`http-set-header`](#http-set-header) * [Libraries](#libraries) * [`lib-loaded`](#lib-loaded) * [`lib-header`](#lib-header) @@ -1401,31 +1403,38 @@ command "-" "Check environment" Makes HTTP request and checks status code. -**Syntax:** `http-status ` +**Syntax:** `http-status [payload]` **Arguments:** * `method` - Method (_String_) * `url` - URL (_String_) * `code` - Status code (_Integer_) +* `payload` - Request payload (_String_) [Optional] **Negative form:** Yes -**Example:** +**Examples:** ```yang -command "-" "Check environment" +command "-" "Make HTTP request" http-status GET "http://127.0.0.1:19999" 200 ``` +```yang +command "-" "Make HTTP request" + http-status PUT "http://127.0.0.1:19999" 200 '{"id":103}' + +``` +
##### `http-header` Makes HTTP request and checks response header value. -**Syntax:** `http-header ` +**Syntax:** `http-header [payload]` **Arguments:** @@ -1433,43 +1442,106 @@ Makes HTTP request and checks response header value. * `url` - URL (_String_) * `header-name` - Header name (_String_) * `header-value` - Header value (_String_) +* `payload` - Request payload (_String_) [Optional] **Negative form:** Yes -**Example:** +**Examples:** ```yang -command "-" "Check environment" +command "-" "Make HTTP request" http-header GET "http://127.0.0.1:19999" strict-transport-security "max-age=32140800" ``` +```yang +command "-" "Make HTTP request" + http-header PUT "http://127.0.0.1:19999" x-request-status "OK" '{"id":103}' + +``` +
##### `http-contains` Makes HTTP request and checks response data for some substring. -**Syntax:** `http-contains ` +**Syntax:** `http-contains [payload]` **Arguments:** * `method` - Method (_String_) * `url` - URL (_String_) * `substr` - Substring for search (_String_) +* `payload` - Request payload (_String_) [Optional] **Negative form:** Yes **Example:** ```yang -command "-" "Check environment" +command "-" "Make HTTP request" http-contains GET "http://127.0.0.1:19999/info" "version: 1" ```
+##### `http-set-auth` + +Sets username and password for Basic Auth. + +_Notice that auth data will be set only for current command scope._ + +**Syntax:** `http-set-auth ` + +**Arguments:** + +* `username` - User name (_String_) +* `password` - Password (_String_) + +**Negative form:** No + +**Example:** + +```yang +command "-" "Make HTTP request with auth" + http-set-auth admin test1234 + http-status GET "http://127.0.0.1:19999" 200 + +command "-" "Make HTTP request without auth" + http-status GET "http://127.0.0.1:19999" 403 + +``` + +
+ +##### `http-set-header` + +Sets request header. + +_Notice that header will be set only for current command scope._ + +**Syntax:** `http-set-header ` + +**Arguments:** + +* `header-name` - Header name (_String_) +* `header-value` - Header value (_String_) + +**Negative form:** No + +**Example:** + +```yang +command "-" "Make HTTP request" + http-set-header Accept application/vnd.myapp.v3+json + http-status GET "http://127.0.0.1:19999" 200 + +``` + +
+ #### Libraries ##### `lib-loaded` diff --git a/action/http.go b/action/http.go index c2b4540a..fac629c5 100644 --- a/action/http.go +++ b/action/http.go @@ -12,13 +12,20 @@ import ( "strings" "pkg.re/essentialkaos/ek.v11/req" - "pkg.re/essentialkaos/ek.v11/strutil" "github.com/essentialkaos/bibop/recipe" ) // ////////////////////////////////////////////////////////////////////////////////// // +const ( + PROP_HTTP_REQUEST_HEADERS = "HTTP_REQUEST_HEADERS" + PROP_HTTP_AUTH_USERNAME = "HTTP_AUTH_USERNAME" + PROP_HTTP_AUTH_PASSWORD = "HTTP_AUTH_PASSWORD" +) + +// ////////////////////////////////////////////////////////////////////////////////// // + // HTTPStatus is action processor for "http-status" func HTTPStatus(action *recipe.Action) error { var payload string @@ -51,7 +58,7 @@ func HTTPStatus(action *recipe.Action) error { return err } - resp, err := makeHTTPRequest(method, url, payload).Do() + resp, err := makeHTTPRequest(action, method, url, payload).Do() if err != nil { return fmt.Errorf("Can't send HTTP request %s %s", method, url) @@ -105,7 +112,7 @@ func HTTPHeader(action *recipe.Action) error { return err } - resp, err := makeHTTPRequest(method, url, payload).Do() + resp, err := makeHTTPRequest(action, method, url, payload).Do() if err != nil { return fmt.Errorf("Can't send HTTP request %s %s", method, url) @@ -158,7 +165,7 @@ func HTTPContains(action *recipe.Action) error { return err } - resp, err := makeHTTPRequest(method, url, payload).Do() + resp, err := makeHTTPRequest(action, method, url, payload).Do() if err != nil { return fmt.Errorf("Can't send HTTP request %s %s", method, url) @@ -176,6 +183,59 @@ func HTTPContains(action *recipe.Action) error { return nil } +// HTTPSetAuth is action processor for "http-set-auth" +func HTTPSetAuth(action *recipe.Action) error { + command := action.Command + + username, err := action.GetS(0) + + if err != nil { + return err + } + + password, err := action.GetS(1) + + if err != nil { + return err + } + + command.SetProp(PROP_HTTP_AUTH_USERNAME, username) + command.SetProp(PROP_HTTP_AUTH_PASSWORD, password) + + return nil +} + +// HTTPSetHeader is action processor for "http-set-header" +func HTTPSetHeader(action *recipe.Action) error { + command := action.Command + + headerName, err := action.GetS(0) + + if err != nil { + return err + } + + headerValue, err := action.GetS(1) + + if err != nil { + return err + } + + var headers req.Headers + + if !command.HasProp(PROP_HTTP_REQUEST_HEADERS) { + headers = req.Headers{} + } else { + headers = command.GetProp(PROP_HTTP_REQUEST_HEADERS).(req.Headers) + } + + headers[headerName] = headerValue + + command.SetProp(PROP_HTTP_REQUEST_HEADERS, headers) + + return nil +} + // ////////////////////////////////////////////////////////////////////////////////// // // isHTTPMethodSupported returns true if HTTP method is supported @@ -207,29 +267,22 @@ func checkRequestData(method, payload string) error { } // makeHTTPRequest creates request struct -func makeHTTPRequest(method, url, payload string) *req.Request { - r := &req.Request{Method: method, URL: url, AutoDiscard: true, FollowRedirect: true} - - if strings.Contains(url, "@") { - url, user, pass := extractAuthInfo(url) - r.URL, r.BasicAuthUsername, r.BasicAuthPassword = url, user, pass - } +func makeHTTPRequest(action *recipe.Action, method, url, payload string) *req.Request { + command := action.Command + request := &req.Request{Method: method, URL: url, AutoDiscard: true, FollowRedirect: true} if payload != "" { - r.Body = payload + request.Body = payload } - return r -} - -// extractAuthInfo extracts username and password for basic auth from URL -func extractAuthInfo(url string) (string, string, string) { - auth := strutil.ReadField(url, 0, false, "@") - auth = strings.Replace(auth, "http://", "", -1) - auth = strings.Replace(auth, "https://", "", -1) + if command.HasProp(PROP_HTTP_AUTH_USERNAME) && command.HasProp(PROP_HTTP_AUTH_PASSWORD) { + request.BasicAuthUsername = command.GetProp(PROP_HTTP_AUTH_USERNAME).(string) + request.BasicAuthPassword = command.GetProp(PROP_HTTP_AUTH_PASSWORD).(string) + } - url = strings.Replace(url, auth+"@", "", -1) + if command.HasProp(PROP_HTTP_REQUEST_HEADERS) { + request.Headers = command.GetProp(PROP_HTTP_REQUEST_HEADERS).(req.Headers) + } - return url, strutil.ReadField(auth, 0, false, ":"), - strutil.ReadField(auth, 1, false, ":") + return request } diff --git a/cli/cli.go b/cli/cli.go index bf655a95..5d15efac 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -33,7 +33,7 @@ import ( // Application info const ( APP = "bibop" - VER = "1.8.0" + VER = "2.0.0" DESC = "Utility for testing command-line tools" ) diff --git a/cli/executor/executor.go b/cli/executor/executor.go index fbd5e73d..f4bc6324 100644 --- a/cli/executor/executor.go +++ b/cli/executor/executor.go @@ -108,6 +108,8 @@ var handlers = map[string]action.Handler{ recipe.ACTION_HTTP_STATUS: action.HTTPStatus, recipe.ACTION_HTTP_HEADER: action.HTTPHeader, recipe.ACTION_HTTP_CONTAINS: action.HTTPContains, + recipe.ACTION_HTTP_SET_AUTH: action.HTTPSetAuth, + recipe.ACTION_HTTP_SET_HEADER: action.HTTPSetHeader, recipe.ACTION_LIB_LOADED: action.LibLoaded, recipe.ACTION_LIB_HEADER: action.LibHeader, recipe.ACTION_LIB_CONFIG: action.LibConfig, diff --git a/recipe/recipe.go b/recipe/recipe.go index fff956c6..6bc5c890 100644 --- a/recipe/recipe.go +++ b/recipe/recipe.go @@ -46,7 +46,9 @@ type Command struct { Actions []*Action // Slice with actions Line uint16 // Line in recipe - Recipe *Recipe + props map[string]interface{} // Properties + + Recipe *Recipe // Link to recipe } // Action contains action name and slice with arguments @@ -56,7 +58,7 @@ type Action struct { Negative bool // Is negative Line uint16 // Line in recipe - Command *Command + Command *Command // Link to command } type Variable struct { @@ -194,6 +196,35 @@ func (c *Command) Index() int { return -1 } +// SetProp sets property with given name +func (c *Command) SetProp(name string, value interface{}) { + if c.props == nil { + c.props = make(map[string]interface{}) + } + + c.props[name] = value +} + +// GetProp returns property with given name +func (c *Command) GetProp(name string) interface{} { + if c.props == nil { + return "" + } + + return c.props[name] +} + +// HasProp returns true if the property is present in the store +func (c *Command) HasProp(name string) bool { + if c.props == nil { + return false + } + + _, ok := c.props[name] + + return ok +} + // ////////////////////////////////////////////////////////////////////////////////// // // Index returns action index diff --git a/recipe/recipe_test.go b/recipe/recipe_test.go index e94666ee..4b775f72 100644 --- a/recipe/recipe_test.go +++ b/recipe/recipe_test.go @@ -260,9 +260,21 @@ func (s *RecipeSuite) TestAux(c *C) { variables: map[string]*Variable{"test": &Variable{"ABC", true}}, } + k := &Command{} + + r.AddCommand(k, "") + c.Assert(renderVars(nil, "{abcd}"), Equals, "{abcd}") c.Assert(renderVars(r, "{abcd}"), Equals, "{abcd}") c.Assert(renderVars(r, "{test}.{test}"), Equals, "ABC.ABC") + + c.Assert(k.GetProp("TEST"), Equals, "") + c.Assert(k.HasProp("TEST"), Equals, false) + + k.SetProp("TEST", "ABCD") + + c.Assert(k.GetProp("TEST"), Equals, "ABCD") + c.Assert(k.HasProp("TEST"), Equals, true) } // ////////////////////////////////////////////////////////////////////////////////// // diff --git a/recipe/tokens.go b/recipe/tokens.go index 20d0761e..aebe7b5b 100644 --- a/recipe/tokens.go +++ b/recipe/tokens.go @@ -74,9 +74,11 @@ const ( ACTION_SERVICE_ENABLED = "service-enabled" ACTION_SERVICE_WORKS = "service-works" - ACTION_HTTP_STATUS = "http-status" - ACTION_HTTP_HEADER = "http-header" - ACTION_HTTP_CONTAINS = "http-contains" + ACTION_HTTP_STATUS = "http-status" + ACTION_HTTP_HEADER = "http-header" + ACTION_HTTP_CONTAINS = "http-contains" + ACTION_HTTP_SET_AUTH = "http-set-auth" + ACTION_HTTP_SET_HEADER = "http-set-header" ACTION_LIB_LOADED = "lib-loaded" ACTION_LIB_HEADER = "lib-header" @@ -172,6 +174,8 @@ var Tokens = []TokenInfo{ {ACTION_HTTP_STATUS, 3, 4, false, true}, {ACTION_HTTP_HEADER, 4, 5, false, true}, {ACTION_HTTP_CONTAINS, 3, 4, false, true}, + {ACTION_HTTP_SET_AUTH, 2, 2, false, false}, + {ACTION_HTTP_SET_HEADER, 2, 2, false, false}, {ACTION_LIB_LOADED, 1, 1, false, true}, {ACTION_LIB_HEADER, 1, 1, false, true}, From 43879af600b20a29553c8ef95afa1a17e96dbe25 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Thu, 16 Jan 2020 02:22:24 +0300 Subject: [PATCH 7/9] Improve cookbook --- COOKBOOK.md | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/COOKBOOK.md b/COOKBOOK.md index d7c8ccfd..8105c897 100644 --- a/COOKBOOK.md +++ b/COOKBOOK.md @@ -302,7 +302,13 @@ Waits till command will be finished and then checks exit code. **Negative form:** Yes -**Example:** +**Examples:** + +```yang +command "git clone git@github.com:user/repo.git" "Repository clone" + exit 0 + +``` ```yang command "git clone git@github.com:user/repo.git" "Repository clone" @@ -361,6 +367,12 @@ command "echo 'ABCD'" "Simple echo command" ``` +```yang +command "echo 'ABCD'" "Simple echo command with 1 seconds timeout" + expect "ABCD" 1 + +``` +
##### `print` @@ -988,7 +1000,13 @@ Waits for PID file. **Negative form:** Yes -**Example:** +**Examples:** + +```yang +command "-" "Check environment" + wait-pid /var/run/service.pid + +``` ```yang command "-" "Check environment" @@ -1011,7 +1029,13 @@ Waits for file/directory. **Negative form:** Yes -**Example:** +**Examples:** + +```yang +command "service myapp start" "Starting MyApp" + wait-fs /var/log/myapp.log + +``` ```yang command "service myapp start" "Starting MyApp" @@ -1083,7 +1107,7 @@ If `pid-file` not defined signal will be sent to current process. **Negative form:** No -**Example:** +**Examples:** ```yang command "myapp --daemon" "Check my app" @@ -1091,6 +1115,12 @@ command "myapp --daemon" "Check my app" ``` +```yang +command "myapp --daemon" "Check my app" + signal HUP /var/run/myapp.pid + +``` + ```yang command "myapp --daemon" "Check my app" signal 16 From 740520afaf6a2ad01b5da73e5cbbc389d283bef8 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Thu, 16 Jan 2020 03:26:22 +0300 Subject: [PATCH 8/9] Improve tests --- parser/parser_test.go | 5 ++++- testdata/test1.recipe | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/parser/parser_test.go b/parser/parser_test.go index 28c369c1..43d92661 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -88,7 +88,10 @@ func (s *ParseSuite) TestBasicParsing(c *C) { c.Assert(recipe.Commands[0].Tag, Equals, "") c.Assert(recipe.Commands[0].Cmdline, Equals, "echo") c.Assert(recipe.Commands[0].Description, Equals, "Simple echo command") - c.Assert(recipe.Commands[0].Actions, HasLen, 2) + c.Assert(recipe.Commands[0].Actions, HasLen, 3) + + v, _ := recipe.Commands[0].Actions[1].GetS(0) + c.Assert(v, Equals, `{"id": "test"}`) c.Assert(recipe.Commands[1].User, Equals, "") c.Assert(recipe.Commands[1].Tag, Equals, "special") diff --git a/testdata/test1.recipe b/testdata/test1.recipe index 2039d579..9af3855b 100644 --- a/testdata/test1.recipe +++ b/testdata/test1.recipe @@ -11,6 +11,7 @@ var user nobody command "{user}:echo" "Simple echo command" !exist "/etc/unknown.txt" + expect '{"id": "test"}' exit 1 command:special "echo" "Simple echo command" From cc73d86805de690a18aadf9c081acdb26c1b89f6 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Thu, 16 Jan 2020 15:43:03 +0300 Subject: [PATCH 9/9] Set default user agent for HTTP requests --- cli/cli.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cli/cli.go b/cli/cli.go index 5d15efac..485e7ff6 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -16,6 +16,7 @@ import ( "pkg.re/essentialkaos/ek.v11/fmtutil" "pkg.re/essentialkaos/ek.v11/fsutil" "pkg.re/essentialkaos/ek.v11/options" + "pkg.re/essentialkaos/ek.v11/req" "pkg.re/essentialkaos/ek.v11/strutil" "pkg.re/essentialkaos/ek.v11/usage" "pkg.re/essentialkaos/ek.v11/usage/completion/bash" @@ -90,6 +91,7 @@ func Init() { } configureUI() + configureSubsystems() if options.GetB(OPT_VER) { showAbout() @@ -121,6 +123,11 @@ func configureUI() { } } +// configureSubsystems configures bibop subsystems +func configureSubsystems() { + req.Global.SetUserAgent(APP, VER) +} + // validateOptions validates options func validateOptions() { errsDir := options.GetS(OPT_ERROR_DIR)