Skip to content
jefim edited this page Dec 3, 2024 · 39 revisions

Technical Project Setup

  • Target .NET 6.0 in both task project and testing project
  • Task project namespace should be Frends.SYSTEM.ACTION, task class name should be SYSTEM and task method name should be ACTION
    • Example: namespace = Frends.Salesforce.Query, class name = Salesforce (in namespace Frends.Salesforce.Query) and method name = Query.
  • NB! We have a task template for .NET cli, which you can install. Instructions here: https://github.com/FrendsPlatform/FrendsTaskTemplate

Repository Structure

GitHub Actions in .git/workflows, because this is the only place they can be in

Each task should have its own subfolder. The subfolder should contain task-specific solution, that in general contains the task project and test project.

  • .git/workflows
    • ACTION1_test.yml
    • ACTION1_main.yml
    • ACTION1_release.yml
    • ACTION2_test.yml
    • ACTION2_main.yml
    • ACTION2_release.yml
  • Frends.SYSTEM.ACTION1
    • README.md
    • CHANGELOG.md
    • Frends.SYSTEM.ACTION1.sln
    • Frends.SYSTEM.ACTION1
      • FrendsTaskMetadata.json
      • Frends.SYSTEM.ACTION1.csproj
    • Frends.SYSTEM.ACTION1.Tests
      • Frends.SYSTEM.ACTION1.Tests.csproj
  • Frends.SYSTEM.ACTION2
    • README.md
    • CHANGELOG.md
    • Frends.SYSTEM.ACTION2.sln
    • Frends.SYSTEM.ACTION2
      • FrendsTaskMetadata.json
      • Frends.SYSTEM.ACTION2.csproj
    • Frends.SYSTEM.ACTION2.Tests
      • Frends.SYSTEM.ACTION2.Tests.csproj

Repository Structure Basis

We want to have atomic tasks with as little external dependencies as possible. Shared code usage is not ok in general since using the same external code in many tasks means that shared code changes need to trigger task releases, and this will be definitely very hard to track and remember. Thus we opted for separate task solutions, so that it is clear that tasks are individual and separate entities.

References in to NuGets

If some NuGet package is used in several projects then its version should be the same to avoid problems with conflicting dependency versions.

Task Checklist

  • README.md, CHANGELOG.md files exist in task folder
  • FrendsTaskMetadata.json file exists in task project folder
  • Bagdes correct and have proper values
    • Main build
    • Nuget
    • License
    • Code coverage
  • README.md in repo root has link to task README.md
  • Task description has link to task readme in markdown format [Documentation](link)
  • Targets .NET 6.0
  • Task parameters and result do not include any 3rd party classes. E.g. you cannot use System.Security.Claims.ClaimsPrincipal in your result object. Instead you should create a new class which will contain all necessary information.
  • Make sure that project has the following properties set (for NuGet package)
  • Make sure that all dependencies use permissive licenses like MIT / Apache.
  • NB! GPL / AGPL are NOT permissive!
  • Build succeeds and WARNINGS ARE NOT ALLOWED to be present.
    • Sometimes there are cases when build generated irrelevant / unuseful warnings - in these cases you are allowed to mute those warnings with #pragma. However, you should always explain the #pragma in a comment - why it is here and why it is ok to mute the warnings. Pragma blocks without explanation are not allowed.
  • Documentation related
    • Make sure to have public task properties (task itself, its method parameters and result) documented
    • Make sure that XML docs will be generated (setting in csproj file)
    • Make sure that your comments always include a <summary> and an <example>! Also, do not forget about [DefaultValue]:s
    • For extended task documentation do not use <summary> (it will upset Frends UI), but use a custom tag - . This will be put directly under summary in our documentation website. You can (and probably should) use Markdown in both summary and frendsdocs.
    • For showing a data structure e.g. in task <result> documentation use the following format:
      • object { bool Success, string Error }
      • object { bool Success, object[] Messages { string MessageId, string MessageText } }
      • If the object is big - use newlines to make things readable.
	<PropertyGroup>
		<TargetFrameworks>net6.0</TargetFrameworks>
		<Version>____{{VERSION}}____</Version>
		<Authors>____{{AUTHOR(S)_NAME(S)}}____</Authors>
		<Copyright>Frends</Copyright>
		<Company>Frends</Company>
		<Product>Frends</Product>
		<PackageTags>Frends</PackageTags>
		<PackageLicenseExpression>MIT</PackageLicenseExpression>
		<GenerateDocumentationFile>true</GenerateDocumentationFile>
		<Description>____{{DESCRIPTION}}____.</Description>
		<PackageProjectUrl>https://frends.com/</PackageProjectUrl>
		<RepositoryUrl>____{{REPOSITORY_URL}}____</RepositoryUrl>
	</PropertyGroup>

Database Tasks

  • The resulting data table should always be created via .NET native DataTable class and then converted to JToken JToken.FromObject(myDataTable). This will make sure that data from DB tasks is always in the same shape and form.

Task resource cleanup

Cleanup should be done either in the task code itself, if possible. Or if it not possible here is a snippet. This could also be for cleaning up resources that need to live through process execution (e.g. DB connection pools).

   static ClassName()
        {
            var currentAssembly = Assembly.GetExecutingAssembly();
            var currentContext = AssemblyLoadContext.GetLoadContext(currentAssembly);

            if (currentContext != null)
            {
           
                currentContext.Unloading += OnPluginUnloadingRequested;
            }
        }
   private static void OnPluginUnloadingRequested(AssemblyLoadContext obj)
        {
            // Get rid off whatever you need to get rid off
            obj.Unloading -= OnPluginUnloadingRequested;
        }

Choosing a Target .NET Version

Here are the possible target framework combinations and results of empiric tests.

Always target .NET 6 in new tasks, unless we have specifically discussed a need for .NET Standard 2.0 compatibility.