diff --git a/.github/workflows/main.yml b/.github/workflows/deploy.yml similarity index 90% rename from .github/workflows/main.yml rename to .github/workflows/deploy.yml index 12c36da..012124a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/deploy.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: push: tags: - - '*' + - "*" jobs: publish-automate-function-version: # make sure the action works on a clean machine without building @@ -11,11 +11,11 @@ jobs: FUNCTION_SCHEMA_FILE_NAME: functionSchema.json runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.6 + - uses: actions/checkout@v4 - name: Setup .NET Core SDK - uses: actions/setup-dotnet@v4.0.0 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 7.x + dotnet-version: 8.x.x - name: Restore dependencies run: dotnet restore - name: Extract functionInputSchema @@ -26,7 +26,7 @@ jobs: dotnet run generate-schema ${HOME}/functionSchema.json cat ${HOME}/functionSchema.json - name: Speckle Automate Function - Build and Publish - uses: specklesystems/speckle-automate-github-composite-action@0.8.1 + uses: specklesystems/speckle-automate-github-composite-action@0.9.0 with: speckle_function_command: "dotnet SpeckleAutomateDotnetExample.dll" speckle_automate_url: ${{ env.SPECKLE_AUTOMATE_URL || vars.SPECKLE_AUTOMATE_URL || 'https://automate.speckle.dev' }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000..0a129b7 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,19 @@ +name: "Test Building" +on: + pull_request: + +jobs: + build-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup .NET Core SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.x.x + - name: Restore dependencies + run: dotnet restore + - name: Build + working-directory: "SpeckleAutomateDotnetExample" + run: | + dotnet build -warnaserror diff --git a/Dockerfile b/Dockerfile index 70cc0c2..b1bf025 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0 as build-env +FROM mcr.microsoft.com/dotnet/sdk:8.0 as build-env WORKDIR /src COPY SpeckleAutomateDotnetExample/ . RUN dotnet restore --use-current-runtime RUN dotnet publish --use-current-runtime --self-contained false --no-restore -o /publish -FROM mcr.microsoft.com/dotnet/runtime:7.0 as runtime +FROM mcr.microsoft.com/dotnet/runtime:8.0 as runtime WORKDIR /publish COPY --from=build-env /publish . \ No newline at end of file diff --git a/README.md b/README.md index 1e87ee9..4bd95ed 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ This repository contains an example function that is compatible with Speckle Aut ## Getting started -This is essentially a template function, designed to serve as a starting point for creating your own function. The function targets dotnet 7.0 and uses the Speckle.Automate.SDK NuGet package, as well as the Objects Kit. +This is essentially a template function, designed to serve as a starting point for creating your own function. The function targets dotnet 8.0 and uses the Speckle.Automate.SDK NuGet package. At its core every Speckle Automate function is a CLI application with a specific, standardized set of available commands and arguments ([see below](#anatomy-of-a-function)). Each automate function is then built into a Docker image and published onto Speckle Automate. @@ -62,13 +62,14 @@ These arguments are automatically provided by the automate platform every time a ### Function Boilerplate (`Program.cs`) -In this file, you'll find a call to `AutomationRunner.Main`, which serves as your function's SDK entry point. This method handles argument parsing and accepts: +This Program.cs file is the entry point to your CLI app. +It contains boilerplate to setup the Automate SDK services, Resolve your function, and run it via the call to `IAutomationRunner.Main`. This method handles argument parsing and accepts: - `args` -> the arguments provided by Speckle Automate, and - `Func` -> Your custom function that gets executed when the automation is triggered. > [!NOTE] -> If your function requires no inputs, there is also `AutomationRunner.Main` (non-generic) which takes in a `Func` instead. +> If your function requires no inputs, there is also `IAutomationRunner.Main` (non-generic) which takes in a `Func` instead. This sets up a CLI application with two commands: diff --git a/SpeckleAutomateDotnetExample/AutomateFunction.cs b/SpeckleAutomateDotnetExample/AutomateFunction.cs index 4b583e2..8e90c10 100644 --- a/SpeckleAutomateDotnetExample/AutomateFunction.cs +++ b/SpeckleAutomateDotnetExample/AutomateFunction.cs @@ -1,16 +1,14 @@ -using Objects; using Speckle.Automate.Sdk; -using Speckle.Core.Models.Extensions; +using Speckle.Sdk.Models.Extensions; -public static class AutomateFunction +public class AutomateFunction { - public static async Task Run( - AutomationContext automationContext, + public async Task Run( + IAutomationContext automationContext, FunctionInputs functionInputs ) { Console.WriteLine("Starting execution"); - _ = typeof(ObjectsKit).Assembly; // INFO: Force objects kit to initialize Console.WriteLine("Receiving version"); var commitObject = await automationContext.ReceiveVersion(); @@ -23,8 +21,11 @@ public static class AutomateFunction Console.WriteLine($"Counted {count} objects"); - if (count < functionInputs.SpeckleTypeTargetCount) { - automationContext.MarkRunFailed($"Counted {count} objects where {functionInputs.SpeckleTypeTargetCount} were expected"); + if (count < functionInputs.SpeckleTypeTargetCount) + { + automationContext.MarkRunFailed( + $"Counted {count} objects where {functionInputs.SpeckleTypeTargetCount} were expected" + ); return; } diff --git a/SpeckleAutomateDotnetExample/FunctionInputs.cs b/SpeckleAutomateDotnetExample/FunctionInputs.cs index 29b7b88..5140427 100644 --- a/SpeckleAutomateDotnetExample/FunctionInputs.cs +++ b/SpeckleAutomateDotnetExample/FunctionInputs.cs @@ -1,19 +1,19 @@ -using Speckle.Automate.Sdk.DataAnnotations; using System.ComponentModel; using System.ComponentModel.DataAnnotations; +using Speckle.Automate.Sdk.DataAnnotations; /// /// This class describes the user specified variables that the function wants to work with. /// /// This class is used to generate a JSON Schema to ensure that the user provided values /// are valid and match the required schema. -public struct FunctionInputs +public readonly struct FunctionInputs { /// /// The object type to count instances of in the given model version. /// [Required] - public string SpeckleTypeToCount; + public string SpeckleTypeToCount { get; init; } /// /// The total number of the specified type expected. @@ -21,12 +21,12 @@ public struct FunctionInputs [DefaultValue(10)] [Range(1, 100)] [Required] - public int SpeckleTypeTargetCount; + public int SpeckleTypeTargetCount { get; init; } /// /// An arbitrary example of using a secret input value. /// [Required] [Secret] - public string ExternalServiceKey; + public string ExternalServiceKey { get; init; } } diff --git a/SpeckleAutomateDotnetExample/Program.cs b/SpeckleAutomateDotnetExample/Program.cs index 0bac59a..1f65ac5 100644 --- a/SpeckleAutomateDotnetExample/Program.cs +++ b/SpeckleAutomateDotnetExample/Program.cs @@ -1,6 +1,14 @@ -using Speckle.Automate.Sdk; +using Microsoft.Extensions.DependencyInjection; +using Speckle.Automate.Sdk; + +//Boilerplate to setup Automate SDK +var serviceCollection = new ServiceCollection(); +serviceCollection.AddAutomateSdk(); +serviceCollection.AddSingleton(); +await using var container = serviceCollection.BuildServiceProvider(); + +var runner = container.GetRequiredService(); +var function = container.GetRequiredService(); // WARNING do not delete this call, this is the actual execution of your function -return await AutomationRunner - .Main(args, AutomateFunction.Run) - .ConfigureAwait(false); +return await runner.Main(args, function.Run); diff --git a/SpeckleAutomateDotnetExample/SpeckleAutomateDotnetExample.csproj b/SpeckleAutomateDotnetExample/SpeckleAutomateDotnetExample.csproj index f1b4a10..df37db1 100644 --- a/SpeckleAutomateDotnetExample/SpeckleAutomateDotnetExample.csproj +++ b/SpeckleAutomateDotnetExample/SpeckleAutomateDotnetExample.csproj @@ -2,14 +2,15 @@ Exe - net7.0 + net8.0 enable enable + $(NoWarn);NETSDK1206 - - + + diff --git a/TestAutomateFunction/AutomationContextTest.cs b/TestAutomateFunction/AutomationContextTest.cs index 692a691..9eb9853 100644 --- a/TestAutomateFunction/AutomationContextTest.cs +++ b/TestAutomateFunction/AutomationContextTest.cs @@ -1,27 +1,35 @@ -namespace TestAutomateFunction; - +using Microsoft.Extensions.DependencyInjection; using Speckle.Automate.Sdk; using Speckle.Automate.Sdk.Test; -using Speckle.Core.Api; -using Speckle.Core.Api.GraphQL.Models; -using Speckle.Core.Credentials; +using Speckle.Sdk.Api; +using Speckle.Sdk.Api.GraphQL.Models; +using Speckle.Sdk.Credentials; + +namespace TestAutomateFunction; [TestFixture] public sealed class AutomationContextTest : IDisposable { - - private Client client; - private Account account; + private IClient _client; + private Account _account; + private IAutomationRunner _runner; + private AutomateFunction _function; [OneTimeSetUp] public void Setup() { - account = new Account + var serviceProvider = ServiceRegistration.GetServiceProvider(); + _account = new Account { token = TestAutomateEnvironment.GetSpeckleToken(), - serverInfo = new ServerInfo { url = TestAutomateEnvironment.GetSpeckleServerUrl().ToString() } + serverInfo = new ServerInfo + { + url = TestAutomateEnvironment.GetSpeckleServerUrl().ToString() + } }; - client = new Client(account); + _client = serviceProvider.GetRequiredService().Create(_account); + _runner = serviceProvider.GetRequiredService(); + _function = serviceProvider.GetRequiredService(); } [Test] @@ -33,11 +41,11 @@ public sealed class AutomationContextTest : IDisposable SpeckleTypeTargetCount = 1 }; - var automationRunData = await TestAutomateUtils.CreateTestRun(client); - var automationContext = await AutomationRunner.RunFunction( - AutomateFunction.Run, + var automationRunData = await TestAutomateUtils.CreateTestRun(_client); + var automationContext = await _runner.RunFunction( + _function.Run, automationRunData, - account.token, + _account.token, inputs ); @@ -46,7 +54,7 @@ public sealed class AutomationContextTest : IDisposable public void Dispose() { - client.Dispose(); + _client.Dispose(); TestAutomateEnvironment.Clear(); } } diff --git a/TestAutomateFunction/ServiceRegistration.cs b/TestAutomateFunction/ServiceRegistration.cs new file mode 100644 index 0000000..5ba583f --- /dev/null +++ b/TestAutomateFunction/ServiceRegistration.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; +using Speckle.Automate.Sdk; + +namespace TestAutomateFunction; + +public static class ServiceRegistration +{ + public static IServiceProvider GetServiceProvider() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddAutomateSdk(); + serviceCollection.AddSingleton(); + return serviceCollection.BuildServiceProvider(); + } +} diff --git a/TestAutomateFunction/TestAutomateFunction.csproj b/TestAutomateFunction/TestAutomateFunction.csproj index 10b7954..239a2b6 100644 --- a/TestAutomateFunction/TestAutomateFunction.csproj +++ b/TestAutomateFunction/TestAutomateFunction.csproj @@ -1,19 +1,24 @@ - net7.0 + net8.0 enable enable - false - - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/TestAutomateFunction/Usings.cs b/TestAutomateFunction/Usings.cs index cefced4..3244567 100644 --- a/TestAutomateFunction/Usings.cs +++ b/TestAutomateFunction/Usings.cs @@ -1 +1 @@ -global using NUnit.Framework; \ No newline at end of file +global using NUnit.Framework;