Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#404 - WIP #451

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ this is based on [GoJQ which has a number of differences](https://github.com/itc
epcc runbooks run misc get-store-info
```

### Retries vs Ignoring Errors

Retries in epcc-cli will retry the _exact_ rendered request so if you are using templated parameters i.e., `auto-fill` and the failure is deterministic (say a unique constraint),
a retry will just get stuck in a loop. In this case if you want to create many different records, you want to `--ignore-errors`.

## Development Tips

### Fast rebuilds
Expand Down
3 changes: 3 additions & 0 deletions cmd/repeater.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ func repeater(c func(*cobra.Command, []string) error, repeat, repeatDelay uint32
if ignoreErrors {
log.Debugf("Ignored error %v", ignoreErrors)
} else {
if repeat > 1 && !ignoreErrors {
log.Infof("if you want to continue in the face of errors use the --ignore-errors")
}
return err
}
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func InitializeCmd() {
RootCmd.PersistentFlags().StringVarP(&profileNameFromCommandLine, "profile", "P", "", "overrides the current EPCC_PROFILE var to run the command with the chosen profile.")
RootCmd.PersistentFlags().Uint16VarP(&rateLimit, "rate-limit", "", 10, "Request limit per second")
RootCmd.PersistentFlags().BoolVarP(&httpclient.Retry5xx, "retry-5xx", "", false, "Whether we should retry requests with HTTP 5xx response code")
RootCmd.PersistentFlags().BoolVarP(&httpclient.Retry4xx, "retry-4xx", "", false, "Whether we should retry requests with HTTP 4xx response code")
RootCmd.PersistentFlags().BoolVarP(&httpclient.Retry429, "retry-429", "", false, "Whether we should retry requests with HTTP 429 response code")
RootCmd.PersistentFlags().BoolVarP(&httpclient.RetryConnectionErrors, "retry-connection-errors", "", false, "Whether we should retry requests with connection errors")
RootCmd.PersistentFlags().UintVarP(&httpclient.RetryDelay, "retry-delay", "", 500, "When retrying how long should we delay")
Expand Down Expand Up @@ -286,12 +287,13 @@ func Execute() {
<-shutdownHandlerDone

if err != nil {

log.Errorf("Error occurred while processing command: %s", err)

os.Exit(1)
} else {

os.Exit(0)
//os.Exit(0)
}
}

Expand Down
4 changes: 3 additions & 1 deletion cmd/runbooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ func initRunbookShowCommands() *cobra.Command {

for _, line := range rawCmdLines {
if len(strings.Trim(line, " \n")) > 0 {
//if i <= 10 {
println(line)
//}
}

}
Expand Down Expand Up @@ -420,12 +422,12 @@ func processRunbookVariablesOnCommand(runbookActionRunActionCommand *cobra.Comma
log.Errorf("Could not set flag as required, this is a bug of some kind %s: %v", key, err)
}
} else {

description := ""

if variable.Description != nil {
description = variable.Description.Short
}

runbookActionRunActionCommand.Flags().StringVar(runbookStringArguments[key], key, variable.Default, description)
}

Expand Down
48 changes: 24 additions & 24 deletions docs/runbook-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,30 +170,30 @@ name: hello-world
description:
short: "A hello world runbook"
actions:
sequential-sleeps:
variables:
count:
type: INT
default: 2
description:
short: "The number of sleeps"
commands:
- |2
{{- range untilStep 0 .count 1}}
- sleep 1
{{- end -}}
concurrent-sleeps:
variables:
count:
type: INT
default: 2
description:
short: "The number of sleeps"
commands:
- |
{{- range untilStep 0 .count 1}}
sleep 1
{{- end -}}
sequential-sleeps:
variables:
count:
type: INT
default: 2
description:
short: "The number of sleeps"
commands:
- |2
{{- range untilStep 0 .count 1}}
- sleep 1
{{- end -}}
concurrent-sleeps:
variables:
count:
type: INT
default: 2
description:
short: "The number of sleeps"
commands:
- |
{{- range untilStep 0 .count 1}}
sleep 1
{{- end -}}
```

It's important for all commands to be indended the same amount, and start with a `-` this will cause the entire string to be valid as a Yaml array.
Expand Down
1 change: 1 addition & 0 deletions external/completion/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ func Complete(c Request) ([]string, cobra.ShellCompDirective) {
}
results = append(results, supportedFileTypes...)
}

}
}
}
Expand Down
1 change: 1 addition & 0 deletions external/httpclient/httpclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func Initialize(rateLimit uint16, requestTimeout float32, statisticsFrequency in

var Retry429 = false
var Retry5xx = false
var Retry4xx = false

var RetryConnectionErrors = false

Expand Down
6 changes: 5 additions & 1 deletion external/json/to_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"github.com/elasticpath/epcc-cli/external/aliases"
"github.com/elasticpath/epcc-cli/external/resources"
"github.com/elasticpath/epcc-cli/external/templates"
"github.com/itchyny/gojq"
log "github.com/sirupsen/logrus"
"regexp"
Expand Down Expand Up @@ -53,6 +54,9 @@ func toJsonObject(args []string, noWrapping bool, compliant bool, attributes map
key := args[i]
val := args[i+1]

// Try and process the argument as a helm template
val = templates.Render(val)

jsonKey := key
switch {
case key == "type" || key == "id":
Expand Down Expand Up @@ -265,6 +269,6 @@ func formatValue(v string) string {
} else if match, _ := regexp.MatchString("^\\[\\]$", v); match {
return v
} else {
return fmt.Sprintf("\"%s\"", v)
return fmt.Sprintf("\"%s\"", strings.ReplaceAll(v, `"`, `\"`))
}
}
55 changes: 53 additions & 2 deletions external/resources/yaml/resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ account-authentication-settings:
auto_create_account_for_account_members:
type: BOOL
account_member_self_management:
type: BOOL
type: ENUM:disabled,update_only

account-management-authentication-tokens:
singular-name: "account-management-authentication-token"
json-api-type: "account_management_authentication_token"
Expand All @@ -30,7 +31,7 @@ account-management-authentication-tokens:
content-type: application/json
attributes:
authentication_mechanism:
type: STRING
type: ENUM:oidc,password,passwordless,self_signup
oauth_authorization_code:
type: STRING
oauth_redirect_uri:
Expand All @@ -43,6 +44,13 @@ account-management-authentication-tokens:
type: STRING
password:
type: STRING
name:
type: STRING
autofill: FUNC:Name
email:
type: string
autofill: FUNC:Email

suppress-reset-warning: true
account-members:
singular-name: "account-member"
Expand Down Expand Up @@ -1575,9 +1583,15 @@ pcm-nodes:
get-entity:
docs: "https://documentation.elasticpath.com/commerce-cloud/docs/api/pcm/hierarchies/nodes/get-a-hierarchy-node.html"
url: "/pcm/hierarchies/{pcm_hierarchies}/nodes/{pcm_nodes}"
get-collection:
docs: "https://documentation.elasticpath.com/commerce-cloud/docs/api/pcm/hierarchies/nodes/get-a-hierarchy-node.html"
url: "/pcm/hierarchies/{pcm_hierarchies}/nodes"
update-entity:
docs: "https://documentation.elasticpath.com/commerce-cloud/docs/api/pcm/hierarchies/nodes/update-a-hierarchy-node.html"
url: "/pcm/hierarchies/{pcm_hierarchies}/nodes/{pcm_nodes}"
get-collection:
docs: "https://documentation.elasticpath.com/commerce-cloud/docs/api/pcm/hierarchies/nodes/get-a-hierarchy-node.html"
url: "/pcm/hierarchies/{pcm_hierarchies}/nodes"
delete-entity:
docs: "https://documentation.elasticpath.com/commerce-cloud/docs/api/pcm/hierarchies/nodes/delete-a-hierarchy-node.html"
url: "/pcm/hierarchies/{pcm_hierarchies}/nodes/{pcm_nodes}"
Expand Down Expand Up @@ -1777,8 +1791,10 @@ pcm-pricebooks:
attributes:
name:
type: STRING
autofill: FUNC:Company
description:
type: STRING
autofill: FUNC:Phrase
pcm-product-prices:
singular-name: "pcm-product-price"
json-api-type: "product-price"
Expand Down Expand Up @@ -1816,6 +1832,41 @@ pcm-product-prices:
type: INT
currencies.CAD.includes_tax:
type: BOOL
pcm-pricebook-modifiers:
singular-name: "pcm-pricebook-modifier"
json-api-format: "compliant"
json-api-type: "price-modifier"
docs: "https://elasticpath.dev/docs/pxm/pricebooks/pxm-pricebooks-modifiers/get-a-price-modifier"
get-collection:
docs: "https://elasticpath.dev/docs/pxm/pricebooks/pxm-pricebooks-modifiers/get-all-price-modifiers"
url: "/pcm/pricebooks/{pcm_pricebooks}/modifiers/"
get-entity:
docs: "https://elasticpath.dev/docs/pxm/pricebooks/pxm-pricebooks-modifiers/get-a-price-modifier"
url: "/pcm/pricebooks/{pcm_pricebooks}/modifiers/{pcm_pricebook_modifiers}"
create-entity:
docs: "https://elasticpath.dev/docs/pxm/pricebooks/pxm-pricebooks-modifiers/create-a-price-modifier"
url: "/pcm/pricebooks/{pcm_pricebooks}/modifiers"
update-entity:
docs: "https://elasticpath.dev/docs/pxm/pricebooks/pxm-pricebooks-modifiers/update-a-price-modifier"
url: "/pcm/pricebooks/{pcm_pricebooks}/modifiers/{pcm_pricebook_modifiers}"
delete-entity:
docs: "https://elasticpath.dev/docs/pxm/pricebooks/pxm-pricebooks-modifiers/delete-a-price-modifier"
url: "/pcm/pricebooks/{pcm_pricebooks}/modifiers/{pcm_pricebook_modifiers}"
attributes:
name:
type: STRING
autofill: FUNC:BuzzWord
modifier_type:
type: ENUM:price_increment,price_decrement,price_equals
autofill: VALUE:price_equals
currencies.USD.amount:
type: INT
currencies.USD.includes_tax:
type: BOOL
^currencies\.USD\.tiers\..+\.minimum_quantity$:
type: INT
^currencies\.USD\.tiers\..+\.amount$:
type: INT
pcm-variations:
singular-name: "pcm-variation"
json-api-type: "product-variation"
Expand Down
9 changes: 9 additions & 0 deletions external/runbooks/account-management.epcc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ actions:
# Initialize alias for Authentication Realm
- epcc get account-authentication-settings
- epcc create password-profile related_authentication_realm_for_account_authentication_settings_last_read=entity name "Username and Password Authentication"
enable-self-signup-and-management:
description:
short: "Enable password authentication"
commands:
# Initialize alias for Authentication Realm
- epcc get account-authentication-settings
- |
epcc create password-profile related_authentication_realm_for_account_authentication_settings_last_read=entity name "Username and Password Authentication"
epcc update account-authentication-setting enable_self_signup true auto_create_account_for_account_members true account_member_self_management "update_only"
create-deep-hierarchy:
description:
short: "Create a hierarchy"
Expand Down
47 changes: 46 additions & 1 deletion external/runbooks/runbook_rendering.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"bytes"
"fmt"
"github.com/Masterminds/sprig/v3"
"math"
"math/rand"
"strconv"
"strings"
"text/template"
Expand All @@ -20,7 +22,15 @@ func CreateMapForRunbookArgumentPointers(runbookAction *RunbookAction) map[strin
}

func RenderTemplates(templateName string, rawCmd string, stringVars map[string]*string, variableDefinitions map[string]Variable) ([]string, error) {
tpl, err := template.New(templateName).Funcs(sprig.FuncMap()).Parse(rawCmd)
tpl, err := template.New(templateName).Funcs(sprig.FuncMap()).Funcs(
map[string]any{
"pow": func(a, b int) int { return int(math.Pow(float64(a), float64(b))) },
"pseudoRandAlphaNum": randAlphaNum,
"pseudoRandAlpha": randAlpha,
"pseudoRandNumeric": randNumeric,
"pseudoRandString": randString,
"pseudoRandInt": randInt,
}).Parse(rawCmd)

if err != nil {
// Handle this case better
Expand All @@ -40,10 +50,13 @@ func RenderTemplates(templateName string, rawCmd string, stringVars map[string]*
return nil, fmt.Errorf("error processing variable %s, value %v is not an integer: %w", key, *val, err)
}
data[key] = parsedVal
data[strings.ReplaceAll(key, "-", "_")] = parsedVal
} else if variableDef.Type == "STRING" {
data[key] = val
data[strings.ReplaceAll(key, "-", "_")] = val
} else if strings.HasPrefix(variableDef.Type, "RESOURCE_ID:") {
data[key] = val
data[strings.ReplaceAll(key, "-", "_")] = val
} else {
return nil, fmt.Errorf("error processing variable %s, unknown type [%s] specified in template", key, variableDef.Type)
}
Expand All @@ -63,3 +76,35 @@ func RenderTemplates(templateName string, rawCmd string, stringVars map[string]*
rawCmdLines := strings.Split(renderedTpl.String(), "\n")
return rawCmdLines, nil
}

// randString is the internal function that generates a random string.
// It takes the length of the string and a string of allowed characters as parameters.
func randString(letters string, n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}

// randAlphaNum generates a string consisting of characters in the range 0-9, a-z, and A-Z.
func randAlphaNum(n int) string {
const letters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
return randString(letters, n)
}

// randAlpha generates a string consisting of characters in the range a-z and A-Z.
func randAlpha(n int) string {
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
return randString(letters, n)
}

// randNumeric generates a string consisting of characters in the range 0-9.
func randNumeric(n int) string {
const digits = "0123456789"
return randString(digits, n)
}

func randInt(min, max int) int {
return rand.Intn(max-min) + min
}
2 changes: 1 addition & 1 deletion external/runbooks/runbook_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"properties": {
"type": {
"type": "string",
"pattern": "^(STRING|URL|INT|ENUM:[a-z0-9A-Z._,-]+|FLOAT|BOOL|FILE|CURRENCY|SINGULAR_RESOURCE_TYPE|JSON_API_TYPE|RESOURCE_ID:[a-z0-9-]+)$"
"pattern": "^(STRING|URL|INT|ENUM:[a-z0-9A-Z._,-]+|FLOAT|BOOL|FILE|CURRENCY|SINGULAR_RESOURCE_TYPE|JSON_API_TYPE|RESOURCE_ID:[a-z0-9-]+|ANY)$"
},
"default": {
"type": ["integer", "string"],
Expand Down
Loading
Loading