diff --git a/commands/actions/init.go b/commands/actions/init.go index f84c77b..797c15e 100644 --- a/commands/actions/init.go +++ b/commands/actions/init.go @@ -57,15 +57,24 @@ module.exports = { blockHelloWorldFn }; var initDescription = "This is just an example, but you can publish this action." var initAction = &actionsModel.ActionSpec{ - Description: &initDescription, - Function: "example:blockHelloWorldFn", - Trigger: actionsModel.TriggerUnparsed{Type: "block"}, + Description: &initDescription, + Function: "example:blockHelloWorldFn", + Trigger: actionsModel.TriggerUnparsed{Type: "block"}, + ExecutionType: "sequential", } func init() { - initCmd.PersistentFlags().StringVar(&actionsSourcesDir, "sources", "", "The path where the actions will be created.") - initCmd.PersistentFlags().StringVar(&actionsLanguage, "language", "typescript", "Initialize actions for this language. Supported {javascript, typescript}") - initCmd.PersistentFlags().StringVar(&actionsTemplateName, "template", "", "Initialize actions from this template, see Tenderly/tenderly-actions.") + initCmd.PersistentFlags().StringVar( + &actionsSourcesDir, "sources", "", "The path where the actions will be created.", + ) + initCmd.PersistentFlags().StringVar( + &actionsLanguage, "language", "typescript", + "Initialize actions for this language. Supported {javascript, typescript}", + ) + initCmd.PersistentFlags().StringVar( + &actionsTemplateName, "template", "", + "Initialize actions from this template, see Tenderly/tenderly-actions.", + ) actionsCmd.AddCommand(initCmd) } @@ -88,11 +97,13 @@ var initCmd = &cobra.Command{ "Actions for project are already initialized", userError.NewUserError( fmt.Errorf("actions initialized"), - commands.Colorizer.Sprintf("Actions for project %s are already initialized, see %s", + commands.Colorizer.Sprintf( + "Actions for project %s are already initialized, see %s", commands.Colorizer.Bold(commands.Colorizer.Green(projectSlug)), commands.Colorizer.Bold(commands.Colorizer.Green("tenderly.yaml")), ), - )) + ), + ) os.Exit(0) } @@ -106,7 +117,10 @@ var initCmd = &cobra.Command{ if err != nil { userError.LogErrorf( "failed to load template", - userError.NewUserError(err, fmt.Sprintf("Failed to load template %s", actionsTemplateName))) + userError.NewUserError( + err, fmt.Sprintf("Failed to load template %s", actionsTemplateName), + ), + ) os.Exit(1) } @@ -127,17 +141,22 @@ var initCmd = &cobra.Command{ if err != nil { userError.LogErrorf( "failed to load template specs", - userError.NewUserError(err, fmt.Sprintf("Failed to load specs for template %s", actionsTemplateName))) + userError.NewUserError( + err, fmt.Sprintf("Failed to load specs for template %s", actionsTemplateName), + ), + ) os.Exit(1) } } - config.MustWriteActionsInit(projectSlug, &actionsModel.ProjectActions{ - Runtime: actionsModel.RuntimeV2, - Sources: sources, - Dependencies: nil, - Specs: specs, - }) + config.MustWriteActionsInit( + projectSlug, &actionsModel.ProjectActions{ + Runtime: actionsModel.RuntimeV2, + Sources: sources, + Dependencies: nil, + Specs: specs, + }, + ) if actionsLanguage == LanguageJavaScript { filePath := filepath.Join(sources, "example.js") @@ -145,10 +164,13 @@ var initCmd = &cobra.Command{ util.CreateFileWithContent(filePath, content) - logrus.Info(commands.Colorizer.Sprintf("\nInitialized actions project. Sources directory created at %s. Configuration created in %s.", - commands.Colorizer.Bold(commands.Colorizer.Green(sources)), - commands.Colorizer.Bold(commands.Colorizer.Green("tenderly.yaml")), - )) + logrus.Info( + commands.Colorizer.Sprintf( + "\nInitialized actions project. Sources directory created at %s. Configuration created in %s.", + commands.Colorizer.Bold(commands.Colorizer.Green(sources)), + commands.Colorizer.Bold(commands.Colorizer.Green("tenderly.yaml")), + ), + ) os.Exit(0) } @@ -183,7 +205,10 @@ var initCmd = &cobra.Command{ if err != nil { userError.LogErrorf( "failed to create from template", - userError.NewUserError(err, fmt.Sprintf("Failed to create from template %s", actionsTemplateName))) + userError.NewUserError( + err, fmt.Sprintf("Failed to create from template %s", actionsTemplateName), + ), + ) os.Exit(1) } } @@ -191,10 +216,13 @@ var initCmd = &cobra.Command{ // Install dependencies mustInstallDependencies(sources) - logrus.Info(commands.Colorizer.Sprintf("\nInitialized actions project. Sources directory created at %s. Configuration created in %s.", - commands.Colorizer.Bold(commands.Colorizer.Green(sources)), - commands.Colorizer.Bold(commands.Colorizer.Green("tenderly.yaml")), - )) + logrus.Info( + commands.Colorizer.Sprintf( + "\nInitialized actions project. Sources directory created at %s. Configuration created in %s.", + commands.Colorizer.Bold(commands.Colorizer.Green(sources)), + commands.Colorizer.Bold(commands.Colorizer.Green("tenderly.yaml")), + ), + ) os.Exit(0) }, @@ -229,8 +257,10 @@ func promptTemplateArg(arg actionsModel.TemplateArg) string { if result == "" { userError.LogErrorf( "value for template arg not entered", - userError.NewUserError(errors.New("enter template arg"), - "Value for template arg not entered correctly"), + userError.NewUserError( + errors.New("enter template arg"), + "Value for template arg not entered correctly", + ), ) os.Exit(1) } @@ -241,7 +271,11 @@ func mustValidateFlags() { if actionsLanguage != LanguageTypeScript && actionsLanguage != LanguageJavaScript { userError.LogErrorf( "language not supported", - userError.NewUserError(errors.New("language not supported"), fmt.Sprintf("Language %s not supported", actionsLanguage))) + userError.NewUserError( + errors.New("language not supported"), + fmt.Sprintf("Language %s not supported", actionsLanguage), + ), + ) os.Exit(1) } } @@ -251,8 +285,10 @@ func chooseSources() string { if util.ExistFile(actionsSourcesDir) { userError.LogErrorf( "sources dir is file: %s", - userError.NewUserError(errors.New("sources dir is file"), - "Selected sources directory is a file."), + userError.NewUserError( + errors.New("sources dir is file"), + "Selected sources directory is a file.", + ), ) os.Exit(1) } @@ -260,8 +296,10 @@ func chooseSources() string { if util.ExistDir(actionsSourcesDir) { userError.LogErrorf( "sources dir exists: %s", - userError.NewUserError(errors.New("sources dir exists"), - "Selected sources directory already exists."), + userError.NewUserError( + errors.New("sources dir exists"), + "Selected sources directory already exists.", + ), ) os.Exit(1) } @@ -324,7 +362,8 @@ func excludeFromTsconfigParent(sourcesPath string, parentPath string) { if err != nil { userError.LogErrorf( "failed to get path relative to parentPath", - userError.NewUserError(err, fmt.Sprintf("Can't find relative path for %s", sourcesPath))) + userError.NewUserError(err, fmt.Sprintf("Can't find relative path for %s", sourcesPath)), + ) os.Exit(1) } rel = relTmp diff --git a/commands/actions/publish.go b/commands/actions/publish.go index 4cfc053..6cc63cb 100644 --- a/commands/actions/publish.go +++ b/commands/actions/publish.go @@ -86,17 +86,28 @@ func buildFunc(cmd *cobra.Command, args []string) { actions = mustGetProjectActions(allActions, projectSlug) logrus.Info("\nBuilding actions:") for actionName := range actions.Specs { - logrus.Info(commands.Colorizer.Sprintf( - "- %s", commands.Colorizer.Bold(commands.Colorizer.Green(actionName)))) + logrus.Info( + commands.Colorizer.Sprintf( + "- %s", commands.Colorizer.Bold(commands.Colorizer.Green(actionName)), + ), + ) } util.MustExistDir(actions.Sources) if !actionsModel.IsRuntimeSupported(actions.Runtime) { - logrus.Error(commands.Colorizer.Sprintf( - "Configured runtime %s is not supported. Supported values: {%s}", - commands.Colorizer.Bold(commands.Colorizer.Red(actions.Runtime)), - commands.Colorizer.Bold(commands.Colorizer.Green(strings.Join(actionsModel.SupportedRuntimes, ","))), - )) + logrus.Error( + commands.Colorizer.Sprintf( + "Configured runtime %s is not supported. Supported values: {%s}", + commands.Colorizer.Bold(commands.Colorizer.Red(actions.Runtime)), + commands.Colorizer.Bold( + commands.Colorizer.Green( + strings.Join( + actionsModel.SupportedRuntimes, ",", + ), + ), + ), + ), + ) os.Exit(1) } mustParseAndValidateTriggers(actions) @@ -104,13 +115,20 @@ func buildFunc(cmd *cobra.Command, args []string) { tsConfigExists := util.TsConfigExists(actions.Sources) tsFileExists, tsFile := anyFunctionTsFileExists(actions) if tsFileExists && !tsConfigExists { - err := errors.New(fmt.Sprintf("File %s is a typescript file but there is no typescript config file!", tsFile)) - userError.LogErrorf("missing typescript config file %s", - userError.NewUserError(err, + err := errors.New( + fmt.Sprintf( + "File %s is a typescript file but there is no typescript config file!", tsFile, + ), + ) + userError.LogErrorf( + "missing typescript config file %s", + userError.NewUserError( + err, commands.Colorizer.Sprintf( "Missing typescript config file in your sources! Sources: %s, File: %s", commands.Colorizer.Bold(commands.Colorizer.Red(actions.Sources)), - commands.Colorizer.Bold(commands.Colorizer.Red(tsFile))), + commands.Colorizer.Bold(commands.Colorizer.Red(tsFile)), + ), ), ) os.Exit(1) @@ -161,11 +179,14 @@ func mustParseAndValidateTriggers(projectActions *actionsModel.ProjectActions) { for name, spec := range projectActions.Specs { err := spec.Parse() if err != nil { - userError.LogErrorf("failed parsing action trigger with %s", - userError.NewUserError(err, + userError.LogErrorf( + "failed parsing action trigger with %s", + userError.NewUserError( + err, commands.Colorizer.Sprintf( "Failed parsing action trigger for %s", - commands.Colorizer.Bold(commands.Colorizer.Red(name))), + commands.Colorizer.Bold(commands.Colorizer.Red(name)), + ), ), ) os.Exit(1) @@ -216,8 +237,11 @@ func publish( logrus.Info("\nPublishing and deploying actions:") } for actionName := range actions.Specs { - logrus.Info(commands.Colorizer.Sprintf( - "- %s", commands.Colorizer.Bold(commands.Colorizer.Green(actionName)))) + logrus.Info( + commands.Colorizer.Sprintf( + "- %s", commands.Colorizer.Bold(commands.Colorizer.Green(actionName)), + ), + ) } logicZip, logicHash := util.MustZipAndHashDir(outDir, srcPathInZip, zipLimitBytes) @@ -226,7 +250,9 @@ func publish( } dependenciesDir := filepath.Join(actions.Sources, typescript.NodeModulesDir) - dependenciesZip, dependenciesHash := util.ZipAndHashDir(dependenciesDir, nodeModulesPathInZip, zipLimitBytes) + dependenciesZip, dependenciesHash := util.ZipAndHashDir( + dependenciesDir, nodeModulesPathInZip, zipLimitBytes, + ) if dependenciesExist { dependenciesZip = nil } @@ -248,11 +274,14 @@ func publish( s.Stop() if err != nil { - userError.LogErrorf("publish request failed", + userError.LogErrorf( + "publish request failed", userError.NewUserError( err, - commands.Colorizer.Sprintf("Publish request failed: %s", - commands.Colorizer.Red(err.Error())), + commands.Colorizer.Sprintf( + "Publish request failed: %s", + commands.Colorizer.Red(err.Error()), + ), ), ) os.Exit(1) @@ -264,11 +293,15 @@ func publish( logrus.Info("\nPublished and deployed actions:") } for key, version := range response.Actions { - logrus.Info(commands.Colorizer.Sprintf("- %s (actionId = %s, versionId = %s) %s", - commands.Colorizer.Bold(commands.Colorizer.Green(key)), - version.ActionId, - version.Id, - fmt.Sprintf(ActionUrlPattern, projectSlug, version.ActionId))) + logrus.Info( + commands.Colorizer.Sprintf( + "- %s (actionId = %s, versionId = %s) %s", + commands.Colorizer.Bold(commands.Colorizer.Green(key)), + version.ActionId, + version.Id, + fmt.Sprintf(ActionUrlPattern, projectSlug, version.ActionId), + ), + ) } } @@ -286,8 +319,10 @@ func mustBuildProject(sourcesDir string, tsconfig *typescript.TsConfig) { err := cmd.Run() if err != nil { - userError.LogErrorf("failed to run build typescript: %s", - userError.NewUserError(err, + userError.LogErrorf( + "failed to run build typescript: %s", + userError.NewUserError( + err, commands.Colorizer.Sprintf( "Failed to run: %s.", commands.Colorizer.Bold( @@ -323,7 +358,8 @@ func mustValidateAndGetSources( func mustGetSource(sourcesDir string, locator string) string { internalLocator, err := actionsModel.NewInternalLocator(locator) if err != nil { - userError.LogErrorf("invalid locator: %s", + userError.LogErrorf( + "invalid locator: %s", userError.NewUserError( err, commands.Colorizer.Sprintf( @@ -349,11 +385,13 @@ func mustGetSource(sourcesDir string, locator string) string { } } if !exists { - logrus.Error(commands.Colorizer.Sprintf( - "Invalid locator %s (file %s not found).", - commands.Colorizer.Bold(commands.Colorizer.Red(locator)), - commands.Colorizer.Bold(commands.Colorizer.Red(filePath)), - )) + logrus.Error( + commands.Colorizer.Sprintf( + "Invalid locator %s (file %s not found).", + commands.Colorizer.Bold(commands.Colorizer.Red(locator)), + commands.Colorizer.Bold(commands.Colorizer.Red(filePath)), + ), + ) os.Exit(1) } @@ -384,11 +422,14 @@ func mustValidate( response, err := r.Actions.Validate(request, projectSlug) if err != nil { - userError.LogErrorf("validate request failed", + userError.LogErrorf( + "validate request failed", userError.NewUserError( err, - commands.Colorizer.Sprintf("Validate request failed: %s", - commands.Colorizer.Red(err.Error())), + commands.Colorizer.Sprintf( + "Validate request failed: %s", + commands.Colorizer.Red(err.Error()), + ), ), ) os.Exit(1) @@ -397,7 +438,9 @@ func mustValidate( if len(response.Errors) > 0 { for name, errs := range response.Errors { logrus.Info( - commands.Colorizer.Sprintf("Validation for %s failed with errors:", commands.Colorizer.Yellow(name)), + commands.Colorizer.Sprintf( + "Validation for %s failed with errors:", commands.Colorizer.Yellow(name), + ), ) for _, e := range errs { logrus.Info(commands.Colorizer.Sprintf("%s: %s", commands.Colorizer.Red(e.Name), e.Message)) @@ -411,10 +454,12 @@ func mustValidate( func mustValidateTsconfig(tsconfig *typescript.TsConfig) { if tsconfig.CompilerOptions.OutDir == nil { - logrus.Error(commands.Colorizer.Sprintf( - "Invalid tsconfig - %s must be set.", - commands.Colorizer.Bold(commands.Colorizer.Red("compilerOptions.outDir")), - )) + logrus.Error( + commands.Colorizer.Sprintf( + "Invalid tsconfig - %s must be set.", + commands.Colorizer.Bold(commands.Colorizer.Red("compilerOptions.outDir")), + ), + ) os.Exit(1) } } @@ -424,7 +469,8 @@ func anyFunctionTsFileExists(actions *actionsModel.ProjectActions) (bool, string locator := spec.Function internalLocator, err := actionsModel.NewInternalLocator(locator) if err != nil { - userError.LogErrorf("invalid locator: %s", + userError.LogErrorf( + "invalid locator: %s", userError.NewUserError( err, commands.Colorizer.Sprintf( @@ -450,12 +496,16 @@ func mustExistCompiledFiles(outDir string, actions *actionsModel.ProjectActions) for _, spec := range actions.Specs { internalLocator, err := actionsModel.NewInternalLocator(spec.Function) if err != nil { - userError.LogErrorf("invalid locator: %s", - userError.NewUserError(err, + userError.LogErrorf( + "invalid locator: %s", + userError.NewUserError( + err, commands.Colorizer.Sprintf( "Invalid locator format %s.", commands.Colorizer.Bold(commands.Colorizer.Red(spec.Function)), - ))) + ), + ), + ) os.Exit(1) } @@ -469,12 +519,14 @@ func mustExistCompiledFiles(outDir string, actions *actionsModel.ProjectActions) } } if len(missingFilePaths) > 0 { - logrus.Errorf("Unable to resolve path for some of the compiled files: %s\n"+ - "Make sure all imported files are contained in the configured action sources directory (%s).\n"+ - "If the problem persists, please run this command with the %s flag and send logs to our customer support.", + logrus.Errorf( + "Unable to resolve path for some of the compiled files: %s\n"+ + "Make sure all imported files are contained in the configured action sources directory (%s).\n"+ + "If the problem persists, please run this command with the %s flag and send logs to our customer support.", commands.Colorizer.Bold(commands.Colorizer.Red(strings.Join(missingFilePaths, ", "))), commands.Colorizer.Bold(actions.Sources), - commands.Colorizer.Bold(commands.Colorizer.Red("--debug"))) + commands.Colorizer.Bold(commands.Colorizer.Red("--debug")), + ) os.Exit(1) } } @@ -482,11 +534,13 @@ func mustExistCompiledFiles(outDir string, actions *actionsModel.ProjectActions) func printPackageValidationErrors(validationErrors []*packagejson.ValidationError) { logrus.Error("The following packages have invalid versions:") for _, e := range validationErrors { - logrus.Error(commands.Colorizer.Sprintf( - " %s\n\tFound: %s\n\tRequired: %s", - commands.Colorizer.Bold(commands.Colorizer.Bold(e.Name)), - commands.Colorizer.Bold(commands.Colorizer.Red(e.PackageJsonVersion)), - commands.Colorizer.Bold(commands.Colorizer.Red(e.Constraint)), - )) + logrus.Error( + commands.Colorizer.Sprintf( + " %s\n\tFound: %s\n\tRequired: %s", + commands.Colorizer.Bold(commands.Colorizer.Bold(e.Name)), + commands.Colorizer.Bold(commands.Colorizer.Red(e.PackageJsonVersion)), + commands.Colorizer.Bold(commands.Colorizer.Red(e.Constraint)), + ), + ) } } diff --git a/model/actions/action.go b/model/actions/action.go index 49d0c6b..5896627 100644 --- a/model/actions/action.go +++ b/model/actions/action.go @@ -9,6 +9,11 @@ import ( "github.com/tenderly/tenderly-cli/rest/payloads/generated/actions" ) +const ( + sequentialExecutionType = "sequential" + parallelExecutionType = "parallel" +) + type Action struct { ID string `json:"id"` Name string `json:"name"` @@ -36,8 +41,9 @@ func (s *ProjectActions) ToRequest(sources map[string]string) map[string]actions Runtime: actions.New_Runtime(actions.Runtime_Value(s.Runtime)), Function: actions.Function(action.Function), // Field will be set when we access it - TriggerType: action.TriggerParsed.ToRequestType(), - Trigger: action.TriggerParsed.ToRequest(), + TriggerType: action.TriggerParsed.ToRequestType(), + Trigger: action.TriggerParsed.ToRequest(), + InvocationType: invocationTypeFromExecution(action.ExecutionType), } response[name] = spec } @@ -50,6 +56,7 @@ type ActionSpec struct { // Parsing and validation of trigger happens later, and Trigger field is set Trigger TriggerUnparsed `json:"trigger" yaml:"trigger"` TriggerParsed *Trigger `json:"-" yaml:"-"` + ExecutionType string `json:"execution_type" yaml:"execution_type"` } type TriggerUnparsed struct { @@ -105,3 +112,14 @@ func IsRuntimeSupported(runtime string) bool { return false } + +func invocationTypeFromExecution(executionType string) string { + switch executionType { + case sequentialExecutionType: + return "SYNC" + case parallelExecutionType: + return "ASYNC" + default: + return "" + } +} diff --git a/rest/payloads/generated/actions/structs.conjure.go b/rest/payloads/generated/actions/structs.conjure.go index 9f5ec2a..ada0ad8 100644 --- a/rest/payloads/generated/actions/structs.conjure.go +++ b/rest/payloads/generated/actions/structs.conjure.go @@ -65,11 +65,12 @@ type ActionSpec struct { Name string `json:"name"` Description *string `json:"description"` // Source code, usually just top level file when function is defined. - Source *string `json:"source" conjure-docs:"Source code, usually just top level file when function is defined."` - Runtime Runtime `json:"runtime"` - Function Function `json:"function"` - TriggerType TriggerType `json:"triggerType"` - Trigger *Trigger `json:"trigger"` + Source *string `json:"source" conjure-docs:"Source code, usually just top level file when function is defined."` + Runtime Runtime `json:"runtime"` + Function Function `json:"function"` + TriggerType TriggerType `json:"triggerType"` + Trigger *Trigger `json:"trigger"` + InvocationType string `json:"invocationType"` } func (o ActionSpec) MarshalYAML() (interface{}, error) {