diff --git a/plugin/studio/package_analyze_command.go b/plugin/studio/package_analyze_command.go index fd1ff70..2907bbf 100644 --- a/plugin/studio/package_analyze_command.go +++ b/plugin/studio/package_analyze_command.go @@ -82,8 +82,10 @@ func (c PackageAnalyzeCommand) execute(source string, treatWarningsAsErrors bool args = append(args, "--stopOnRuleViolation") } + projectReader := newStudioProjectReader(source) + uipcli := newUipcli(c.Exec, logger) - cmd, err := uipcli.Execute(args...) + cmd, err := uipcli.Execute(projectReader.GetTargetFramework(), args...) if err != nil { return 1, nil, err } diff --git a/plugin/studio/package_pack_command.go b/plugin/studio/package_pack_command.go index 6bc236d..35ecef6 100644 --- a/plugin/studio/package_pack_command.go +++ b/plugin/studio/package_pack_command.go @@ -90,8 +90,10 @@ func (c PackagePackCommand) execute(params packagePackParams, debug bool, logger args = append(args, "--releaseNotes", params.ReleaseNotes) } + projectReader := newStudioProjectReader(params.Source) + uipcli := newUipcli(c.Exec, logger) - cmd, err := uipcli.Execute(args...) + cmd, err := uipcli.Execute(projectReader.GetTargetFramework(), args...) if err != nil { return nil, err } @@ -120,7 +122,7 @@ func (c PackagePackCommand) execute(params packagePackParams, debug bool, logger go c.wait(cmd, &wg) wg.Wait() - projectJson, err := c.readProjectJson(params.Source) + project, err := projectReader.ReadMetadata() if err != nil { return nil, err } @@ -132,16 +134,16 @@ func (c PackagePackCommand) execute(params packagePackParams, debug bool, logger version := c.extractVersion(nupkgFile) result = newSucceededPackagePackResult( filepath.Join(params.Destination, nupkgFile), - projectJson.Name, - projectJson.Description, - projectJson.ProjectId, + project.Name, + project.Description, + project.ProjectId, version) } else { result = newFailedPackagePackResult( stderrOutputBuilder.String(), - &projectJson.Name, - &projectJson.Description, - &projectJson.ProjectId) + &project.Name, + &project.Description, + &project.ProjectId) } return result, nil } @@ -214,25 +216,6 @@ func (c PackagePackCommand) getSource(context plugin.ExecutionContext) (string, return source, nil } -func (c PackagePackCommand) readProjectJson(path string) (projectJson, error) { - file, err := os.Open(path) - if err != nil { - return projectJson{}, fmt.Errorf("Error reading %s file: %v", defaultProjectJson, err) - } - defer file.Close() - byteValue, err := io.ReadAll(file) - if err != nil { - return projectJson{}, fmt.Errorf("Error reading %s file: %v", defaultProjectJson, err) - } - - var project projectJson - err = json.Unmarshal(byteValue, &project) - if err != nil { - return projectJson{}, fmt.Errorf("Error parsing %s file: %v", defaultProjectJson, err) - } - return project, nil -} - func (c PackagePackCommand) getDestination(context plugin.ExecutionContext) (string, error) { destination := c.getParameter("destination", context.Parameters) if destination == "" { diff --git a/plugin/studio/project/.gitignore b/plugin/studio/project/.gitignore deleted file mode 100644 index 658eff9..0000000 --- a/plugin/studio/project/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -* -!.gitignore -!Main.xaml -!project.json \ No newline at end of file diff --git a/plugin/studio/project_json.go b/plugin/studio/project_json.go deleted file mode 100644 index fb577cd..0000000 --- a/plugin/studio/project_json.go +++ /dev/null @@ -1,7 +0,0 @@ -package studio - -type projectJson struct { - Name string `json:"name"` - Description string `json:"description"` - ProjectId string `json:"projectId"` -} diff --git a/plugin/studio/projects/.gitignore b/plugin/studio/projects/.gitignore new file mode 100644 index 0000000..57c19d8 --- /dev/null +++ b/plugin/studio/projects/.gitignore @@ -0,0 +1,6 @@ +crossplatform/* +!crossplatform/Main.xaml +!crossplatform/project.json +windows/* +!windows/Main.xaml +!windows/project.json \ No newline at end of file diff --git a/plugin/studio/project/Main.xaml b/plugin/studio/projects/crossplatform/Main.xaml similarity index 98% rename from plugin/studio/project/Main.xaml rename to plugin/studio/projects/crossplatform/Main.xaml index 2c90b2c..c7168e2 100644 --- a/plugin/studio/project/Main.xaml +++ b/plugin/studio/projects/crossplatform/Main.xaml @@ -1,87 +1,87 @@ - - - - System.Activities - System.Activities.Statements - System.Activities.Expressions - System.Activities.Validation - System.Activities.XamlIntegration - Microsoft.VisualBasic - Microsoft.VisualBasic.Activities - System - System.Collections - System.Collections.Generic - System.Collections.ObjectModel - System.Data - System.Diagnostics - System.Drawing - System.IO - System.Linq - System.Net.Mail - System.Xml - System.Text - System.Xml.Linq - UiPath.Core - UiPath.Core.Activities - System.Windows.Markup - GlobalVariablesNamespace - GlobalConstantsNamespace - System.Linq.Expressions - System.Runtime.Serialization - - - - - Microsoft.CSharp - Microsoft.VisualBasic - mscorlib - System - System.Activities - System.ComponentModel.TypeConverter - System.Core - System.Data - System.Data.Common - System.Data.DataSetExtensions - System.Drawing - System.Drawing.Common - System.Drawing.Primitives - System.Linq - System.Net.Mail - System.ObjectModel - System.Private.CoreLib - System.Runtime.Serialization - System.ServiceModel - System.ServiceModel.Activities - System.Xaml - System.Xml - System.Xml.Linq - UiPath.System.Activities - UiPath.UiAutomation.Activities - UiPath.Studio.Constants - System.Configuration.ConfigurationManager - System.Security.Permissions - System.Console - System.ComponentModel - System.Memory - System.Private.Uri - System.Linq.Expressions - System.Runtime.Serialization.Formatters - System.Private.DataContractSerialization - System.Runtime.Serialization.Primitives - - - - - - True - - - - - - "Hello World" - - - - + + + + System.Activities + System.Activities.Statements + System.Activities.Expressions + System.Activities.Validation + System.Activities.XamlIntegration + Microsoft.VisualBasic + Microsoft.VisualBasic.Activities + System + System.Collections + System.Collections.Generic + System.Collections.ObjectModel + System.Data + System.Diagnostics + System.Drawing + System.IO + System.Linq + System.Net.Mail + System.Xml + System.Text + System.Xml.Linq + UiPath.Core + UiPath.Core.Activities + System.Windows.Markup + GlobalVariablesNamespace + GlobalConstantsNamespace + System.Linq.Expressions + System.Runtime.Serialization + + + + + Microsoft.CSharp + Microsoft.VisualBasic + mscorlib + System + System.Activities + System.ComponentModel.TypeConverter + System.Core + System.Data + System.Data.Common + System.Data.DataSetExtensions + System.Drawing + System.Drawing.Common + System.Drawing.Primitives + System.Linq + System.Net.Mail + System.ObjectModel + System.Private.CoreLib + System.Runtime.Serialization + System.ServiceModel + System.ServiceModel.Activities + System.Xaml + System.Xml + System.Xml.Linq + UiPath.System.Activities + UiPath.UiAutomation.Activities + UiPath.Studio.Constants + System.Configuration.ConfigurationManager + System.Security.Permissions + System.Console + System.ComponentModel + System.Memory + System.Private.Uri + System.Linq.Expressions + System.Runtime.Serialization.Formatters + System.Private.DataContractSerialization + System.Runtime.Serialization.Primitives + + + + + + True + + + + + + "Hello World" + + + + \ No newline at end of file diff --git a/plugin/studio/project/project.json b/plugin/studio/projects/crossplatform/project.json similarity index 96% rename from plugin/studio/project/project.json rename to plugin/studio/projects/crossplatform/project.json index 77426bd..e6c5ed0 100644 --- a/plugin/studio/project/project.json +++ b/plugin/studio/projects/crossplatform/project.json @@ -1,61 +1,61 @@ -{ - "name": "MyProcess", - "projectId": "9011ee47-8dd4-4726-8850-299bd6ef057c", - "description": "Blank Process", - "main": "Main.xaml", - "dependencies": { - "UiPath.System.Activities": "[24.10.3]", - "UiPath.Testing.Activities": "[24.10.0]", - "UiPath.UIAutomation.Activities": "[24.10.0]", - "UiPath.WebAPI.Activities": "[1.21.0]" - }, - "webServices": [], - "entitiesStores": [], - "schemaVersion": "4.0", - "studioVersion": "24.10.1.0", - "projectVersion": "1.0.2", - "runtimeOptions": { - "autoDispose": false, - "netFrameworkLazyLoading": false, - "isPausable": true, - "isAttended": false, - "requiresUserInteraction": false, - "supportsPersistence": false, - "workflowSerialization": "DataContract", - "excludedLoggedData": [ - "Private:*", - "*password*" - ], - "executionType": "Workflow", - "readyForPiP": false, - "startsInPiP": false, - "mustRestoreAllDependencies": true, - "pipType": "ChildSession" - }, - "designOptions": { - "projectProfile": "Developement", - "outputType": "Process", - "libraryOptions": { - "includeOriginalXaml": false, - "privateWorkflows": [] - }, - "processOptions": { - "ignoredFiles": [] - }, - "fileInfoCollection": [], - "saveToCloud": false - }, - "expressionLanguage": "CSharp", - "entryPoints": [ - { - "filePath": "Main.xaml", - "uniqueId": "ac610120-f85b-4ed4-a014-05dca3380186", - "input": [], - "output": [] - } - ], - "isTemplate": false, - "templateProjectData": {}, - "publishData": {}, - "targetFramework": "Portable" +{ + "name": "MyProcess", + "projectId": "9011ee47-8dd4-4726-8850-299bd6ef057c", + "description": "Blank Process", + "main": "Main.xaml", + "dependencies": { + "UiPath.System.Activities": "[24.10.3]", + "UiPath.Testing.Activities": "[24.10.0]", + "UiPath.UIAutomation.Activities": "[24.10.0]", + "UiPath.WebAPI.Activities": "[1.21.0]" + }, + "webServices": [], + "entitiesStores": [], + "schemaVersion": "4.0", + "studioVersion": "24.10.1.0", + "projectVersion": "1.0.2", + "runtimeOptions": { + "autoDispose": false, + "netFrameworkLazyLoading": false, + "isPausable": true, + "isAttended": false, + "requiresUserInteraction": false, + "supportsPersistence": false, + "workflowSerialization": "DataContract", + "excludedLoggedData": [ + "Private:*", + "*password*" + ], + "executionType": "Workflow", + "readyForPiP": false, + "startsInPiP": false, + "mustRestoreAllDependencies": true, + "pipType": "ChildSession" + }, + "designOptions": { + "projectProfile": "Developement", + "outputType": "Process", + "libraryOptions": { + "includeOriginalXaml": false, + "privateWorkflows": [] + }, + "processOptions": { + "ignoredFiles": [] + }, + "fileInfoCollection": [], + "saveToCloud": false + }, + "expressionLanguage": "CSharp", + "entryPoints": [ + { + "filePath": "Main.xaml", + "uniqueId": "ac610120-f85b-4ed4-a014-05dca3380186", + "input": [], + "output": [] + } + ], + "isTemplate": false, + "templateProjectData": {}, + "publishData": {}, + "targetFramework": "Portable" } \ No newline at end of file diff --git a/plugin/studio/projects/windows/Main.xaml b/plugin/studio/projects/windows/Main.xaml new file mode 100644 index 0000000..4c906dc --- /dev/null +++ b/plugin/studio/projects/windows/Main.xaml @@ -0,0 +1,94 @@ + + + + System.Activities + System.Activities.Statements + System.Activities.Expressions + System.Activities.Validation + System.Activities.XamlIntegration + Microsoft.VisualBasic + Microsoft.VisualBasic.Activities + System + System.Collections + System.Collections.Generic + System.Collections.ObjectModel + System.Data + System.Diagnostics + System.Drawing + System.IO + System.Linq + System.Net.Mail + System.Xml + System.Text + System.Xml.Linq + UiPath.Core + UiPath.Core.Activities + System.Windows.Markup + GlobalVariablesNamespace + GlobalConstantsNamespace + System.Linq.Expressions + System.Runtime.Serialization + + + + + Microsoft.CSharp + Microsoft.VisualBasic + mscorlib + PresentationCore + PresentationFramework + System + System.Activities + System.ComponentModel.TypeConverter + System.Core + System.Data + System.Data.Common + System.Data.DataSetExtensions + System.Drawing + System.Drawing.Common + System.Drawing.Primitives + System.Linq + System.Net.Mail + System.ObjectModel + System.Private.CoreLib + System.Runtime.Serialization + System.ServiceModel + System.ServiceModel.Activities + System.Xaml + System.Xml + System.Xml.Linq + UiPath.System.Activities + UiPath.UiAutomation.Activities + WindowsBase + UiPath.Studio.Constants + System.Memory.Data + UiPath.Excel.Activities.Design + NPOI + System.Console + System.Security.Permissions + System.Configuration.ConfigurationManager + System.ComponentModel + System.Memory + System.Private.Uri + System.Linq.Expressions + System.Private.ServiceModel + System.Runtime.Serialization.Formatters + System.Private.DataContractSerialization + System.Runtime.Serialization.Primitives + + + + + + True + + + + + + "Hello World" + + + + + \ No newline at end of file diff --git a/plugin/studio/projects/windows/project.json b/plugin/studio/projects/windows/project.json new file mode 100644 index 0000000..4798b88 --- /dev/null +++ b/plugin/studio/projects/windows/project.json @@ -0,0 +1,62 @@ +{ + "name": "MyWindowsProcess", + "projectId": "94c4c9c1-68c3-45d4-be14-d4427f17eddd", + "description": "Blank Process", + "main": "Main.xaml", + "dependencies": { + "UiPath.Excel.Activities": "[2.23.4]", + "UiPath.Mail.Activities": "[1.23.1]", + "UiPath.System.Activities": "[24.10.3]", + "UiPath.Testing.Activities": "[24.10.0]", + "UiPath.UIAutomation.Activities": "[24.10.0]" + }, + "webServices": [], + "entitiesStores": [], + "schemaVersion": "4.0", + "studioVersion": "24.10.1.0", + "projectVersion": "1.0.0", + "runtimeOptions": { + "autoDispose": false, + "netFrameworkLazyLoading": false, + "isPausable": true, + "isAttended": false, + "requiresUserInteraction": true, + "supportsPersistence": false, + "workflowSerialization": "DataContract", + "excludedLoggedData": [ + "Private:*", + "*password*" + ], + "executionType": "Workflow", + "readyForPiP": false, + "startsInPiP": false, + "mustRestoreAllDependencies": true, + "pipType": "ChildSession" + }, + "designOptions": { + "projectProfile": "Developement", + "outputType": "Process", + "libraryOptions": { + "includeOriginalXaml": false, + "privateWorkflows": [] + }, + "processOptions": { + "ignoredFiles": [] + }, + "fileInfoCollection": [], + "saveToCloud": false + }, + "expressionLanguage": "CSharp", + "entryPoints": [ + { + "filePath": "Main.xaml", + "uniqueId": "657507a4-4df3-47eb-810e-2548d3a59824", + "input": [], + "output": [] + } + ], + "isTemplate": false, + "templateProjectData": {}, + "publishData": {}, + "targetFramework": "Windows" +} \ No newline at end of file diff --git a/plugin/studio/studio_plugin_notwin_test.go b/plugin/studio/studio_plugin_notwin_test.go new file mode 100644 index 0000000..85b5a17 --- /dev/null +++ b/plugin/studio/studio_plugin_notwin_test.go @@ -0,0 +1,83 @@ +//go:build !windows + +package studio + +import ( + "path/filepath" + "strings" + "testing" + + "github.com/UiPath/uipathcli/test" + "github.com/UiPath/uipathcli/utils" +) + +func TestPackOnLinuxWithCorrectArguments(t *testing.T) { + commandName := "" + commandArgs := []string{} + exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { + commandName = name + commandArgs = args + }) + context := test.NewContextBuilder(). + WithDefinition("studio", studioDefinition). + WithCommandPlugin(PackagePackCommand{exec}). + Build() + + source := studioCrossPlatformProjectDirectory() + destination := createDirectory(t) + test.RunCli([]string{"studio", "package", "pack", "--source", source, "--destination", destination}, context) + + if !strings.HasSuffix(commandName, "dotnet") { + t.Errorf("Expected command name to be dotnet, but got: %v", commandName) + } + if !strings.HasSuffix(commandArgs[0], "uipcli.dll") { + t.Errorf("Expected 1st argument to be the uipcli.dll, but got: %v", commandArgs[0]) + } + if commandArgs[1] != "package" { + t.Errorf("Expected 2nd argument to be package, but got: %v", commandArgs[1]) + } + if commandArgs[2] != "pack" { + t.Errorf("Expected 3rd argument to be pack, but got: %v", commandArgs[2]) + } + if commandArgs[3] != filepath.Join(source, "project.json") { + t.Errorf("Expected 4th argument to be the project.json, but got: %v", commandArgs[3]) + } + if commandArgs[4] != "--output" { + t.Errorf("Expected 5th argument to be output, but got: %v", commandArgs[4]) + } + if commandArgs[5] != destination { + t.Errorf("Expected 6th argument to be the output path, but got: %v", commandArgs[5]) + } +} + +func TestAnalyzeOnLinuxWithCorrectArguments(t *testing.T) { + commandName := "" + commandArgs := []string{} + exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { + commandName = name + commandArgs = args + }) + context := test.NewContextBuilder(). + WithDefinition("studio", studioDefinition). + WithCommandPlugin(PackageAnalyzeCommand{exec}). + Build() + + source := studioCrossPlatformProjectDirectory() + test.RunCli([]string{"studio", "package", "analyze", "--source", source}, context) + + if !strings.HasSuffix(commandName, "dotnet") { + t.Errorf("Expected command name to be dotnet, but got: %v", commandName) + } + if !strings.HasSuffix(commandArgs[0], "uipcli.dll") { + t.Errorf("Expected 1st argument to be the uipcli.dll, but got: %v", commandArgs[0]) + } + if commandArgs[1] != "package" { + t.Errorf("Expected 2nd argument to be package, but got: %v", commandArgs[1]) + } + if commandArgs[2] != "analyze" { + t.Errorf("Expected 3rd argument to be analyze, but got: %v", commandArgs[2]) + } + if commandArgs[3] != filepath.Join(source, "project.json") { + t.Errorf("Expected 4th argument to be the project.json, but got: %v", commandArgs[3]) + } +} diff --git a/plugin/studio/studio_plugin_test.go b/plugin/studio/studio_plugin_test.go index 90ee9d7..712bf96 100644 --- a/plugin/studio/studio_plugin_test.go +++ b/plugin/studio/studio_plugin_test.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "runtime" + "slices" "strings" "testing" @@ -48,7 +49,7 @@ func TestPackWithoutDestinationParameterShowsValidationError(t *testing.T) { WithCommandPlugin(NewPackagePackCommand()). Build() - source := studioProjectDirectory() + source := studioCrossPlatformProjectDirectory() result := test.RunCli([]string{"studio", "package", "pack", "--source", source}, context) if !strings.Contains(result.StdErr, "Argument --destination is missing") { @@ -76,7 +77,7 @@ func TestFailedPackagingReturnsFailureStatus(t *testing.T) { WithCommandPlugin(PackagePackCommand{exec}). Build() - source := studioProjectDirectory() + source := studioCrossPlatformProjectDirectory() destination := createDirectory(t) result := test.RunCli([]string{"studio", "package", "pack", "--source", source, "--destination", destination}, context) @@ -93,13 +94,13 @@ func TestFailedPackagingReturnsFailureStatus(t *testing.T) { } } -func TestPackSuccessfully(t *testing.T) { +func TestPackCrossPlatformSuccessfully(t *testing.T) { context := test.NewContextBuilder(). WithDefinition("studio", studioDefinition). WithCommandPlugin(NewPackagePackCommand()). Build() - source := studioProjectDirectory() + source := studioCrossPlatformProjectDirectory() destination := createDirectory(t) result := test.RunCli([]string{"studio", "package", "pack", "--source", source, "--destination", destination}, context) @@ -136,10 +137,8 @@ func TestPackSuccessfully(t *testing.T) { } func TestPackWithAutoVersionArgument(t *testing.T) { - commandName := "" commandArgs := []string{} exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { - commandName = name commandArgs = args }) context := test.NewContextBuilder(). @@ -147,48 +146,18 @@ func TestPackWithAutoVersionArgument(t *testing.T) { WithCommandPlugin(PackagePackCommand{exec}). Build() - source := studioProjectDirectory() + source := studioCrossPlatformProjectDirectory() destination := createDirectory(t) test.RunCli([]string{"studio", "package", "pack", "--source", source, "--destination", destination, "--auto-version", "true"}, context) - expectedCommandName := "uipcli.exe" - if runtime.GOOS != "windows" { - expectedCommandName = "dotnet" - } - if !strings.HasSuffix(commandName, expectedCommandName) { - t.Errorf("Expected command name to be %s, but got: %v", expectedCommandName, commandName) - } - if runtime.GOOS != "windows" { - if !strings.HasSuffix(commandArgs[0], "uipcli.dll") { - t.Errorf("Expected first argument to be the uipcli.dll, but got: %v", commandArgs[0]) - } - commandArgs = commandArgs[1:] - } - if commandArgs[0] != "package" { - t.Errorf("Expected 1st argument to be the package, but got: %v", commandArgs[0]) - } - if commandArgs[1] != "pack" { - t.Errorf("Expected 2nd argument to be the analyze, but got: %v", commandArgs[1]) - } - if commandArgs[2] != filepath.Join(source, "project.json") { - t.Errorf("Expected 3rd argument to be the project.json, but got: %v", commandArgs[2]) - } - if commandArgs[3] != "--output" { - t.Errorf("Expected 4th argument to be the output, but got: %v", commandArgs[3]) - } - if commandArgs[4] != destination { - t.Errorf("Expected 5th argument to be the output path, but got: %v", commandArgs[4]) - } - if commandArgs[5] != "--autoVersion" { - t.Errorf("Expected 6th argument to be autoVersion, but got: %v", commandArgs[5]) + if !slices.Contains(commandArgs, "--autoVersion") { + t.Errorf("Expected argument --autoVersion, but got: %v", strings.Join(commandArgs, " ")) } } func TestPackWithOutputTypeArgument(t *testing.T) { - commandName := "" commandArgs := []string{} exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { - commandName = name commandArgs = args }) context := test.NewContextBuilder(). @@ -196,51 +165,18 @@ func TestPackWithOutputTypeArgument(t *testing.T) { WithCommandPlugin(PackagePackCommand{exec}). Build() - source := studioProjectDirectory() + source := studioCrossPlatformProjectDirectory() destination := createDirectory(t) test.RunCli([]string{"studio", "package", "pack", "--source", source, "--destination", destination, "--output-type", "Process"}, context) - expectedCommandName := "uipcli.exe" - if runtime.GOOS != "windows" { - expectedCommandName = "dotnet" - } - if !strings.HasSuffix(commandName, expectedCommandName) { - t.Errorf("Expected command name to be %s, but got: %v", expectedCommandName, commandName) - } - if runtime.GOOS != "windows" { - if !strings.HasSuffix(commandArgs[0], "uipcli.dll") { - t.Errorf("Expected first argument to be the uipcli.dll, but got: %v", commandArgs[0]) - } - commandArgs = commandArgs[1:] - } - if commandArgs[0] != "package" { - t.Errorf("Expected 1st argument to be the package, but got: %v", commandArgs[0]) - } - if commandArgs[1] != "pack" { - t.Errorf("Expected 2nd argument to be the analyze, but got: %v", commandArgs[1]) - } - if commandArgs[2] != filepath.Join(source, "project.json") { - t.Errorf("Expected 3rd argument to be the project.json, but got: %v", commandArgs[2]) - } - if commandArgs[3] != "--output" { - t.Errorf("Expected 4th argument to be the output, but got: %v", commandArgs[3]) - } - if commandArgs[4] != destination { - t.Errorf("Expected 5th argument to be the output path, but got: %v", commandArgs[4]) - } - if commandArgs[5] != "--outputType" { - t.Errorf("Expected 6th argument to be outputType, but got: %v", commandArgs[5]) - } - if commandArgs[6] != "Process" { - t.Errorf("Expected 7th argument to be outputType value, but got: %v", commandArgs[6]) + if !slices.Contains(commandArgs, "--outputType") { + t.Errorf("Expected argument --outputType, but got: %v", strings.Join(commandArgs, " ")) } } func TestPackWithSplitOutputArgument(t *testing.T) { - commandName := "" commandArgs := []string{} exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { - commandName = name commandArgs = args }) context := test.NewContextBuilder(). @@ -248,48 +184,18 @@ func TestPackWithSplitOutputArgument(t *testing.T) { WithCommandPlugin(PackagePackCommand{exec}). Build() - source := studioProjectDirectory() + source := studioCrossPlatformProjectDirectory() destination := createDirectory(t) test.RunCli([]string{"studio", "package", "pack", "--source", source, "--destination", destination, "--split-output", "true"}, context) - expectedCommandName := "uipcli.exe" - if runtime.GOOS != "windows" { - expectedCommandName = "dotnet" - } - if !strings.HasSuffix(commandName, expectedCommandName) { - t.Errorf("Expected command name to be %s, but got: %v", expectedCommandName, commandName) - } - if runtime.GOOS != "windows" { - if !strings.HasSuffix(commandArgs[0], "uipcli.dll") { - t.Errorf("Expected first argument to be the uipcli.dll, but got: %v", commandArgs[0]) - } - commandArgs = commandArgs[1:] - } - if commandArgs[0] != "package" { - t.Errorf("Expected 1st argument to be the package, but got: %v", commandArgs[0]) - } - if commandArgs[1] != "pack" { - t.Errorf("Expected 2nd argument to be the analyze, but got: %v", commandArgs[1]) - } - if commandArgs[2] != filepath.Join(source, "project.json") { - t.Errorf("Expected 3rd argument to be the project.json, but got: %v", commandArgs[2]) - } - if commandArgs[3] != "--output" { - t.Errorf("Expected 4th argument to be the output, but got: %v", commandArgs[3]) - } - if commandArgs[4] != destination { - t.Errorf("Expected 5th argument to be the output path, but got: %v", commandArgs[4]) - } - if commandArgs[5] != "--splitOutput" { - t.Errorf("Expected 6th argument to be splitOutput, but got: %v", commandArgs[5]) + if !slices.Contains(commandArgs, "--splitOutput") { + t.Errorf("Expected argument --splitOutput, but got: %v", strings.Join(commandArgs, " ")) } } func TestPackWithReleaseNotesArgument(t *testing.T) { - commandName := "" commandArgs := []string{} exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { - commandName = name commandArgs = args }) context := test.NewContextBuilder(). @@ -297,43 +203,16 @@ func TestPackWithReleaseNotesArgument(t *testing.T) { WithCommandPlugin(PackagePackCommand{exec}). Build() - source := studioProjectDirectory() + source := studioCrossPlatformProjectDirectory() destination := createDirectory(t) test.RunCli([]string{"studio", "package", "pack", "--source", source, "--destination", destination, "--release-notes", "These are release notes."}, context) - expectedCommandName := "uipcli.exe" - if runtime.GOOS != "windows" { - expectedCommandName = "dotnet" + index := slices.Index(commandArgs, "--releaseNotes") + if commandArgs[index] != "--releaseNotes" { + t.Errorf("Expected argument --releaseNotes, but got: %v", strings.Join(commandArgs, " ")) } - if !strings.HasSuffix(commandName, expectedCommandName) { - t.Errorf("Expected command name to be %s, but got: %v", expectedCommandName, commandName) - } - if runtime.GOOS != "windows" { - if !strings.HasSuffix(commandArgs[0], "uipcli.dll") { - t.Errorf("Expected first argument to be the uipcli.dll, but got: %v", commandArgs[0]) - } - commandArgs = commandArgs[1:] - } - if commandArgs[0] != "package" { - t.Errorf("Expected 1st argument to be the package, but got: %v", commandArgs[0]) - } - if commandArgs[1] != "pack" { - t.Errorf("Expected 2nd argument to be the analyze, but got: %v", commandArgs[1]) - } - if commandArgs[2] != filepath.Join(source, "project.json") { - t.Errorf("Expected 3rd argument to be the project.json, but got: %v", commandArgs[2]) - } - if commandArgs[3] != "--output" { - t.Errorf("Expected 4th argument to be the output, but got: %v", commandArgs[3]) - } - if commandArgs[4] != destination { - t.Errorf("Expected 5th argument to be the output path, but got: %v", commandArgs[4]) - } - if commandArgs[5] != "--releaseNotes" { - t.Errorf("Expected 6th argument to be outputType, but got: %v", commandArgs[5]) - } - if commandArgs[6] != "These are release notes." { - t.Errorf("Expected 7th argument to be outputType value, but got: %v", commandArgs[6]) + if commandArgs[index+1] != "These are release notes." { + t.Errorf("Expected release notes argument, but got: %v", strings.Join(commandArgs, " ")) } } @@ -350,13 +229,13 @@ func TestAnalyzeWithoutSourceParameterShowsValidationError(t *testing.T) { } } -func TestAnalyzeSuccessfully(t *testing.T) { +func TestAnalyzeCrossPlatformSuccessfully(t *testing.T) { context := test.NewContextBuilder(). WithDefinition("studio", studioDefinition). WithCommandPlugin(NewPackageAnalyzeCommand()). Build() - source := studioProjectDirectory() + source := studioCrossPlatformProjectDirectory() result := test.RunCli([]string{"studio", "package", "analyze", "--source", source}, context) stdout := map[string]interface{}{} @@ -411,7 +290,7 @@ func TestFailedAnalyzeReturnsFailureStatus(t *testing.T) { WithCommandPlugin(PackageAnalyzeCommand{exec}). Build() - source := studioProjectDirectory() + source := studioCrossPlatformProjectDirectory() result := test.RunCli([]string{"studio", "package", "analyze", "--source", source}, context) stdout := map[string]interface{}{} @@ -427,11 +306,9 @@ func TestFailedAnalyzeReturnsFailureStatus(t *testing.T) { } } -func TestAnalyzeWithTreatWarningsAsErrorsAndStopOnRuleViolation(t *testing.T) { - commandName := "" +func TestAnalyzeWithTreatWarningsAsErrorsArgument(t *testing.T) { commandArgs := []string{} exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { - commandName = name commandArgs = args }) context := test.NewContextBuilder(). @@ -439,39 +316,29 @@ func TestAnalyzeWithTreatWarningsAsErrorsAndStopOnRuleViolation(t *testing.T) { WithCommandPlugin(PackageAnalyzeCommand{exec}). Build() - source := studioProjectDirectory() - test.RunCli([]string{"studio", "package", "analyze", "--source", source, "--treat-warnings-as-errors", "true", "--stop-on-rule-violation", "true"}, context) + source := studioCrossPlatformProjectDirectory() + test.RunCli([]string{"studio", "package", "analyze", "--source", source, "--treat-warnings-as-errors", "true"}, context) - expectedCommandName := "uipcli.exe" - if runtime.GOOS != "windows" { - expectedCommandName = "dotnet" - } - if !strings.HasSuffix(commandName, expectedCommandName) { - t.Errorf("Expected command name to be %s, but got: %v", expectedCommandName, commandName) - } - if runtime.GOOS != "windows" { - if !strings.HasSuffix(commandArgs[0], "uipcli.dll") { - t.Errorf("Expected first argument to be the uipcli.dll, but got: %v", commandArgs[0]) - } - commandArgs = commandArgs[1:] - } - if commandArgs[0] != "package" { - t.Errorf("Expected 1st argument to be the package, but got: %v", commandArgs[0]) - } - if commandArgs[1] != "analyze" { - t.Errorf("Expected 2nd argument to be the analyze, but got: %v", commandArgs[1]) - } - if commandArgs[2] != filepath.Join(source, "project.json") { - t.Errorf("Expected 3rd argument to be the project.json, but got: %v", commandArgs[2]) + if !slices.Contains(commandArgs, "--treatWarningsAsErrors") { + t.Errorf("Expected argument --treatWarningsAsErrors, but got: %v", strings.Join(commandArgs, " ")) } - if commandArgs[3] != "--resultPath" { - t.Errorf("Expected 4th argument to be the result path, but got: %v", commandArgs[3]) - } - if commandArgs[5] != "--treatWarningsAsErrors" { - t.Errorf("Expected 6th argument to be treatWarningsAsErrors, but got: %v", commandArgs[5]) - } - if commandArgs[6] != "--stopOnRuleViolation" { - t.Errorf("Expected 7th argument to be stopOnRuleViolation, but got: %v", commandArgs[6]) +} + +func TestAnalyzeWithStopOnRuleViolationArgument(t *testing.T) { + commandArgs := []string{} + exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { + commandArgs = args + }) + context := test.NewContextBuilder(). + WithDefinition("studio", studioDefinition). + WithCommandPlugin(PackageAnalyzeCommand{exec}). + Build() + + source := studioCrossPlatformProjectDirectory() + test.RunCli([]string{"studio", "package", "analyze", "--source", source, "--stop-on-rule-violation", "true"}, context) + + if !slices.Contains(commandArgs, "--stopOnRuleViolation") { + t.Errorf("Expected argument --stopOnRuleViolation, but got: %v", strings.Join(commandArgs, " ")) } } @@ -486,9 +353,9 @@ func findViolation(violations []interface{}, errorCode string) map[string]interf return violation } -func studioProjectDirectory() string { +func studioCrossPlatformProjectDirectory() string { _, filename, _, _ := runtime.Caller(0) - return filepath.Join(filepath.Dir(filename), "project") + return filepath.Join(filepath.Dir(filename), "projects", "crossplatform") } func createDirectory(t *testing.T) string { diff --git a/plugin/studio/studio_plugin_windows_test.go b/plugin/studio/studio_plugin_windows_test.go new file mode 100644 index 0000000..f9dcdad --- /dev/null +++ b/plugin/studio/studio_plugin_windows_test.go @@ -0,0 +1,153 @@ +//go:build windows + +package studio + +import ( + "encoding/json" + "os" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/UiPath/uipathcli/test" + "github.com/UiPath/uipathcli/utils" +) + +func TestPackWindowsSuccessfully(t *testing.T) { + context := test.NewContextBuilder(). + WithDefinition("studio", studioDefinition). + WithCommandPlugin(NewPackagePackCommand()). + Build() + + source := studioWindowsProjectDirectory() + destination := createDirectory(t) + result := test.RunCli([]string{"studio", "package", "pack", "--source", source, "--destination", destination}, context) + + stdout := map[string]interface{}{} + err := json.Unmarshal([]byte(result.StdOut), &stdout) + if err != nil { + t.Errorf("Failed to deserialize pack command result: %v", err) + } + if stdout["status"] != "Succeeded" { + t.Errorf("Expected status to be Succeeded, but got: %v", result.StdOut) + } + if stdout["error"] != nil { + t.Errorf("Expected error to be nil, but got: %v", result.StdOut) + } + if stdout["name"] != "MyWindowsProcess" { + t.Errorf("Expected name to be set, but got: %v", result.StdOut) + } + if stdout["description"] != "Blank Process" { + t.Errorf("Expected version to be set, but got: %v", result.StdOut) + } + if stdout["projectId"] != "94c4c9c1-68c3-45d4-be14-d4427f17eddd" { + t.Errorf("Expected projectId to be set, but got: %v", result.StdOut) + } + if stdout["version"] != "1.0.0" { + t.Errorf("Expected version to be set, but got: %v", result.StdOut) + } + outputFile := stdout["output"].(string) + if outputFile != filepath.Join(destination, "MyWindowsProcess.1.0.0.nupkg") { + t.Errorf("Expected output path to be set, but got: %v", result.StdOut) + } + if _, err := os.Stat(outputFile); err != nil { + t.Errorf("Expected output file %s to exists, but could not find it: %v", outputFile, err) + } +} + +func TestPackOnWindowsWithCorrectArguments(t *testing.T) { + commandName := "" + commandArgs := []string{} + exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { + commandName = name + commandArgs = args + }) + context := test.NewContextBuilder(). + WithDefinition("studio", studioDefinition). + WithCommandPlugin(PackagePackCommand{exec}). + Build() + + source := studioCrossPlatformProjectDirectory() + destination := createDirectory(t) + test.RunCli([]string{"studio", "package", "pack", "--source", source, "--destination", destination}, context) + + if !strings.HasSuffix(commandName, "uipcli.exe") { + t.Errorf("Expected command name to be uipcli.exe, but got: %v", commandName) + } + if commandArgs[0] != "package" { + t.Errorf("Expected 1st argument to be package, but got: %v", commandArgs[0]) + } + if commandArgs[1] != "pack" { + t.Errorf("Expected 2nd argument to be pack, but got: %v", commandArgs[1]) + } + if commandArgs[2] != filepath.Join(source, "project.json") { + t.Errorf("Expected 3rd argument to be the project.json, but got: %v", commandArgs[2]) + } + if commandArgs[3] != "--output" { + t.Errorf("Expected 4th argument to be output, but got: %v", commandArgs[3]) + } + if commandArgs[4] != destination { + t.Errorf("Expected 5th argument to be the output path, but got: %v", commandArgs[4]) + } +} + +func TestAnalyzeWindowsSuccessfully(t *testing.T) { + context := test.NewContextBuilder(). + WithDefinition("studio", studioDefinition). + WithCommandPlugin(NewPackageAnalyzeCommand()). + Build() + + source := studioWindowsProjectDirectory() + result := test.RunCli([]string{"studio", "package", "analyze", "--source", source}, context) + + stdout := map[string]interface{}{} + err := json.Unmarshal([]byte(result.StdOut), &stdout) + if err != nil { + t.Errorf("Failed to deserialize analyze command result: %v", err) + } + if stdout["status"] != "Succeeded" { + t.Errorf("Expected status to be Succeeded, but got: %v", result.StdOut) + } + if stdout["error"] != nil { + t.Errorf("Expected error to be nil, but got: %v", result.StdOut) + } + violations := stdout["violations"].([]interface{}) + if len(violations) == 0 { + t.Errorf("Expected violations not to be empty, but got: %v", result.StdOut) + } +} + +func TestAnalyzeOnWindowsWithCorrectArguments(t *testing.T) { + commandName := "" + commandArgs := []string{} + exec := utils.NewExecCustomProcess(0, "", "", func(name string, args []string) { + commandName = name + commandArgs = args + }) + context := test.NewContextBuilder(). + WithDefinition("studio", studioDefinition). + WithCommandPlugin(PackageAnalyzeCommand{exec}). + Build() + + source := studioCrossPlatformProjectDirectory() + test.RunCli([]string{"studio", "package", "analyze", "--source", source}, context) + + if !strings.HasSuffix(commandName, "uipcli.exe") { + t.Errorf("Expected command name to be uipcli.exe, but got: %v", commandName) + } + if commandArgs[0] != "package" { + t.Errorf("Expected 2nd argument to be package, but got: %v", commandArgs[0]) + } + if commandArgs[1] != "analyze" { + t.Errorf("Expected 3rd argument to be analyze, but got: %v", commandArgs[1]) + } + if commandArgs[2] != filepath.Join(source, "project.json") { + t.Errorf("Expected 4th argument to be the project.json, but got: %v", commandArgs[2]) + } +} + +func studioWindowsProjectDirectory() string { + _, filename, _, _ := runtime.Caller(0) + return filepath.Join(filepath.Dir(filename), "projects", "windows") +} diff --git a/plugin/studio/studio_project_json.go b/plugin/studio/studio_project_json.go new file mode 100644 index 0000000..25b2db3 --- /dev/null +++ b/plugin/studio/studio_project_json.go @@ -0,0 +1,8 @@ +package studio + +type studioProjectJson struct { + Name string `json:"name"` + Description string `json:"description"` + ProjectId string `json:"projectId"` + TargetFramework string `json:"targetFramework"` +} diff --git a/plugin/studio/studio_project_reader.go b/plugin/studio/studio_project_reader.go new file mode 100644 index 0000000..e96be3b --- /dev/null +++ b/plugin/studio/studio_project_reader.go @@ -0,0 +1,44 @@ +package studio + +import ( + "encoding/json" + "fmt" + "io" + "os" + "strings" +) + +type studioProjectReader struct { + Path string +} + +func (p studioProjectReader) GetTargetFramework() TargetFramework { + project, _ := p.ReadMetadata() + if strings.EqualFold(project.TargetFramework, "windows") { + return TargetFrameworkWindows + } + return TargetFrameworkCrossPlatform +} + +func (p studioProjectReader) ReadMetadata() (studioProjectJson, error) { + file, err := os.Open(p.Path) + if err != nil { + return studioProjectJson{}, fmt.Errorf("Error reading %s file: %v", defaultProjectJson, err) + } + defer file.Close() + byteValue, err := io.ReadAll(file) + if err != nil { + return studioProjectJson{}, fmt.Errorf("Error reading %s file: %v", defaultProjectJson, err) + } + + var project studioProjectJson + err = json.Unmarshal(byteValue, &project) + if err != nil { + return studioProjectJson{}, fmt.Errorf("Error parsing %s file: %v", defaultProjectJson, err) + } + return project, nil +} + +func newStudioProjectReader(path string) *studioProjectReader { + return &studioProjectReader{path} +} diff --git a/plugin/studio/target_framework.go b/plugin/studio/target_framework.go new file mode 100644 index 0000000..969cc5d --- /dev/null +++ b/plugin/studio/target_framework.go @@ -0,0 +1,8 @@ +package studio + +type TargetFramework int + +const ( + TargetFrameworkCrossPlatform TargetFramework = iota + 1 + TargetFrameworkWindows +) diff --git a/plugin/studio/uipcli.go b/plugin/studio/uipcli.go index 72f8851..04ddde9 100644 --- a/plugin/studio/uipcli.go +++ b/plugin/studio/uipcli.go @@ -14,13 +14,23 @@ import ( const uipcliVersion = "24.12.9111.31003" const uipcliUrl = "https://uipath.pkgs.visualstudio.com/Public.Feeds/_apis/packaging/feeds/1c781268-d43d-45ab-9dfc-0151a1c740b7/nuget/packages/UiPath.CLI/versions/" + uipcliVersion + "/content" +const uipcliWindowsVersion = "24.12.9111.31003" +const uipcliWindowsUrl = "https://uipath.pkgs.visualstudio.com/Public.Feeds/_apis/packaging/feeds/1c781268-d43d-45ab-9dfc-0151a1c740b7/nuget/packages/UiPath.CLI.Windows/versions/" + uipcliWindowsVersion + "/content" + type uipcli struct { Exec utils.ExecProcess Logger log.Logger } -func (c uipcli) Execute(args ...string) (utils.ExecCmd, error) { - uipcliPath, err := c.getPath() +func (c uipcli) Execute(targetFramework TargetFramework, args ...string) (utils.ExecCmd, error) { + if targetFramework == TargetFrameworkWindows { + return c.execute("uipcli-win", uipcliWindowsUrl, args) + } + return c.execute("uipcli", uipcliUrl, args) +} + +func (c uipcli) execute(name string, url string, args []string) (utils.ExecCmd, error) { + uipcliPath, err := c.getPath(name, url) if err != nil { return nil, err } @@ -38,13 +48,13 @@ func (c uipcli) Execute(args ...string) (utils.ExecCmd, error) { return cmd, nil } -func (c uipcli) getPath() (string, error) { +func (c uipcli) getPath(name string, url string) (string, error) { externalPlugin := plugin.NewExternalPlugin(c.Logger) executable := "tools/uipcli.dll" if c.isWindows() { executable = "tools/uipcli.exe" } - return externalPlugin.GetTool("uipcli", uipcliUrl, executable) + return externalPlugin.GetTool(name, url, executable) } func (c uipcli) isWindows() bool {