diff --git a/Frends.Template/.template.config/template.json b/Frends.Template/.template.config/template.json index 90fd994..85c11b5 100644 --- a/Frends.Template/.template.config/template.json +++ b/Frends.Template/.template.config/template.json @@ -14,22 +14,29 @@ "sourceName": "Frends.Echo.Execute", "preferNameDirectory": true, "symbols": { - "taskName": { + "FullTaskName": { "type": "parameter", "datatype": "string", - "defaultValue": "Execute", - "replaces": "Execute" + "defaultValue": "Frends.Echo.Execute", + "replaces": "Frends.Echo.Execute", + "description": "Full name in format: Frends.ClassName.MethodName" }, "className": { - "type": "parameter", - "datatype": "string", - "defaultValue": "Echo", + "type": "derived", + "valueSource": "FullTaskName", + "valueTransform": "GetClassName", "replaces": "Echo" }, + "taskName": { + "type": "derived", + "valueSource": "FullTaskName", + "valueTransform": "GetMethodName", + "replaces": "Execute" + }, "workflows": { - "type": "parameter", - "datatype": "string", - "defaultValue": "Execute", + "type": "derived", + "valueSource": "FullTaskName", + "valueTransform": "GetMethodName", "FileRename": "Execute" }, "CurrentDate": { @@ -49,6 +56,18 @@ "replaces": "GeneratedYear" } }, + "forms": { + "GetClassName": { + "identifier": "replace", + "pattern": "^.*\\.([^.]+)\\.[^.]+$", + "replacement": "$1" + }, + "GetMethodName": { + "identifier": "replace", + "pattern": "^.*\\.([^.]+)$", + "replacement": "$1" + } + }, "SpecialCustomOperations": { "**/*.md": { "operations": [ @@ -151,4 +170,4 @@ "continueOnError": false } ] -} +} \ No newline at end of file diff --git a/Frends.Template/CHANGELOG.md b/Frends.Template/CHANGELOG.md index fe2b20e..9bf77ea 100644 --- a/Frends.Template/CHANGELOG.md +++ b/Frends.Template/CHANGELOG.md @@ -2,6 +2,6 @@ ## [1.0.0] - GeneratedDate -### Changed +### Added - Initial implementation diff --git a/Frends.Template/Frends.Echo.Execute.Tests/ErrorHandlerTest.cs b/Frends.Template/Frends.Echo.Execute.Tests/ErrorHandlerTest.cs new file mode 100644 index 0000000..5f78365 --- /dev/null +++ b/Frends.Template/Frends.Echo.Execute.Tests/ErrorHandlerTest.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading; +using Frends.Echo.Execute.Definitions; +using NUnit.Framework; + +namespace Frends.Echo.Execute.Tests; + +// TODO: Adjust the test to use a real invalid Input scenario (e.g., missing or malformed data) +[TestFixture] +public class ErrorHandlerTest +{ + private const string CustomErrorMessage = "CustomErrorMessage"; + + [Test] + public void Should_Throw_Error_When_ThrowErrorOnFailure_Is_True() + { + var ex = Assert.Throws(() => + Echo.Execute(DefaultInput(), DefaultConnection(), DefaultOptions(), CancellationToken.None)); + Assert.That(ex, Is.Not.Null); + } + + [Test] + public void Should_Return_Failed_Result_When_ThrowErrorOnFailure_Is_False() + { + var options = DefaultOptions(); + options.ThrowErrorOnFailure = false; + var result = Echo.Execute(DefaultInput(), DefaultConnection(), options, CancellationToken.None); + Assert.That(result.Success, Is.False); + } + + [Test] + public void Should_Use_Custom_ErrorMessageOnFailure() + { + var options = DefaultOptions(); + options.ErrorMessageOnFailure = CustomErrorMessage; + var ex = Assert.Throws(() => + Echo.Execute(DefaultInput(), DefaultConnection(), options, CancellationToken.None)); + Assert.That(ex, Is.Not.Null); + Assert.That(ex.Message, Contains.Substring(CustomErrorMessage)); + } + + private static Input DefaultInput() => new() + { + Repeat = -1, // Invalid value to cause an exception + }; + + private static Connection DefaultConnection() => new(); + + private static Options DefaultOptions() => new() + { + ThrowErrorOnFailure = true, + ErrorMessageOnFailure = string.Empty, + }; +} diff --git a/Frends.Template/Frends.Echo.Execute.Tests/GlobalSuppressions.cs b/Frends.Template/Frends.Echo.Execute.Tests/GlobalSuppressions.cs index b48c026..8a31c19 100644 --- a/Frends.Template/Frends.Echo.Execute.Tests/GlobalSuppressions.cs +++ b/Frends.Template/Frends.Echo.Execute.Tests/GlobalSuppressions.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; +[assembly: SuppressMessage("StyleCop.CSharp.SpecialRules", "SA0001::XmlCommentAnalysisDisabled", Justification = "Following Frends documentation guidelines")] [assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1000:KeywordsMustBeSpacedCorrectly", Justification = "Incorrect for .NET 8.0")] [assembly: SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1010:OpeningSquareBracketsMustBeSpacedCorrectly", Justification = "Incorrect for .NET 8.0")] [assembly: SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1101:PrefixLocalCallsWithThis", Justification = "Following Frends documentation guidelines")] @@ -7,4 +8,4 @@ [assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1206:DeclarationKeywordsMustFollowOrder", Justification = "Incorrect for .NET 8.0")] [assembly: SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:BracesMustNotBeOmitted", Justification = "Following Frends documentation guidelines")] [assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", Justification = "Following Frends documentation guidelines")] -[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:FileMustHaveHeader", Justification = "Following Frends documentation guidelines")] +[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:FileMustHaveHeader", Justification = "Following Frends documentation guidelines")] \ No newline at end of file diff --git a/Frends.Template/Frends.Echo.Execute/Definitions/Connection.cs b/Frends.Template/Frends.Echo.Execute/Definitions/Connection.cs index 469238b..3fa9219 100644 --- a/Frends.Template/Frends.Echo.Execute/Definitions/Connection.cs +++ b/Frends.Template/Frends.Echo.Execute/Definitions/Connection.cs @@ -16,5 +16,5 @@ public class Connection /// Host=127.0.0.1;Port=5432 [DisplayFormat(DataFormatString = "Text")] [DefaultValue("")] - public string ConnectionString { get; set; } + public string ConnectionString { get; set; } = string.Empty; } diff --git a/Frends.Template/Frends.Echo.Execute/Definitions/Error.cs b/Frends.Template/Frends.Echo.Execute/Definitions/Error.cs index fcb5f09..0c29775 100644 --- a/Frends.Template/Frends.Echo.Execute/Definitions/Error.cs +++ b/Frends.Template/Frends.Echo.Execute/Definitions/Error.cs @@ -1,3 +1,5 @@ +using System; + namespace Frends.Echo.Execute.Definitions; /// @@ -14,7 +16,7 @@ public class Error /// /// Additional information about the error. /// - /// object { Exception Exception } + /// object { Exception AdditionalInfo } // TODO: Add task specific additional information. Strong typing is recommended when reasonable. - public dynamic AdditionalInfo { get; set; } + public Exception AdditionalInfo { get; set; } } diff --git a/Frends.Template/Frends.Echo.Execute/Definitions/Options.cs b/Frends.Template/Frends.Echo.Execute/Definitions/Options.cs index 9a82adc..d912f10 100644 --- a/Frends.Template/Frends.Echo.Execute/Definitions/Options.cs +++ b/Frends.Template/Frends.Echo.Execute/Definitions/Options.cs @@ -21,7 +21,7 @@ public class Options /// /// false [DefaultValue(true)] - public bool ThrowErrorOnFailure { get; set; } + public bool ThrowErrorOnFailure { get; set; } = true; /// /// Overrides the error message on failure. @@ -29,5 +29,5 @@ public class Options /// Custom error message [DisplayFormat(DataFormatString = "Text")] [DefaultValue("")] - public string ErrorMessageOnFailure { get; set; } + public string ErrorMessageOnFailure { get; set; } = string.Empty; } diff --git a/Frends.Template/Frends.Echo.Execute/Definitions/Result.cs b/Frends.Template/Frends.Echo.Execute/Definitions/Result.cs index 11dd9d7..9aeca65 100644 --- a/Frends.Template/Frends.Echo.Execute/Definitions/Result.cs +++ b/Frends.Template/Frends.Echo.Execute/Definitions/Result.cs @@ -20,6 +20,6 @@ public class Result /// /// Error that occurred during task execution. /// - /// object { string Message, object { Exception Exception } AdditionalInfo } + /// object { string Message, Exception AdditionalInfo } public Error Error { get; set; } -} +} \ No newline at end of file diff --git a/Frends.Template/Frends.Echo.Execute/Frends.Echo.Execute.cs b/Frends.Template/Frends.Echo.Execute/Frends.Echo.Execute.cs index 3587ded..19b68ac 100644 --- a/Frends.Template/Frends.Echo.Execute/Frends.Echo.Execute.cs +++ b/Frends.Template/Frends.Echo.Execute/Frends.Echo.Execute.cs @@ -3,11 +3,12 @@ using System.Linq; using System.Threading; using Frends.Echo.Execute.Definitions; +using Frends.Echo.Execute.Helpers; namespace Frends.Echo.Execute; /// -/// Task class. +/// Task Class for Echo operations. /// public static class Echo { @@ -19,7 +20,7 @@ public static class Echo /// Connection parameters. /// Additional parameters. /// A cancellation token provided by Frends Platform. - /// object { bool Success, string Output, object Error { string Message, dynamic AdditionalInfo } } + /// object { bool Success, string Output, object Error { string Message, Exception AdditionalInfo } } // TODO: Remove Connection parameter if the task does not make connections public static Result Execute( [PropertyTab] Input input, @@ -36,6 +37,9 @@ public static Result Execute( // and checked during long-running operations, e.g., loops cancellationToken.ThrowIfCancellationRequested(); + if (input.Repeat < 0) + throw new Exception("Repeat count cannot be negative."); + var output = string.Join(options.Delimiter, Enumerable.Repeat(input.Content, input.Repeat)); return new Result @@ -45,33 +49,9 @@ public static Result Execute( Error = null, }; } - catch (Exception e) when (e is not OperationCanceledException) + catch (Exception ex) { - if (options.ThrowErrorOnFailure) - { - if (string.IsNullOrEmpty(options.ErrorMessageOnFailure)) - throw new Exception(e.Message, e); - - throw new Exception(options.ErrorMessageOnFailure, e); - } - - var errorMessage = !string.IsNullOrEmpty(options.ErrorMessageOnFailure) - ? $"{options.ErrorMessageOnFailure}: {e.Message}" - : e.Message; - - return new Result - { - Success = false, - Output = null, - Error = new Error - { - Message = errorMessage, - AdditionalInfo = new - { - Exception = e, - }, - }, - }; + return ErrorHandler.Handle(ex, options.ThrowErrorOnFailure, options.ErrorMessageOnFailure); } } } diff --git a/Frends.Template/Frends.Echo.Execute/Frends.Echo.Execute.csproj b/Frends.Template/Frends.Echo.Execute/Frends.Echo.Execute.csproj index b40e85f..03975b7 100644 --- a/Frends.Template/Frends.Echo.Execute/Frends.Echo.Execute.csproj +++ b/Frends.Template/Frends.Echo.Execute/Frends.Echo.Execute.csproj @@ -31,9 +31,21 @@ - + PreserveNewest - + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/Frends.Template/Frends.Echo.Execute/GlobalSuppressions.cs b/Frends.Template/Frends.Echo.Execute/GlobalSuppressions.cs index e180a1e..cf208b2 100644 --- a/Frends.Template/Frends.Echo.Execute/GlobalSuppressions.cs +++ b/Frends.Template/Frends.Echo.Execute/GlobalSuppressions.cs @@ -6,6 +6,7 @@ [assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1200:UsingDirectivesMustBePlacedWithinNamespace", Justification = "Following Frends documentation guidelines")] [assembly: SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1206:DeclarationKeywordsMustFollowOrder", Justification = "Incorrect for .NET 8.0")] [assembly: SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1503:BracesMustNotBeOmitted", Justification = "Following Frends documentation guidelines")] +[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Documentation checked by custom analyzers")] [assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1623:PropertySummaryDocumentationMustMatchAccessors", Justification = "Following Frends documentation guidelines")] [assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1629:DocumentationTextMustEndWithAPeriod", Justification = "Following Frends Tasks guidelines")] -[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:FileMustHaveHeader", Justification = "Following Frends documentation guidelines")] +[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1633:FileMustHaveHeader", Justification = "Following Frends documentation guidelines")] \ No newline at end of file diff --git a/Frends.Template/Frends.Echo.Execute/Helpers/ErrorHandler.cs b/Frends.Template/Frends.Echo.Execute/Helpers/ErrorHandler.cs new file mode 100644 index 0000000..d1487c9 --- /dev/null +++ b/Frends.Template/Frends.Echo.Execute/Helpers/ErrorHandler.cs @@ -0,0 +1,32 @@ +using System; +using Frends.Echo.Execute.Definitions; + +namespace Frends.Echo.Execute.Helpers; + +internal static class ErrorHandler +{ + internal static Result Handle(Exception exception, bool throwOnFailure, string errorMessageOnFailure) + { + if (throwOnFailure) + { + if (!string.IsNullOrEmpty(errorMessageOnFailure)) + { + throw new Exception(errorMessageOnFailure, exception); + } + + throw exception; + } + + var errorMessage = string.IsNullOrEmpty(errorMessageOnFailure) + ? exception.Message + : $"{errorMessageOnFailure}: {exception.Message}"; + + var error = new Error + { + Message = errorMessage, + AdditionalInfo = exception, + }; + + return new Result { Success = false, Error = error }; + } +} diff --git a/Frends.Template/Frends.Echo.Execute/migration.json b/Frends.Template/Frends.Echo.Execute/migration.json new file mode 100644 index 0000000..03483c5 --- /dev/null +++ b/Frends.Template/Frends.Echo.Execute/migration.json @@ -0,0 +1,12 @@ +[ + { + "Task": "Frends.Echo.Execute", + "Migrations": [ + { + "Version": "1.0.0", + "Description": "", + "Migration": [] + } + ] + } +] \ No newline at end of file diff --git a/Frends.Template/README.md b/Frends.Template/README.md index 232bcc3..cbdc2d0 100644 --- a/Frends.Template/README.md +++ b/Frends.Template/README.md @@ -8,7 +8,7 @@ Description of what the Task will do. ## Installing -You can install the Task via frends UI Task View. +You can install the Task via Frends UI Task View. ## Building @@ -30,7 +30,7 @@ Run the tests `dotnet pack --configuration Release` -### Third party licenses +### Third-party licenses StyleCop.Analyzer version (unmodified version 1.1.118) used to analyze code uses Apache-2.0 license, full text and source code can be found at https://github.com/DotNetAnalyzers/StyleCopAnalyzers diff --git a/Frends.Template/workflows/Execute_build_and_test_on_main.yml b/Frends.Template/workflows/Execute_build_and_test_on_main.yml index bea9ca2..a661c08 100644 --- a/Frends.Template/workflows/Execute_build_and_test_on_main.yml +++ b/Frends.Template/workflows/Execute_build_and_test_on_main.yml @@ -14,5 +14,6 @@ jobs: with: workdir: Frends.Echo.Execute dotnet_version: 8.0.x + strict_analyzers: true secrets: badge_service_api_key: ${{ secrets.BADGE_SERVICE_API_KEY }} diff --git a/Frends.Template/workflows/Execute_build_and_test_on_push.yml b/Frends.Template/workflows/Execute_build_and_test_on_push.yml index 8202eef..68ef71b 100644 --- a/Frends.Template/workflows/Execute_build_and_test_on_push.yml +++ b/Frends.Template/workflows/Execute_build_and_test_on_push.yml @@ -14,6 +14,7 @@ jobs: with: workdir: Frends.Echo.Execute dotnet_version: 8.0.x + strict_analyzers: true secrets: badge_service_api_key: ${{ secrets.BADGE_SERVICE_API_KEY }} test_feed_api_key: ${{ secrets.TASKS_TEST_FEED_API_KEY }} diff --git a/Frends.Template/workflows/Execute_release.yml b/Frends.Template/workflows/Execute_release.yml index 2cd66b8..70dd6b7 100644 --- a/Frends.Template/workflows/Execute_release.yml +++ b/Frends.Template/workflows/Execute_release.yml @@ -9,5 +9,6 @@ jobs: with: workdir: Frends.Echo.Execute dotnet_version: 8.0.x + strict_analyzers: true secrets: feed_api_key: ${{ secrets.TASKS_FEED_API_KEY }} diff --git a/FrendsTaskTemplate.csproj b/FrendsTaskTemplate.csproj index 5fadd69..685dbe5 100644 --- a/FrendsTaskTemplate.csproj +++ b/FrendsTaskTemplate.csproj @@ -2,14 +2,14 @@ Template - 1.3.0 + 1.4.0 frendstasktemplate Frends Task template Frends Template for creating Frends Tasks. https://github.com/FrendsPlatform/FrendsTaskTemplate dotnet-new;templates;frends - net6.0 + net8.0 true false diff --git a/README.md b/README.md index 1ef2b91..34c7f55 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ You need to clone the repository for the new Task. After cloning, move to that f You can create a new Task by running the following command in the Task's repository folder. -`dotnet new frendstasktemplate --name namespaceForTask --className classNameForTask --taskName TaskName --workflows TaskName --allow-scripts yes` +`dotnet new frendstasktemplate --FullTaskName Frends.ClassName.TaskName --allow-scripts yes` ## Get help using the template @@ -63,12 +63,9 @@ Options: --allow-scripts Specifies if post action scripts should run. [default: Prompt] Template options: - -ta, --taskName Type: string - Default: Execute - -c, --className Type: string - Default: Echo - -w, --workflows Type: string - Default: Execute + --FullTaskName Full name in format: Frends.ClassName.TaskName + Type: string + Default: Frends.Echo.Execute ``` ## Update the template